int fork(void) { size_t rc; size_t stacksize; char modname[512];/*FIXBUF*/ HANDLE hProc,hThread, hArray[2]; STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD dwCreationflags; unsigned int priority; HANDLE h64Parent,h64Child; #ifndef _M_ALPHA unsigned long fork_stack_end; #endif _M_ALPHA __fork_stack_begin =GETSTACKBASE(); #ifndef _M_ALPHA __fork_stack_end = &fork_stack_end; #else __fork_stack_end = (unsigned long *)__asm("mov $sp, $0"); #endif /*_M_ALPHA*/ h64Parent = h64Child = NULL; // // Create two inheritable events // sa.nLength = sizeof(sa); sa.lpSecurityDescriptor =0; sa.bInheritHandle = TRUE; if (!__hforkchild) __hforkchild = CreateEvent(&sa,TRUE,FALSE,NULL); if (!__hforkparent) __hforkparent = CreateEvent(&sa,TRUE,FALSE,NULL); rc = setjmp(__fork_context); if (rc) { // child #ifdef _M_IX86 // // Restore old registration // -amol 2/2/97 GETEXCEPTIONREGIST() = (struct _EXCEPTION_REGISTRATION_RECORD*)_old_exr; #endif // _M_ALPHA SetEvent(__hforkchild); dprintf("Child ready to rumble\n"); if(WaitForSingleObject(__hforkparent,FORK_TIMEOUT) != WAIT_OBJECT_0) ExitProcess(0xFFFF); CloseHandle(__hforkchild); CloseHandle(__hforkparent); __hforkchild = __hforkparent=0; //__asm { int 3}; restore_fds(); STR_environ = blk2short(environ); environ = short2blk(STR_environ); /* So that we can free it */ return 0; } copy_fds(); memset(&si,0,sizeof(si)); si.cb= sizeof(si); /* * This f!@#!@% function returns the old value even if the std handles * have been closed. * Skip this step, since we know tcsh will do the right thing later. * si.hStdInput= GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle(STD_ERROR_HANDLE); */ if (!GetModuleFileName(GetModuleHandle(NULL),modname,512) ) { rc = GetLastError(); return -1; } dwCreationflags = GetPriorityClass(GetCurrentProcess()); priority = GetThreadPriority(GetCurrentThread()); rc = CreateProcess(NULL, modname, NULL, NULL, TRUE, CREATE_SUSPENDED | dwCreationflags, NULL, NULL, &si, &pi); if (!rc) { rc = GetLastError(); return -1; } ResetEvent(__hforkchild); ResetEvent(__hforkparent); hProc = pi.hProcess; hThread = pi.hThread; __forked=1; /* * Usage of events in the wow64 case: * * h64Parent : initially non-signalled * h64Child : initially non-signalled * * 1. Create the events, resume the child thread. * 2. Child opens h64Parent to see if it is a child process in wow64 * 3. Child opens and sets h64Child to tell parent it's running. (This * step is needed because we can't copy to a process created in the * suspended state on wow64.) * 4. Copy gForkData and then set h64Parent. This tells the child * that the parameters in the structure are trustworthy. * 5. Wait for h64Child so that we know the child has created the stack * in dynamic memory. * * The rest of the fork hack should now proceed as in x86 * */ if (bIsWow64Process) { // allocate the heap for the child. this can be done even when // the child is suspended. // avoids inexplicable allocation failures in the child. if (VirtualAllocEx(hProc, __heap_base, __heap_size, MEM_RESERVE, PAGE_READWRITE) == NULL) { dprintf("virtual allocex failed %d\n",GetLastError()); goto error; } if (VirtualAllocEx(hProc, __heap_base, __heap_size, MEM_COMMIT, PAGE_READWRITE) == NULL) { dprintf("virtual allocex2 failed %d\n",GetLastError()); goto error; } // Do NOT expect existing events if (!CreateWow64Events(pi.dwProcessId,&h64Parent,&h64Child,FALSE)) { goto error; } ResumeThread(hThread); // wait for the child to tell us it is running //if (WaitForSingleObject(h64Child,FORK_TIMEOUT) != WAIT_OBJECT_0) { // rc = GetLastError(); // goto error; //} hArray[0] = h64Child; hArray[1] = hProc; if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) != WAIT_OBJECT_0){ rc = GetLastError(); goto error; } } // // Copy all the shared data // if (!WriteProcessMemory(hProc,&gForkData,&gForkData, sizeof(ForkData),&rc)) { goto error; } if (rc != sizeof(ForkData)) goto error; if (!bIsWow64Process) { rc = ResumeThread(hThread); } // in the wow64 case, the child will be waiting on h64parent again. // set it, and then wait for h64child. This will mean the child has // a stack set up at the right location. else { SetEvent(h64Parent); hArray[0] = h64Child; hArray[1] = hProc; if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) != WAIT_OBJECT_0){ rc = GetLastError(); goto error; } CloseHandle(h64Parent); CloseHandle(h64Child); h64Parent = h64Child = NULL; } // // Wait for the child to start and init itself. // The timeout is so that we don't wait too long // hArray[0] = __hforkchild; hArray[1] = hProc; if (WaitForMultipleObjects(2,hArray,FALSE,FORK_TIMEOUT) != WAIT_OBJECT_0){ int err = GetLastError(); // For debugging purposes dprintf("wait failed err %d\n",err); goto error; } // Stop the child again and copy the stack and heap // SuspendThread(hThread); if (!SetThreadPriority(hThread,priority) ) { priority =GetLastError(); } // stack stacksize = (char*)__fork_stack_begin - (char*)__fork_stack_end; if (!WriteProcessMemory(hProc,(char *)__fork_stack_end, (char *)__fork_stack_end, (u_long)stacksize, &rc)){ goto error; } // // copy heap itself if (!WriteProcessMemory(hProc, (void*)__heap_base,(void*)__heap_base, (DWORD)((char*)__heap_top-(char*)__heap_base), &rc)){ goto error; } rc = fork_copy_user_mem(hProc); if(rc) { goto error; } // Release the child. SetEvent(__hforkparent); rc = ResumeThread(hThread); __forked=0; dprintf("forked process %d\n",pi.dwProcessId); start_sigchild_thread(hProc,pi.dwProcessId); close_copied_fds(); CloseHandle(hThread); // // return process id to parent. return pi.dwProcessId; error: __forked=0; SetEvent(__hforkparent); ResumeThread(hThread); CloseHandle(hProc); CloseHandle(hThread); if (h64Parent) { SetEvent(h64Parent); // don't let child block forever CloseHandle(h64Parent); } if (h64Child) CloseHandle(h64Child); return -1; }
void silly_entry(void *peb) { char * path1=NULL; int rc; char temp[MAX_PATH+5]; char buf[MAX_PATH]; char ptr1[MAX_PATH]; char ptr2[MAX_PATH]; char ptr3[MAX_PATH]; OSVERSIONINFO osver; init_wow64(); // look at the explanation in fork.c for why we do these steps. if (bIsWow64Process) { HANDLE h64Parent,h64Child; char *stk, *end; DWORD mb = (1<<20); // if we found the events, then we're the product of a fork() if (CreateWow64Events(GetCurrentProcessId(), &h64Parent,&h64Child,TRUE)) { if (!h64Parent || !h64Child) return; // tell parent we're rolling SetEvent(h64Child); if(WaitForSingleObject(h64Parent,FORK_TIMEOUT) != WAIT_OBJECT_0) { return; } // if __forked is 0, we shouldn't have found the events if (!__forked) return; } // now create the stack if (!__forked) { stk = VirtualAlloc(NULL,mb+65536,MEM_COMMIT,PAGE_READWRITE); if (!stk) { dprintf("virtual alloc in parent failed %d\n",GetLastError()); return; } end = stk + mb + 65536; end -= sizeof(char*); __fork_stack_begin = end; __asm {mov esp,end }; set_stackbase(end); heap_init(); } else { // child process stk = (char*)__fork_stack_begin + sizeof(char*)- mb - 65536; dprintf("begin is 0x%08x\n",stk); end = VirtualAlloc(stk, mb+65536 , MEM_RESERVE , PAGE_READWRITE); if (!end) { rc = GetLastError(); dprintf("virtual alloc 1 in child failed %d\n",rc); return; } stk = VirtualAlloc(end, mb+65536 , MEM_COMMIT , PAGE_READWRITE); if (!stk) { rc = GetLastError(); dprintf("virtual alloc 2 in child failed %d\n",rc); return; } end = stk + mb + 65536; __asm {mov esp, end}; set_stackbase(end); SetEvent(h64Child); CloseHandle(h64Parent); CloseHandle(h64Child); } } SetFileApisToOEM(); if (!bIsWow64Process) heap_init(); osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (!GetVersionEx(&osver)) { MessageBox(NULL,"GetVersionEx failed","tcsh",MB_ICONHAND); ExitProcess(0xFF); } gdwVersion = osver.dwMajorVersion; /* If home is set, we only need to change '\' to '/' */ rc = GetEnvironmentVariable("HOME",buf,MAX_PATH); if (rc && (rc < MAX_PATH)){ path_slashify(buf); (void)SetEnvironmentVariable("HOME",buf); goto skippy; } memset(ptr1,0,MAX_PATH); memset(ptr2,0,MAX_PATH); memset(ptr3,0,MAX_PATH); if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { GetEnvironmentVariable("USERPROFILE",ptr1,MAX_PATH); GetEnvironmentVariable("HOMEDRIVE",ptr2,MAX_PATH); GetEnvironmentVariable("HOMEPATH",ptr3,MAX_PATH); ptr1[MAX_PATH -1] = ptr2[MAX_PATH-1] = ptr3[MAX_PATH-1]= 0; if (!ptr1[0] || osver.dwMajorVersion <4) { wsprintf(temp,"%s%s",ptr2[0]?ptr2:"C:",ptr3[0]?ptr3:"\\"); } else if (osver.dwMajorVersion >= 4) { wsprintf(temp,"%s",ptr1); } } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { rc = GetWindowsDirectory(ptr1,MAX_PATH); if (rc > MAX_PATH) { MessageBox(NULL,"This should never happen","tcsh",MB_ICONHAND); ExitProcess(0xFF); } wsprintf(temp,"%s",ptr1); } else { MessageBox(NULL,"Unknown platform","tcsh",MB_ICONHAND); } path_slashify(temp); SetEnvironmentVariable("HOME",temp); skippy: gdwPlatform = osver.dwPlatformId; rc = GetEnvironmentVariable("Path",path1,0); if ( rc !=0) { path1 =heap_alloc(rc); GetEnvironmentVariable("Path",path1,rc); SetEnvironmentVariable("Path",NULL); /*SetEnvironmentVariable("PATH",NULL);*/ SetEnvironmentVariable("PATH",path1); heap_free(path1); } mainCRTStartup(peb); }