VOID SepServerSpawnClientProcess(VOID) { RTL_USER_PROCESS_INFORMATION ProcessInformation; STRING ImagePathName, ProgramName; UNICODE_STRING UnicodeImagePathName, UnicodeProgramName; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; RtlInitString( &ProgramName, "\\SystemRoot\\Bin\\utlpcqos.exe" ); Status = RtlAnsiStringToUnicodeString( &UnicodeProgramName, &ProgramName, TRUE ); SEASSERT_SUCCESS( NT_SUCCESS(Status) ); RtlInitString( &ImagePathName, "utlpcqos.exe"); Status = RtlAnsiStringToUnicodeString( &UnicodeImagePathName, &ImagePathName, TRUE ); SEASSERT_SUCCESS( NT_SUCCESS(Status) ); Status = RtlCreateProcessParameters( &ProcessParameters, &ImagePathName, //UNICODEFIX &UnicodeImagePathName, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); SEASSERT_SUCCESS(Status); Status = RtlCreateUserProcess( &ProgramName, // UNICODEFIX &UnicodeProgramName, ProcessParameters, // ProcessParameters NULL, // ProcessSecurityDescriptor NULL, // ThreadSecurityDescriptor NtCurrentProcess(), // ParentProcess FALSE, // InheritHandles NULL, // DebugPort NULL, // ExceptionPort &ProcessInformation // ProcessInformation ); SEASSERT_SUCCESS(Status); Status = NtResumeThread( ProcessInformation.Thread, NULL ); SEASSERT_SUCCESS(Status); RtlDestroyProcessParameters( ProcessParameters ); RtlFreeUnicodeString( &UnicodeProgramName ); RtlFreeUnicodeString( &UnicodeImagePathName ); }
NTSTATUS NTAPI SmpExecuteImage(IN PUNICODE_STRING FileName, IN PUNICODE_STRING Directory, IN PUNICODE_STRING CommandLine, IN ULONG MuSessionId, IN ULONG Flags, IN PRTL_USER_PROCESS_INFORMATION ProcessInformation) { PRTL_USER_PROCESS_INFORMATION ProcessInfo; NTSTATUS Status; RTL_USER_PROCESS_INFORMATION LocalProcessInfo; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; /* Use the input process information if we have it, otherwise use local */ ProcessInfo = ProcessInformation; if (!ProcessInfo) ProcessInfo = &LocalProcessInfo; /* Create parameters for the target process */ Status = RtlCreateProcessParameters(&ProcessParameters, FileName, SmpDefaultLibPath.Length ? &SmpDefaultLibPath : NULL, Directory, CommandLine, SmpDefaultEnvironment, NULL, NULL, NULL, 0); if (!NT_SUCCESS(Status)) { /* This is a pretty bad failure. ASSERT on checked builds and exit */ ASSERTMSG("RtlCreateProcessParameters", NT_SUCCESS(Status)); DPRINT1("SMSS: RtlCreateProcessParameters failed for %wZ - Status == %lx\n", FileName, Status); return Status; } /* Set the size field as required */ ProcessInfo->Size = sizeof(RTL_USER_PROCESS_INFORMATION); /* Check if the debug flag was requested */ if (Flags & SMP_DEBUG_FLAG) { /* Write it in the process parameters */ ProcessParameters->DebugFlags = 1; } else { /* Otherwise inherit the flag that was passed to SMSS itself */ ProcessParameters->DebugFlags = SmpDebug; } /* Subsystems get the first 1MB of memory reserved for DOS/IVT purposes */ if (Flags & SMP_SUBSYSTEM_FLAG) { ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB; } /* And always force NX for anything that SMSS launches */ ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_NX; /* Now create the process */ Status = RtlCreateUserProcess(FileName, OBJ_CASE_INSENSITIVE, ProcessParameters, NULL, NULL, NULL, FALSE, NULL, NULL, ProcessInfo); RtlDestroyProcessParameters(ProcessParameters); if (!NT_SUCCESS(Status)) { /* If we couldn't create it, fail back to the caller */ DPRINT1("SMSS: Failed load of %wZ - Status == %lx\n", FileName, Status); return Status; } /* Associate a session with this process */ Status = SmpSetProcessMuSessionId(ProcessInfo->ProcessHandle, MuSessionId); /* If the application is deferred (suspended), there's nothing to do */ if (Flags & SMP_DEFERRED_FLAG) return Status; /* Otherwise, get ready to start it, but make sure it's a native app */ if (ProcessInfo->ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE) { /* Resume it */ NtResumeThread(ProcessInfo->ThreadHandle, NULL); if (!(Flags & SMP_ASYNC_FLAG)) { /* Block on it unless Async was requested */ NtWaitForSingleObject(ProcessInfo->ThreadHandle, FALSE, NULL); } /* It's up and running now, close our handles */ NtClose(ProcessInfo->ThreadHandle); NtClose(ProcessInfo->ProcessHandle); } else { /* This image is invalid, so kill it, close our handles, and fail */ Status = STATUS_INVALID_IMAGE_FORMAT; NtTerminateProcess(ProcessInfo->ProcessHandle, Status); NtWaitForSingleObject(ProcessInfo->ThreadHandle, 0, 0); NtClose(ProcessInfo->ThreadHandle); NtClose(ProcessInfo->ProcessHandle); DPRINT1("SMSS: Not an NT image - %wZ\n", FileName); } /* Return the outcome of the process create */ return Status; }
/********************************************************************** * SmCreateUserProcess/5 * * DESCRIPTION * * ARGUMENTS * ImagePath: absolute path of the image to run; * CommandLine: arguments and options for ImagePath; * Flags: Wait flag: Set for boot time processes and unset for * subsystems bootstrapping; * 1Mb reserve flag: Set for subsystems, unset for everything * else * Timeout: optional: used if WaitForIt==TRUE; * ProcessHandle: optional: a duplicated handle for the child process (storage provided by the caller). * * RETURN VALUE * NTSTATUS: * */ NTSTATUS NTAPI SmCreateUserProcess (LPWSTR ImagePath, LPWSTR CommandLine, ULONG Flags, PLARGE_INTEGER Timeout OPTIONAL, PRTL_USER_PROCESS_INFORMATION UserProcessInfo OPTIONAL) { UNICODE_STRING ImagePathString = { 0, 0, NULL }; UNICODE_STRING CommandLineString = { 0, 0, NULL }; UNICODE_STRING SystemDirectory = { 0, 0, NULL }; PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL; RTL_USER_PROCESS_INFORMATION ProcessInfo = {0}; PRTL_USER_PROCESS_INFORMATION pProcessInfo = & ProcessInfo; NTSTATUS Status = STATUS_SUCCESS; DPRINT("SM: %s called\n", __FUNCTION__); if (NULL != UserProcessInfo) { pProcessInfo = UserProcessInfo; } RtlInitUnicodeString (& ImagePathString, ImagePath); RtlInitUnicodeString (& CommandLineString, CommandLine); SystemDirectory.MaximumLength = (wcslen(SharedUserData->NtSystemRoot) * sizeof(WCHAR)) + sizeof(szSystemDirectory); SystemDirectory.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, SystemDirectory.MaximumLength); if (SystemDirectory.Buffer == NULL) { Status = STATUS_NO_MEMORY; DPRINT1("SM: %s: Allocating system directory string failed (Status=0x%08lx)\n", __FUNCTION__, Status); return Status; } Status = RtlAppendUnicodeToString(& SystemDirectory, SharedUserData->NtSystemRoot); if (!NT_SUCCESS(Status)) { goto FailProcParams; } Status = RtlAppendUnicodeToString(& SystemDirectory, szSystemDirectory); if (!NT_SUCCESS(Status)) { goto FailProcParams; } Status = RtlCreateProcessParameters(& ProcessParameters, & ImagePathString, NULL, & SystemDirectory, & CommandLineString, SmSystemEnvironment, NULL, NULL, NULL, NULL); RtlFreeHeap(RtlGetProcessHeap(), 0, SystemDirectory.Buffer); if (!NT_SUCCESS(Status)) { FailProcParams: DPRINT1("SM: %s: Creating process parameters failed (Status=0x%08lx)\n", __FUNCTION__, Status); return Status; } /* Reserve lower 1Mb, if requested */ if (Flags & SM_CREATE_FLAG_RESERVE_1MB) ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB; /* Create the user process */ Status = RtlCreateUserProcess (& ImagePathString, OBJ_CASE_INSENSITIVE, ProcessParameters, NULL, NULL, NULL, FALSE, NULL, NULL, pProcessInfo); RtlDestroyProcessParameters (ProcessParameters); if (!NT_SUCCESS(Status)) { DPRINT1("SM: %s: Running \"%S\" failed (Status=0x%08lx)\n", __FUNCTION__, ImagePathString.Buffer, Status); return Status; } /* * It the caller is *not* interested in the child info, * resume it immediately. */ if (NULL == UserProcessInfo) { Status = NtResumeThread (ProcessInfo.ThreadHandle, NULL); if(!NT_SUCCESS(Status)) { DPRINT1("SM: %s: NtResumeThread failed (Status=0x%08lx)\n", __FUNCTION__, Status); } } /* Wait for process termination */ if (Flags & SM_CREATE_FLAG_WAIT) { Status = NtWaitForSingleObject (pProcessInfo->ProcessHandle, FALSE, Timeout); if (!NT_SUCCESS(Status)) { DPRINT1("SM: %s: NtWaitForSingleObject failed with Status=0x%08lx\n", __FUNCTION__, Status); } } if (NULL == UserProcessInfo) { NtClose(pProcessInfo->ProcessHandle); NtClose(pProcessInfo->ThreadHandle); } return Status; }
NTSTATUS RtlCreateProcessParameters( OUT PRTL_USER_PROCESS_PARAMETERS *pProcessParameters, IN PUNICODE_STRING ImagePathName, IN PUNICODE_STRING DllPath OPTIONAL, IN PUNICODE_STRING CurrentDirectory OPTIONAL, IN PUNICODE_STRING CommandLine OPTIONAL, IN PVOID Environment OPTIONAL, IN PUNICODE_STRING WindowTitle OPTIONAL, IN PUNICODE_STRING DesktopInfo OPTIONAL, IN PUNICODE_STRING ShellInfo OPTIONAL, IN PUNICODE_STRING RuntimeData OPTIONAL ) /*++ Routine Description: This function formats NT style RTL_USER_PROCESS_PARAMETERS record. The record is self-contained in a single block of memory allocated by this function. The allocation method is opaque and thus the record must be freed by calling the RtlDestroyProcessParameters function. The process parameters record is created in a de-normalized form, thus making it suitable for passing to the RtlCreateUserProcess function. It is expected that the caller will fill in additional fields in the process parameters record after this function returns, but prior to calling RtlCreateUserProcess. Arguments: pProcessParameters - Pointer to a variable that will receive the address of the process parameter structure created by this routine. The memory for the structure is allocated in an opaque manner and must be freed by calling RtlDestroyProcessParameters. ImagePathName - Required parameter that is the fully qualified NT path name of the image file that will be used to create the process that will received these parameters. DllPath - An optional parameter that is an NT String variable pointing to the search path the NT Loader is to use in the target process when searching for Dll modules. If not specified, then the Dll search path is filled in from the current process's Dll search path. CurrentDirectory - An optional parameter that is an NT String variable pointing to the default directory string for the target process. If not specified, then the current directory string is filled in from the current process's current directory string. CommandLine - An optional parameter that is an NT String variable that will be passed to the target process as its command line. If not specified, then the command line passed to the target process will be a null string. Environment - An optional parameter that is an opaque pointer to an environment variable block of the type created by RtlCreateEnvironment routine. If not specified, then the target process will receive a copy of the calling process's environment variable block. WindowTitle - An optional parameter that is an NT String variable that points to the title string the target process is to use for its main window. If not specified, then a null string will be passed to the target process as its default window title. DesktopInfo - An optional parameter that is an NT String variable that contains uninterpreted data that is passed as is to the target process. If not specified, the target process will receive a pointer to an empty string. ShellInfo - An optional parameter that is an NT String variable that contains uninterpreted data that is passed as is to the target process. If not specified, the target process will receive a pointer to an empty string. RuntimeData - An optional parameter that is an NT String variable that contains uninterpreted data that is passed as is to the target process. If not specified, the target process will receive a pointer to an empty string. Return Value: STATUS_SUCCESS - The process parameters is De-Normalized and contains entries for each of the specified argument and variable strings. STATUS_BUFFER_TOO_SMALL - The specified process parameters buffer is too small to contain the argument and environment strings. The value of ProcessParameters->Length is modified to contain the buffer size needed to contain the argument and variable strings. --*/ { PRTL_USER_PROCESS_PARAMETERS p; NTSTATUS Status; ULONG ByteCount; PWSTR pDst; PPEB Peb; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; HANDLE CurDirHandle; BOOLEAN PebLockAcquired = FALSE; // // Acquire the Peb Lock for the duration while we copy information out // of it. // Peb = NtCurrentPeb(); ProcessParameters = Peb->ProcessParameters; Status = STATUS_SUCCESS; p = NULL; CurDirHandle = NULL; try { // // Validate input parameters // #define VALIDATE_STRING_PARAMETER(_x) \ do { \ ASSERT(ARGUMENT_PRESENT((_x))); \ if (!ARGUMENT_PRESENT((_x))) { \ Status = STATUS_INVALID_PARAMETER; \ leave; \ } \ if (ARGUMENT_PRESENT((_x))) { \ ASSERT((_x)->MaximumLength >= (_x)->Length); \ ASSERT(((_x)->Length == 0) || ((_x)->Buffer != NULL)); \ if (((_x)->MaximumLength < (_x)->Length) || \ (((_x)->Length != 0) && ((_x)->Buffer == NULL))) { \ Status = STATUS_INVALID_PARAMETER; \ leave; \ } \ } \ } while (0) #define VALIDATE_OPTIONAL_STRING_PARAMETER(_x) \ do { \ if (ARGUMENT_PRESENT((_x))) { \ ASSERT((_x)->MaximumLength >= (_x)->Length); \ ASSERT(((_x)->Length == 0) || ((_x)->Buffer != NULL)); \ if (((_x)->MaximumLength < (_x)->Length) || \ (((_x)->Length != 0) && ((_x)->Buffer == NULL))) { \ Status = STATUS_INVALID_PARAMETER; \ leave; \ } \ } \ } while (0) VALIDATE_STRING_PARAMETER (ImagePathName); VALIDATE_OPTIONAL_STRING_PARAMETER (DllPath); VALIDATE_OPTIONAL_STRING_PARAMETER (CurrentDirectory); VALIDATE_OPTIONAL_STRING_PARAMETER (CommandLine); VALIDATE_OPTIONAL_STRING_PARAMETER (WindowTitle); VALIDATE_OPTIONAL_STRING_PARAMETER (DesktopInfo); VALIDATE_OPTIONAL_STRING_PARAMETER (ShellInfo); VALIDATE_OPTIONAL_STRING_PARAMETER (RuntimeData); #undef VALIDATE_STRING_PARAMETER #undef VALIDATE_OPTIONAL_STRING_PARAMETER if (!ARGUMENT_PRESENT (CommandLine)) { CommandLine = ImagePathName; } if (!ARGUMENT_PRESENT (WindowTitle)) { WindowTitle = (PUNICODE_STRING)&NullString; } if (!ARGUMENT_PRESENT (DesktopInfo)) { DesktopInfo = (PUNICODE_STRING)&NullString; } if (!ARGUMENT_PRESENT (ShellInfo)) { ShellInfo = (PUNICODE_STRING)&NullString; } if (!ARGUMENT_PRESENT (RuntimeData)) { RuntimeData = (PUNICODE_STRING)&NullString; } // // Determine size need to contain the process parameter record // structure and all of the strings it will point to. Each string // will be aligned on a ULONG byte boundary. // We do the ones we can outside of the peb lock. // ByteCount = sizeof (*ProcessParameters); ByteCount += ROUND_UP (DOS_MAX_PATH_LENGTH*2, sizeof( ULONG ) ); ByteCount += ROUND_UP (ImagePathName->Length + sizeof(UNICODE_NULL), sizeof( ULONG ) ); ByteCount += ROUND_UP (CommandLine->Length + sizeof(UNICODE_NULL), sizeof( ULONG ) ); ByteCount += ROUND_UP (WindowTitle->MaximumLength, sizeof( ULONG ) ); ByteCount += ROUND_UP (DesktopInfo->MaximumLength, sizeof( ULONG ) ); ByteCount += ROUND_UP (ShellInfo->MaximumLength, sizeof( ULONG ) ); ByteCount += ROUND_UP (RuntimeData->MaximumLength, sizeof( ULONG ) ); PebLockAcquired = TRUE; RtlAcquirePebLock (); // // For optional pointer parameters, default them to point to their // corresponding field in the current process's process parameter // structure or to a null string. // if (!ARGUMENT_PRESENT (DllPath)) { DllPath = &ProcessParameters->DllPath; } if (!ARGUMENT_PRESENT (CurrentDirectory)) { if (ProcessParameters->CurrentDirectory.Handle) { CurDirHandle = (HANDLE)((ULONG_PTR)ProcessParameters->CurrentDirectory.Handle & ~OBJ_HANDLE_TAGBITS); CurDirHandle = (HANDLE)((ULONG_PTR)CurDirHandle | RTL_USER_PROC_CURDIR_INHERIT); } CurrentDirectory = &ProcessParameters->CurrentDirectory.DosPath; } else { ASSERT(CurrentDirectory->MaximumLength >= CurrentDirectory->Length); ASSERT((CurrentDirectory->Length == 0) || (CurrentDirectory->Buffer != NULL)); if (ProcessParameters->CurrentDirectory.Handle) { CurDirHandle = (HANDLE)((ULONG_PTR)ProcessParameters->CurrentDirectory.Handle & ~OBJ_HANDLE_TAGBITS); CurDirHandle = (HANDLE)((ULONG_PTR)CurDirHandle | RTL_USER_PROC_CURDIR_CLOSE); } } if (!ARGUMENT_PRESENT (Environment)) { Environment = ProcessParameters->Environment; } ByteCount += ROUND_UP (DllPath->MaximumLength, sizeof( ULONG ) ); // // Allocate memory for the process parameter record. // p = RtlAllocateHeap (RtlProcessHeap (), 0, ByteCount); if (p == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } RtlZeroMemory (p, sizeof (*p)); p->MaximumLength = ByteCount; p->Length = ByteCount; p->Flags = RTL_USER_PROC_PARAMS_NORMALIZED; p->DebugFlags = 0; p->Environment = Environment; p->CurrentDirectory.Handle = CurDirHandle; // // Inherits ^C inhibit information // p->ConsoleFlags = ProcessParameters->ConsoleFlags; pDst = (PWSTR)(p + 1); RtlpCopyProcString (&pDst, &p->CurrentDirectory.DosPath, CurrentDirectory, DOS_MAX_PATH_LENGTH*2); RtlpCopyProcString (&pDst, &p->DllPath, DllPath, 0); RtlpCopyProcString (&pDst, &p->ImagePathName, ImagePathName, ImagePathName->Length + sizeof (UNICODE_NULL)); if (CommandLine->Length == CommandLine->MaximumLength) { RtlpCopyProcString (&pDst, &p->CommandLine, CommandLine, 0); } else { RtlpCopyProcString (&pDst, &p->CommandLine, CommandLine, CommandLine->Length + sizeof (UNICODE_NULL)); } RtlpCopyProcString (&pDst, &p->WindowTitle, WindowTitle, 0); RtlpCopyProcString (&pDst, &p->DesktopInfo, DesktopInfo, 0); RtlpCopyProcString (&pDst, &p->ShellInfo, ShellInfo, 0); if (RuntimeData->Length != 0) { RtlpCopyProcString (&pDst, &p->RuntimeData, RuntimeData, 0); } *pProcessParameters = RtlDeNormalizeProcessParams (p); p = NULL; } finally { if (PebLockAcquired) { RtlReleasePebLock(); } if (AbnormalTermination ()) { Status = STATUS_ACCESS_VIOLATION; } if (p != NULL) { RtlDestroyProcessParameters (p); } } return Status; }
NTSTATUS Nt_CreateProcess( LPCWSTR ApplicationName, LPWSTR CommandLine, ULONG CreationFlags, LPCWSTR CurrentDirectory, LPSTARTUPINFO StartupInfo, LPPROCESS_INFORMATION ProcessInformation ) { NTSTATUS Status; WCHAR FullPathBuffer[MAX_PATH *2], DllPathBuffer[0x3000]; UNICODE_STRING PathVariableName, DllPath, ImagePathName; UNICODE_STRING _CommandLine, _CurrentDirectory; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; RTL_USER_PROCESS_INFORMATION ProcessInfo; if (!RtlDosPathNameToNtPathName_U(ApplicationName, &ImagePathName, NULL, NULL)) return STATUS_OBJECT_PATH_NOT_FOUND; RTL_CONST_STRING(PathVariableName, L"Path"); DllPath.Length = 0; DllPath.MaximumLength = sizeof(DllPathBuffer); DllPath.Buffer = DllPathBuffer; RtlQueryEnvironmentVariable_U(NULL, &PathVariableName, &DllPath); if (CommandLine != NULL) RtlInitUnicodeString(&_CommandLine, CommandLine); if (CurrentDirectory != NULL) RtlInitUnicodeString(&_CurrentDirectory, CurrentDirectory); Status = RtlCreateProcessParameters( &ProcessParameters, &ImagePathName, &DllPath, CurrentDirectory == NULL ? NULL : &_CurrentDirectory, CommandLine == NULL ? NULL : &_CommandLine, NULL, NULL, NULL, NULL, NULL ); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&ImagePathName); return Status; } ProcessInfo.Size = sizeof(ProcessInfo); Status = RtlCreateUserProcess( &ImagePathName, OBJ_CASE_INSENSITIVE, ProcessParameters, NULL, NULL, NULL, FALSE, NULL, NULL, &ProcessInfo ); RtlDestroyProcessParameters(ProcessParameters); RtlFreeUnicodeString(&ImagePathName); if (!NT_SUCCESS(Status)) return Status; if (!FLAG_ON(CreationFlags, CREATE_SUSPENDED)) { NtResumeThread(ProcessInfo.ThreadHandle, NULL); } if (ProcessInformation == NULL) { NtClose(ProcessInfo.ProcessHandle); NtClose(ProcessInfo.ThreadHandle); return Status; } ProcessInformation->dwProcessId = (ULONG)ProcessInfo.ClientId.UniqueProcess; ProcessInformation->dwThreadId = (ULONG)ProcessInfo.ClientId.UniqueThread; ProcessInformation->hProcess = ProcessInfo.ProcessHandle; ProcessInformation->hThread = ProcessInfo.ThreadHandle; return Status; }