| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static intptr_t __fork_retry_stats = 0; |
| static intptr_t __fork_resume_stats = 0; |
| |
| static intptr_t __fastcall __ntapi_tt_fork_finalize(void ** hprocess) |
| { |
| int32_t status; |
| int page; |
| nt_rtdata * rtdata; |
| ntapi_internals * __internals; |
| |
| __internals = __ntapi_internals(); |
| rtdata = __internals->rtdata; |
| |
| if ((status = __ntapi->zw_duplicate_object( |
| __internals->hprocess, |
| __internals->hprocess, |
| __internals->hprocess, |
| hprocess,0,0, |
| NT_DUPLICATE_SAME_ATTRIBUTES |
| |NT_DUPLICATE_SAME_ACCESS))) |
| return status; |
| |
| if ((status = dalist_init_ex( |
| &__internals->ipc_conns, |
| sizeof(nt_ipc_conn), |
| NT_ALLOCATION_GRANULARITY, |
| __ntapi_ipc_page_alloc, |
| DALIST_MEMFN_CUSTOM))) |
| return status; |
| |
| dalist_deposit_memory_block( |
| &__internals->ipc_conns, |
| __internals->ntapi_img_sec_bss->ipc_buffer, |
| __NT_BSS_IPC_BUFFER_SIZE); |
| |
| for (page=0; __internals->ipc_page; page++) |
| dalist_deposit_memory_block( |
| &__internals->ipc_conns, |
| __internals->ipc_pages[page], |
| NT_ALLOCATION_GRANULARITY); |
| |
| rtdata->hsemctl = 0; |
| rtdata->hsempid = 0; |
| |
| rtdata->hmsqctl = 0; |
| rtdata->hmsqpid = 0; |
| |
| rtdata->haflctl = 0; |
| rtdata->haflpid = 0; |
| |
| rtdata->ipc_keys[0] = 0; |
| rtdata->ipc_keys[1] = 0; |
| rtdata->ipc_keys[2] = 0; |
| rtdata->ipc_keys[3] = 0; |
| rtdata->ipc_keys[4] = 0; |
| rtdata->ipc_keys[5] = 0; |
| |
| return 0; |
| } |
| |
| static int32_t __stdcall __fork_thread(void * ctx) |
| { |
| intptr_t * pstate; |
| intptr_t state; |
| void * hready; |
| |
| pstate = (intptr_t *)ctx; |
| state = *pstate; |
| hready = (void *)state; |
| |
| at_store( |
| pstate, |
| 0); |
| |
| return __ntapi->zw_terminate_thread( |
| NT_CURRENT_THREAD_HANDLE, |
| __ntapi->zw_set_event( |
| hready,0)); |
| } |
| |
| static intptr_t __fastcall __ntapi_tt_fork_child( |
| void * hresumed, |
| void * hready, |
| void ** hthread) |
| { |
| int32_t status; |
| nt_thread_params tparams; |
| nt_timeout timeout; |
| nt_timeout zerowait; |
| intptr_t state; |
| nt_oa oa; |
| nt_cid cid; |
| ntapi_internals * __internals; |
| |
| oa.len = sizeof(oa); |
| oa.root_dir = 0; |
| oa.obj_name = 0; |
| oa.obj_attr = 0; |
| oa.sec_desc = &__internals->seq_desc; |
| oa.sec_qos = &__internals->seq_qos; |
| |
| cid.process_id = pe_get_current_process_id(); |
| cid.thread_id = pe_get_current_thread_id(); |
| |
| __internals = __ntapi_internals(); |
| |
| status = __ntapi->zw_open_process( |
| &__internals->hprocess, |
| NT_PROCESS_ALL_ACCESS, |
| &oa,&cid); |
| |
| if (status == NT_STATUS_SUCCESS) |
| status = __ntapi->zw_open_thread( |
| hthread, |
| NT_THREAD_ALL_ACCESS, |
| &oa,&cid); |
| |
| if (status) { |
| __ntapi->zw_set_event( |
| hresumed,0); |
| |
| __ntapi->zw_terminate_process( |
| NT_CURRENT_PROCESS_HANDLE, |
| status); |
| } |
| |
| at_store( |
| &state, |
| (intptr_t)hready); |
| |
| __ntapi->tt_aligned_block_memset( |
| &tparams,0,sizeof(tparams)); |
| |
| tparams.start = __fork_thread; |
| tparams.arg = &state; |
| tparams.stack_size_commit = 0x10000; |
| tparams.stack_size_reserve = 0x20000; |
| |
| status = __ntapi->tt_create_local_thread( |
| &tparams); |
| |
| __ntapi->zw_set_event( |
| hresumed,0); |
| |
| if (status) |
| __ntapi->zw_terminate_process( |
| NT_CURRENT_PROCESS_HANDLE, |
| status); |
| |
| if (!state) { |
| __ntapi->zw_close(hresumed); |
| __ntapi->zw_close(hready); |
| __ntapi->zw_close(tparams.hthread); |
| return 0; |
| } |
| |
| timeout.quad = (-1) * 10 * 1000 * 250; |
| |
| status = __ntapi->zw_wait_for_single_object( |
| hready, |
| NT_SYNC_NON_ALERTABLE, |
| &timeout); |
| |
| if (status == NT_STATUS_SUCCESS) { |
| __ntapi->zw_close(hresumed); |
| __ntapi->zw_close(hready); |
| __ntapi->zw_close(tparams.hthread); |
| return 0; |
| } |
| |
| __ntapi->zw_terminate_thread( |
| tparams.hthread, |
| NT_STATUS_MORE_PROCESSING_REQUIRED); |
| |
| zerowait.quad = 0; |
| |
| status = __ntapi->zw_wait_for_single_object( |
| hready, |
| NT_SYNC_NON_ALERTABLE, |
| &zerowait); |
| |
| if (status == NT_STATUS_SUCCESS) { |
| __ntapi->zw_close(hresumed); |
| __ntapi->zw_close(hready); |
| __ntapi->zw_close(tparams.hthread); |
| return 0; |
| } |
| |
| return __ntapi->zw_terminate_process( |
| NT_CURRENT_PROCESS_HANDLE, |
| status); |
| } |
| |
| static intptr_t __fastcall __ntapi_tt_fork_parent( |
| void ** hprocess, |
| void ** hthread, |
| void * hresumed, |
| void * hready) |
| { |
| int32_t status; |
| nt_timeout timeout; |
| nt_timeout zerowait; |
| uint32_t prev; |
| |
| __ntapi->zw_wait_for_single_object( |
| hresumed, |
| NT_SYNC_NON_ALERTABLE, |
| 0); |
| |
| timeout.quad = (-1) * 10 * 1000 * 500; |
| |
| status = __ntapi->zw_wait_for_single_object( |
| hready, |
| NT_SYNC_NON_ALERTABLE, |
| &timeout); |
| |
| if (status == NT_STATUS_SUCCESS) { |
| __ntapi->zw_close(hresumed); |
| __ntapi->zw_close(hready); |
| return NT_STATUS_SUCCESS; |
| } |
| |
| __ntapi->zw_suspend_thread( |
| *hthread,&prev); |
| |
| zerowait.quad = 0; |
| |
| status = __ntapi->zw_wait_for_single_object( |
| hready, |
| NT_SYNC_NON_ALERTABLE, |
| &zerowait); |
| |
| if (status == NT_STATUS_SUCCESS) { |
| at_locked_inc( |
| &__fork_resume_stats); |
| |
| __ntapi->zw_resume_thread( |
| *hthread,0); |
| |
| __ntapi->zw_close(hresumed); |
| __ntapi->zw_close(hready); |
| return NT_STATUS_SUCCESS; |
| } |
| |
| at_locked_inc( |
| &__fork_retry_stats); |
| |
| __ntapi->zw_terminate_process( |
| *hprocess, |
| status); |
| |
| __ntapi->zw_close(*hprocess); |
| __ntapi->zw_close(*hthread); |
| |
| return status; |
| } |
| |
| intptr_t __fastcall __ntapi_tt_fork( |
| __out void ** hprocess, |
| __out void ** hthread) |
| { |
| int32_t status; |
| intptr_t pid; |
| void * hresumed; |
| void * hready; |
| int i; |
| |
| if ((status = __ntapi->tt_create_inheritable_event( |
| &hresumed, |
| NT_NOTIFICATION_EVENT, |
| NT_EVENT_NOT_SIGNALED))) |
| return -1; |
| |
| if ((status = __ntapi->tt_create_inheritable_event( |
| &hready, |
| NT_NOTIFICATION_EVENT, |
| NT_EVENT_NOT_SIGNALED))) |
| return -1; |
| |
| for (i=0; i<32; i++) { |
| if (__ntapi->zw_create_user_process) |
| pid = __ntapi_tt_fork_v2(hprocess,hthread); |
| else |
| pid = __ntapi_tt_fork_v1(hprocess,hthread); |
| |
| if (pid == 0) { |
| __ntapi_tt_fork_child( |
| hresumed,hready,hthread); |
| |
| return __ntapi_tt_fork_finalize( |
| hprocess); |
| |
| } else if (pid > 0) { |
| if (!(__ntapi_tt_fork_parent( |
| hprocess,hthread, |
| hresumed,hready))) |
| return pid; |
| |
| } else { |
| __ntapi->zw_close(hresumed); |
| __ntapi->zw_close(hready); |
| return -1; |
| } |
| } |
| |
| __ntapi->zw_close(hresumed); |
| __ntapi->zw_close(hready); |
| |
| return -1; |
| } |