internal static partial bool SetThreadPriorityBoost(SafeThreadHandle handle, [MarshalAs(UnmanagedType.Bool)] bool disabled);
internal static extern bool GetThreadPriorityBoost(SafeThreadHandle handle, out bool disabled);
public void Start( Guid payloadGuid, ArraySegment <byte> payloadData, SafeFileHandle inheritableReportHandle, string dllNameX64, string dllNameX86) { using (m_syncSemaphore.AcquireSemaphore()) { if (m_starting || m_disposed) { throw new InvalidOperationException("Cannot invoke start process more than once or after this instance has been Disposed."); } m_starting = true; bool redirectStreams = m_errorDataReceived != null || m_outputDataReceived != null; // The process creation flags: // - We use CREATE_DEFAULT_ERROR_MODE to ensure that the hard error mode of the child process (i.e., GetErrorMode) // is deterministic. Inheriting error mode is the default, but there may be some concurrent operation that temporarily // changes it (process global). The CLR has been observed to do so. // - We use CREATE_NO_WINDOW when redirecting stdout/err/in and there is a parent console (to prevent creating extra conhost.exe // processes on Windows when running headless) or when console sharing is disabled (typical for BuildXL which takes over // management of the console). Otherwise we use the parent console for output. int creationFlags = Native.Processes.ProcessUtilities.CREATE_DEFAULT_ERROR_MODE; if (redirectStreams && (s_consoleWindow != IntPtr.Zero || m_disableConHostSharing)) { creationFlags |= Native.Processes.ProcessUtilities.CREATE_NO_WINDOW; } SafeFileHandle standardInputWritePipeHandle = null; SafeFileHandle standardOutputReadPipeHandle = null; SafeFileHandle standardErrorReadPipeHandle = null; try { // set up the environment block parameter var environmentHandle = default(GCHandle); var payloadHandle = default(GCHandle); SafeFileHandle hStdInput = null; SafeFileHandle hStdOutput = null; SafeFileHandle hStdError = null; SafeThreadHandle threadHandle = null; try { IntPtr environmentPtr = IntPtr.Zero; if (m_unicodeEnvironmentBlock != null) { creationFlags |= Native.Processes.ProcessUtilities.CREATE_UNICODE_ENVIRONMENT; environmentHandle = GCHandle.Alloc(m_unicodeEnvironmentBlock, GCHandleType.Pinned); environmentPtr = environmentHandle.AddrOfPinnedObject(); } if (redirectStreams) { Pipes.CreateInheritablePipe( Pipes.PipeInheritance.InheritRead, Pipes.PipeFlags.WriteSideAsync, readHandle: out hStdInput, writeHandle: out standardInputWritePipeHandle); } else { // Avoid stdin hooking when not needed. hStdInput = new SafeFileHandle(new IntPtr(-1), true); } if (m_outputDataReceived != null) { Pipes.CreateInheritablePipe( Pipes.PipeInheritance.InheritWrite, Pipes.PipeFlags.ReadSideAsync, readHandle: out standardOutputReadPipeHandle, writeHandle: out hStdOutput); } else { // Pass through to the parent console. hStdOutput = new SafeFileHandle(new IntPtr(-1), true); } if (m_errorDataReceived != null) { Pipes.CreateInheritablePipe( Pipes.PipeInheritance.InheritWrite, Pipes.PipeFlags.ReadSideAsync, readHandle: out standardErrorReadPipeHandle, writeHandle: out hStdError); } else { // Pass through to the parent console. hStdError = new SafeFileHandle(new IntPtr(-1), true); } // We want a per-process job primarily. If nested job support is not available, then we make sure to not have a BuildXL-level job. if (JobObject.OSSupportsNestedJobs && m_createJobObjectForCurrentProcess) { JobObject.SetTerminateOnCloseOnCurrentProcessJob(); } // Initialize the injector m_processInjector = new ProcessTreeContext( payloadGuid, inheritableReportHandle, payloadData, dllNameX64, dllNameX86, m_numRetriesPipeReadOnCancel, m_debugPipeReporter, m_loggingContext); // If path remapping is enabled then we wrap the job object in a container, so the filter drivers get // configured (and they get cleaned up when the container is disposed) if (m_containerConfiguration.IsIsolationEnabled) { m_job = new Container( name: null, containerConfiguration: m_containerConfiguration, loggingContext: m_loggingContext); } else { m_job = new JobObject(null); } // We want the effects of SEM_NOGPFAULTERRORBOX on all children (but can't set that with CreateProcess). // That's not set otherwise (even if set in this process) due to CREATE_DEFAULT_ERROR_MODE above. m_job.SetLimitInformation(terminateOnClose: true, failCriticalErrors: false, allowProcessesToBreakAway: m_setJobBreakawayOk); m_processInjector.Listen(); if (m_containerConfiguration.IsIsolationEnabled) { // After calling SetLimitInformation, start up the container if present // This will throw if the container is not set up properly m_job.StartContainerIfPresent(); } // The call to the CreateDetouredProcess below will add a newly created process to the job. System.Diagnostics.Stopwatch m_startUpTimeWatch = System.Diagnostics.Stopwatch.StartNew(); var detouredProcessCreationStatus = Native.Processes.ProcessUtilities.CreateDetouredProcess( m_commandLine, creationFlags, environmentPtr, m_workingDirectory, hStdInput, hStdOutput, hStdError, m_job, m_processInjector.Injector, m_containerConfiguration.IsIsolationEnabled, out m_processHandle, out threadHandle, out m_processId, out int errorCode); m_startUpTimeWatch.Stop(); m_startUpTime = m_startUpTimeWatch.ElapsedMilliseconds; if (detouredProcessCreationStatus != CreateDetouredProcessStatus.Succeeded) { // TODO: Indicating user vs. internal errors (and particular phase failures e.g. adding to job object or injecting detours) // is good progress on the transparency into these failures. But consider making this indication visible beyond this // function without throwing exceptions; consider returning a structured value or logging events. string message; if (detouredProcessCreationStatus.IsDetoursSpecific()) { message = string.Format( CultureInfo.InvariantCulture, "Internal error during process creation: {0:G}", detouredProcessCreationStatus); } else if (detouredProcessCreationStatus == CreateDetouredProcessStatus.ProcessCreationFailed) { message = "Process creation failed"; } else { message = string.Format( CultureInfo.InvariantCulture, "Process creation failed: {0:G}", detouredProcessCreationStatus); } throw new BuildXLException( message, new NativeWin32Exception(errorCode)); } // TODO: We should establish good post-conditions for CreateDetouredProcess. As a temporary measure, it would be nice // to determine if we are sometimes getting invalid process handles with retVal == true. So for now we differentiate // that possible case with a unique error string. if (m_processHandle.IsInvalid) { throw new BuildXLException("Unable to start or detour a process (process handle invalid)", new NativeWin32Exception(errorCode)); } } finally { if (environmentHandle.IsAllocated) { environmentHandle.Free(); } if (payloadHandle.IsAllocated) { payloadHandle.Free(); } if (hStdInput != null && !hStdInput.IsInvalid) { hStdInput.Dispose(); } if (hStdOutput != null && !hStdOutput.IsInvalid) { hStdOutput.Dispose(); } if (hStdError != null && !hStdError.IsInvalid) { hStdError.Dispose(); } if (inheritableReportHandle != null && !inheritableReportHandle.IsInvalid) { inheritableReportHandle.Dispose(); } if (threadHandle != null && !threadHandle.IsInvalid) { threadHandle.Dispose(); } } if (standardInputWritePipeHandle != null) { var standardInputStream = new FileStream(standardInputWritePipeHandle, FileAccess.Write, m_bufferSize, isAsync: true); m_standardInputWriter = new StreamWriter(standardInputStream, m_standardInputEncoding, m_bufferSize) { AutoFlush = true }; } if (standardOutputReadPipeHandle != null) { var standardOutputFile = AsyncFileFactory.CreateAsyncFile( standardOutputReadPipeHandle, FileDesiredAccess.GenericRead, ownsHandle: true, kind: FileKind.Pipe); m_outputReader = new AsyncPipeReader(standardOutputFile, m_outputDataReceived, m_standardOutputEncoding, m_bufferSize); m_outputReader.BeginReadLine(); } if (standardErrorReadPipeHandle != null) { var standardErrorFile = AsyncFileFactory.CreateAsyncFile( standardErrorReadPipeHandle, FileDesiredAccess.GenericRead, ownsHandle: true, kind: FileKind.Pipe); m_errorReader = new AsyncPipeReader(standardErrorFile, m_errorDataReceived, m_standardErrorEncoding, m_bufferSize); m_errorReader.BeginReadLine(); } Contract.Assert(!m_processHandle.IsInvalid); m_processWaitHandle = new SafeWaitHandleFromSafeHandle(m_processHandle); m_waiting = true; TimeSpan timeout = m_timeout ?? Timeout.InfiniteTimeSpan; m_registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject( m_processWaitHandle, CompletionCallbackAsync, null, timeout, true); m_started = true; } catch (Exception e) { if (e is AccessViolationException) { Logger.Log.DetouredProcessAccessViolationException(m_loggingContext, creationFlags + " - " + m_commandLine); } // Dispose pipe handles in case they are not assigned to streams. if (m_standardInputWriter == null) { standardInputWritePipeHandle?.Dispose(); } if (m_outputReader == null) { standardOutputReadPipeHandle?.Dispose(); } if (m_errorReader == null) { standardErrorReadPipeHandle?.Dispose(); } throw; } } }
public static extern bool SetThreadPriority(SafeThreadHandle handle, int priority);
public static extern int SetThreadIdealProcessor(SafeThreadHandle handle, int processor);
internal static extern int WaitForSingleObject(SafeThreadHandle threadHandle, int milliseconds);
public static bool CreateProcess(ProcessStartInfo startInfo, bool createSuspended, out SafeProcessHandle process, out SafeThreadHandle thread, out uint processID, out uint threadID) { StringBuilder cmdLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments); STARTUPINFO lpStartupInfo = new STARTUPINFO(); PROCESS_INFORMATION lpProcessInformation = new PROCESS_INFORMATION(); SafeProcessHandle processHandle = new SafeProcessHandle(); SafeThreadHandle threadHandle = new SafeThreadHandle(); GCHandle environment = new GCHandle(); int creationFlags = 0; bool success; creationFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_PRESERVE_CODE_AUTHZ_LEVEL; if (createSuspended) { creationFlags |= CREATE_SUSPENDED; } if (startInfo.CreateNoWindow) { creationFlags |= CREATE_NO_WINDOW; } IntPtr pinnedEnvironment = IntPtr.Zero; if (startInfo.EnvironmentVariables != null) { bool unicode = false; if (IsNt) { creationFlags |= CREATE_UNICODE_ENVIRONMENT; unicode = true; } environment = GCHandle.Alloc(EnvironmentToByteArray(startInfo.EnvironmentVariables, unicode), GCHandleType.Pinned); pinnedEnvironment = environment.AddrOfPinnedObject(); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == "") { workingDirectory = Environment.CurrentDirectory; } success = CreateProcess(null, cmdLine, null, null, false, creationFlags, pinnedEnvironment, workingDirectory, lpStartupInfo, lpProcessInformation); if ((lpProcessInformation.hProcess != IntPtr.Zero) && (lpProcessInformation.hProcess != INVALID_HANDLE_VALUE)) { processHandle.InitialSetHandle(lpProcessInformation.hProcess); } if ((lpProcessInformation.hThread != IntPtr.Zero) && (lpProcessInformation.hThread != INVALID_HANDLE_VALUE)) { threadHandle.InitialSetHandle(lpProcessInformation.hThread); } if (environment.IsAllocated) { environment.Free(); } lpStartupInfo.Dispose(); if (success && !processHandle.IsInvalid && !threadHandle.IsInvalid) { process = processHandle; thread = threadHandle; processID = lpProcessInformation.dwProcessId; threadID = lpProcessInformation.dwThreadId; return(true); } process = null; thread = null; processID = 0; threadID = 0; return(false); }
public static extern IntPtr SetThreadAffinityMask(SafeThreadHandle handle, HandleRef mask);
public static extern int GetThreadPriority(SafeThreadHandle handle);
public static extern bool SetThreadPriorityBoost(SafeThreadHandle handle, bool disabled);
public static extern bool GetThreadTimes(SafeThreadHandle handle, out long creation, out long exit, out long kernel, out long user);
private static unsafe int ExecWaitWithCaptureUnimpersonated(SafeUserTokenHandle userToken, string cmd, string currentDir, TempFileCollection tempFiles, ref string outputName, ref string errorName, string trueCmdLine) { IntSecurity.UnmanagedCode.Demand(); FileStream output; FileStream error; int retValue = 0; if (outputName == null || outputName.Length == 0) { outputName = tempFiles.AddExtension("out"); } if (errorName == null || errorName.Length == 0) { errorName = tempFiles.AddExtension("err"); } // Create the files output = CreateInheritedFile(outputName); error = CreateInheritedFile(errorName); bool success = false; SafeNativeMethods.PROCESS_INFORMATION pi = new SafeNativeMethods.PROCESS_INFORMATION(); SafeProcessHandle procSH = new SafeProcessHandle(); SafeThreadHandle threadSH = new SafeThreadHandle(); SafeUserTokenHandle primaryToken = null; try { // Output the command line... StreamWriter sw = new StreamWriter(output, Encoding.UTF8); sw.Write(currentDir); sw.Write("> "); // 'true' command line is used in case the command line points to // a response file sw.WriteLine(trueCmdLine != null ? trueCmdLine : cmd); sw.WriteLine(); sw.WriteLine(); sw.Flush(); NativeMethods.STARTUPINFO si = new NativeMethods.STARTUPINFO(); si.cb = Marshal.SizeOf(si); #if FEATURE_PAL si.dwFlags = NativeMethods.STARTF_USESTDHANDLES; #else //!FEATURE_PAL si.dwFlags = NativeMethods.STARTF_USESTDHANDLES | NativeMethods.STARTF_USESHOWWINDOW; si.wShowWindow = NativeMethods.SW_HIDE; #endif //!FEATURE_PAL si.hStdOutput = output.SafeFileHandle; si.hStdError = error.SafeFileHandle; si.hStdInput = new SafeFileHandle(UnsafeNativeMethods.GetStdHandle(NativeMethods.STD_INPUT_HANDLE), false); // // Prepare the environment // #if PLATFORM_UNIX StringDictionary environment = new CaseSensitiveStringDictionary(); #else StringDictionary environment = new StringDictionary(); #endif // PLATFORM_UNIX // Add the current environment foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables()) { environment[(string)entry.Key] = (string)entry.Value; } // Add the flag to indicate restricted security in the process environment["_ClrRestrictSecAttributes"] = "1"; #if DEBUG environment["OANOCACHE"] = "1"; #endif // set up the environment block parameter byte[] environmentBytes = EnvironmentBlock.ToByteArray(environment, false); fixed(byte *environmentBytesPtr = environmentBytes) { IntPtr environmentPtr = new IntPtr((void *)environmentBytesPtr); if (userToken == null || userToken.IsInvalid) { RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { success = NativeMethods.CreateProcess( null, // String lpApplicationName, new StringBuilder(cmd), // String lpCommandLine, null, // SECURITY_ATTRIBUTES lpProcessAttributes, null, // SECURITY_ATTRIBUTES lpThreadAttributes, true, // bool bInheritHandles, 0, // int dwCreationFlags, environmentPtr, // IntPtr lpEnvironment, currentDir, // String lpCurrentDirectory, si, // STARTUPINFO lpStartupInfo, pi); // PROCESS_INFORMATION lpProcessInformation); if (pi.hProcess != (IntPtr)0 && pi.hProcess != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(pi.hProcess); } if (pi.hThread != (IntPtr)0 && pi.hThread != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(pi.hThread); } } } else { #if FEATURE_PAL throw new NotSupportedException(); #else success = SafeUserTokenHandle.DuplicateTokenEx( userToken, NativeMethods.TOKEN_ALL_ACCESS, null, NativeMethods.IMPERSONATION_LEVEL_SecurityImpersonation, NativeMethods.TOKEN_TYPE_TokenPrimary, out primaryToken ); if (success) { RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { success = NativeMethods.CreateProcessAsUser( primaryToken, // int token, null, // String lpApplicationName, cmd, // String lpCommandLine, null, // SECURITY_ATTRIBUTES lpProcessAttributes, null, // SECURITY_ATTRIBUTES lpThreadAttributes, true, // bool bInheritHandles, 0, // int dwCreationFlags, new HandleRef(null, environmentPtr), // IntPtr lpEnvironment, currentDir, // String lpCurrentDirectory, si, // STARTUPINFO lpStartupInfo, pi); // PROCESS_INFORMATION lpProcessInformation); if (pi.hProcess != (IntPtr)0 && pi.hProcess != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(pi.hProcess); } if (pi.hThread != (IntPtr)0 && pi.hThread != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(pi.hThread); } } } #endif // !FEATURE_PAL } } } finally { // Close the file handles if (!success && (primaryToken != null && !primaryToken.IsInvalid)) { primaryToken.Close(); primaryToken = null; } output.Close(); error.Close(); } if (success) { try { bool signaled; ProcessWaitHandle pwh = null; try { pwh = new ProcessWaitHandle(procSH); signaled = pwh.WaitOne(ProcessTimeOut, false); } finally { if (pwh != null) { pwh.Close(); } } // Check for timeout if (!signaled) { throw new ExternalException(SR.GetString(SR.ExecTimeout, cmd), NativeMethods.WAIT_TIMEOUT); } // Check the process's exit code int status = NativeMethods.STILL_ACTIVE; if (!NativeMethods.GetExitCodeProcess(procSH, out status)) { throw new ExternalException(SR.GetString(SR.ExecCantGetRetCode, cmd), Marshal.GetLastWin32Error()); } retValue = status; } finally { procSH.Close(); threadSH.Close(); if (primaryToken != null && !primaryToken.IsInvalid) { primaryToken.Close(); } } } else { int err = Marshal.GetLastWin32Error(); if (err == NativeMethods.ERROR_NOT_ENOUGH_MEMORY) { throw new OutOfMemoryException(); } Win32Exception win32Exception = new Win32Exception(err); ExternalException ex = new ExternalException(SR.GetString(SR.ExecCantExec, cmd), win32Exception); throw ex; } return(retValue); }
internal static extern bool GetExitCodeThread(SafeThreadHandle threadHandle, out ThreadExitCode exitCode);
internal static extern uint Wow64GetThreadContext(SafeThreadHandle threadHandle, IntPtr contextBuffer);
internal static extern bool SetThreadContext(SafeThreadHandle threadHandle, IntPtr context);
public static extern uint ResumeThread(SafeThreadHandle hThread);
private bool StartWithCreateProcess(ProcessStartInfo startInfo) { if (startInfo.StandardOutputEncoding != null && !startInfo.RedirectStandardOutput) { throw new InvalidOperationException("StandardOutputEncodingNotAllowed"); } if (startInfo.StandardErrorEncoding != null && !startInfo.RedirectStandardError) { throw new InvalidOperationException("StandardErrorEncodingNotAllowed"); } StringBuilder stringBuilder = Process2.BuildCommandLine(startInfo.FileName, startInfo.Arguments); NativeMethods.STARTUPINFO sTARTUPINFO = new NativeMethods.STARTUPINFO(); SafeNativeMethods.PROCESS_INFORMATION pROCESS_INFORMATION = new SafeNativeMethods.PROCESS_INFORMATION(); SafeProcessHandle safeProcessHandle = new SafeProcessHandle(); SafeThreadHandle safeThreadHandle = new SafeThreadHandle(); int num = 0; SafeFileHandle handle = null; SafeFileHandle handle2 = null; SafeFileHandle handle3 = null; GCHandle gCHandle = default(GCHandle); lock (Process2.s_CreateProcessLock) { try { if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { if (startInfo.RedirectStandardInput) { CreatePipe(out handle, out sTARTUPINFO.hStdInput, true); } else { sTARTUPINFO.hStdInput = new SafeFileHandle(NativeMethods.GetStdHandle(-10), false); } if (startInfo.RedirectStandardOutput) { CreatePipe(out handle2, out sTARTUPINFO.hStdOutput, false); } else { sTARTUPINFO.hStdOutput = new SafeFileHandle(NativeMethods.GetStdHandle(-11), false); } if (startInfo.RedirectStandardError) { CreatePipe(out handle3, out sTARTUPINFO.hStdError, false); } else { sTARTUPINFO.hStdError = sTARTUPINFO.hStdOutput; } sTARTUPINFO.dwFlags = 256; } int num2 = 0; if (startInfo.CreateNoWindow) { num2 |= 134217728; } IntPtr intPtr = (IntPtr)0; //if (startInfo.environmentVariables != null) //{ // bool unicode = false; // if (ProcessManager.IsNt) // { // num2 |= 1024; // unicode = true; // } // byte[] value = EnvironmentBlock.ToByteArray(startInfo.environmentVariables, unicode); // gCHandle = GCHandle.Alloc(value, GCHandleType.Pinned); // intPtr = gCHandle.AddrOfPinnedObject(); //} string text = startInfo.WorkingDirectory; if (text == string.Empty) { text = Environment.CurrentDirectory; } bool flag2; //if (startInfo.UserName.Length != 0) //{ // NativeMethods.LogonFlags logonFlags = (NativeMethods.LogonFlags)0; // if (startInfo.LoadUserProfile) // { // logonFlags = NativeMethods.LogonFlags.LOGON_WITH_PROFILE; // } // IntPtr intPtr2 = IntPtr.Zero; // try // { // if (startInfo.Password == null) // { // intPtr2 = Marshal.StringToCoTaskMemUni(string.Empty); // } // else // { // intPtr2 = Marshal.SecureStringToCoTaskMemUnicode(startInfo.Password); // } // RuntimeHelpers.PrepareConstrainedRegions(); // try // { // } // finally // { // flag2 = NativeMethods.CreateProcessWithLogonW(startInfo.UserName, startInfo.Domain, intPtr2, logonFlags, null, stringBuilder, num2, intPtr, text, sTARTUPINFO, pROCESS_INFORMATION); // if (!flag2) // { // num = Marshal.GetLastWin32Error(); // } // if (pROCESS_INFORMATION.hProcess != (IntPtr)0 && pROCESS_INFORMATION.hProcess != NativeMethods.INVALID_HANDLE_VALUE) // { // safeProcessHandle.InitialSetHandle(pROCESS_INFORMATION.hProcess); // } // if (pROCESS_INFORMATION.hThread != (IntPtr)0 && pROCESS_INFORMATION.hThread != NativeMethods.INVALID_HANDLE_VALUE) // { // safeThreadHandle.InitialSetHandle(pROCESS_INFORMATION.hThread); // } // } // if (flag2) // { // goto IL_3B9; // } // if (num == 193 || num == 216) // { // throw new Win32Exception(num, SR.GetString("InvalidApplication")); // } // throw new Win32Exception(num); // } // finally // { // if (intPtr2 != IntPtr.Zero) // { // Marshal.ZeroFreeCoTaskMemUnicode(intPtr2); // } // } //} RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { flag2 = NativeMethods.CreateProcess(null, stringBuilder, null, null, true, num2, intPtr, text, sTARTUPINFO, pROCESS_INFORMATION); if (!flag2) { num = Marshal.GetLastWin32Error(); } if (pROCESS_INFORMATION.hProcess != (IntPtr)0 && pROCESS_INFORMATION.hProcess != NativeMethods.INVALID_HANDLE_VALUE) { safeProcessHandle.InitialSetHandle(pROCESS_INFORMATION.hProcess); } if (pROCESS_INFORMATION.hThread != (IntPtr)0 && pROCESS_INFORMATION.hThread != NativeMethods.INVALID_HANDLE_VALUE) { safeThreadHandle.InitialSetHandle(pROCESS_INFORMATION.hThread); } } if (!flag2) { if (num == 193 || num == 216) { throw new Win32Exception(num, "InvalidApplication"); } throw new Win32Exception(num); } } finally { if (gCHandle.IsAllocated) { gCHandle.Free(); } sTARTUPINFO.Dispose(); } } if (startInfo.RedirectStandardInput) { standardInput = new StreamWriter(new FileStream(handle, FileAccess.Write, 4096, false), Console.InputEncoding, 4096); standardInput.AutoFlush = true; } if (startInfo.RedirectStandardOutput) { Encoding encoding = (startInfo.StandardOutputEncoding != null) ? startInfo.StandardOutputEncoding : Console.OutputEncoding; standardOutput = new StreamReader(new FileStream(handle2, FileAccess.Read, 4096, false), encoding, true, 4096); } if (startInfo.RedirectStandardError) { Encoding encoding2 = (startInfo.StandardErrorEncoding != null) ? startInfo.StandardErrorEncoding : Console.OutputEncoding; standardError = new StreamReader(new FileStream(handle3, FileAccess.Read, 4096, false), encoding2, true, 4096); } bool result = false; if (!safeProcessHandle.IsInvalid) { SetProcessHandle(safeProcessHandle); SetProcessId(pROCESS_INFORMATION.dwProcessId); safeThreadHandle.Close(); result = true; } return result; }
internal static partial bool GetThreadTimes(SafeThreadHandle handle, out long creation, out long exit, out long kernel, out long user);
internal void ReadFromHandle(SafeThreadHandle handle) { throw new NotImplementedException(); }
internal void WriteToHandle(SafeThreadHandle handle) { throw new NotImplementedException(); }
internal static extern IntPtr SetThreadAffinityMask(SafeThreadHandle handle, IntPtr mask);
internal static unsafe extern bool SetThreadContext(SafeThreadHandle handle, Native *ctx);
internal static partial int SetThreadIdealProcessor(SafeThreadHandle handle, int processor);
internal static extern bool Wow64SetThreadContext(SafeThreadHandle threadHandle, IntPtr contextBuffer);
/// <summary> /// Calls <see cref="CreateProcessAsUserW"/> and safely stores the obtained handles. /// </summary> /// <param name="userToken">Token to impersonate the external process</param> /// <param name="createFlags">Flags used to create the external process</param> /// <param name="startupInfo">Startup information used to create the external process</param> /// <returns><c>true</c> if the call to <see cref="CreateProcessAsUserW"/> was successful; otherwise <c>false</c></returns> private bool SafeCreateProcessAsUserW(IntPtr userToken, CreateProcessFlags createFlags, StartupInfo startupInfo) { _processHandle = new SafeProcessHandle(); var threadHandle = new SafeThreadHandle(); bool success; // The following is necessary to make sure that processInformation.hProcess and processInformation.hThread // are safely stored in the respective SafeHandle classes. It is, unfortunately, not possible to define // processInformation.hProcess and processInformation.hThread as SafeHandles and use processInformation // as an out parameter, because the unmanaged code is not able to create these objects. We therefore use // IntPtr and ensure in the following that the IntPtrs are stored in SafeHandle objects immediately after // they have been obtained. // For details see here: https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions(v=vs.110).aspx RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { ProcessInformation processInformation; success = CreateProcessAsUserW(userToken, null, GetCommandLine(), IntPtr.Zero, IntPtr.Zero, true, createFlags, IntPtr.Zero, null, startupInfo, out processInformation); if (success) { _processHandle.InitialSetHandle(processInformation.hProcess); threadHandle.InitialSetHandle(processInformation.hThread); _processId = processInformation.dwProcessId; } } // We don't need the threadHandle and therefore immediately dispose it. threadHandle.Dispose(); if (success) return true; _processHandle.Dispose(); var error = Marshal.GetLastWin32Error(); _debugLogger.Error("AsyncImpersonationProcess ({0}): Cannot start process. ErrorCode: {1} ({2})", StartInfo.FileName, error, new Win32Exception(error).Message); return false; }
internal static extern Enumerations.NtStatus RtlCreateUserThread(SafeProcessHandle processHandle, IntPtr securityDescriptorBuffer, bool createSuspended, int stackZeroBits, IntPtr stackReserved, IntPtr stackCommit, IntPtr startAddress, IntPtr parameter, out SafeThreadHandle threadHandle, out IntPtr clientIdBuffer);
/// <summary>Starts the process using the supplied start info.</summary> /// <param name="startInfo">The start info with which to start the process.</param> private bool StartCore(ProcessStartInfo startInfo) { // See knowledge base article Q190351 for an explanation of the following code. Noteworthy tricky points: // * The handles are duplicated as non-inheritable before they are passed to CreateProcess so // that the child process can not close them // * CreateProcess allows you to redirect all or none of the standard IO handles, so we use // GetStdHandle for the handles that are not being redirected StringBuilder commandLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments); Interop.STARTUPINFO startupInfo = new Interop.STARTUPINFO(); Interop.PROCESS_INFORMATION processInfo = new Interop.PROCESS_INFORMATION(); Interop.SECURITY_ATTRIBUTES unused_SecAttrs = new Interop.SECURITY_ATTRIBUTES(); SafeProcessHandle procSH = new SafeProcessHandle(); SafeThreadHandle threadSH = new SafeThreadHandle(); bool retVal; int errorCode = 0; // handles used in parent process SafeFileHandle standardInputWritePipeHandle = null; SafeFileHandle standardOutputReadPipeHandle = null; SafeFileHandle standardErrorReadPipeHandle = null; GCHandle environmentHandle = new GCHandle(); lock (s_createProcessLock) { try { // set up the streams if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { if (startInfo.RedirectStandardInput) { CreatePipe(out standardInputWritePipeHandle, out startupInfo.hStdInput, true); } else { startupInfo.hStdInput = new SafeFileHandle(Interop.mincore.GetStdHandle(Interop.STD_INPUT_HANDLE), false); } if (startInfo.RedirectStandardOutput) { CreatePipe(out standardOutputReadPipeHandle, out startupInfo.hStdOutput, false); } else { startupInfo.hStdOutput = new SafeFileHandle(Interop.mincore.GetStdHandle(Interop.STD_OUTPUT_HANDLE), false); } if (startInfo.RedirectStandardError) { CreatePipe(out standardErrorReadPipeHandle, out startupInfo.hStdError, false); } else { startupInfo.hStdError = new SafeFileHandle(Interop.mincore.GetStdHandle(Interop.STD_ERROR_HANDLE), false); } startupInfo.dwFlags = Interop.STARTF_USESTDHANDLES; } // set up the creation flags paramater int creationFlags = 0; if (startInfo.CreateNoWindow) { creationFlags |= Interop.CREATE_NO_WINDOW; } // set up the environment block parameter IntPtr environmentPtr = (IntPtr)0; if (startInfo._environmentVariables != null) { creationFlags |= Interop.CREATE_UNICODE_ENVIRONMENT; byte[] environmentBytes = EnvironmentVariablesToByteArray(startInfo._environmentVariables); environmentHandle = GCHandle.Alloc(environmentBytes, GCHandleType.Pinned); environmentPtr = environmentHandle.AddrOfPinnedObject(); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == string.Empty) { workingDirectory = Directory.GetCurrentDirectory(); } if (startInfo.UserName.Length != 0) { Interop.LogonFlags logonFlags = (Interop.LogonFlags) 0; if (startInfo.LoadUserProfile) { logonFlags = Interop.LogonFlags.LOGON_WITH_PROFILE; } IntPtr password = IntPtr.Zero; try { if (startInfo.Password == null) { password = Marshal.StringToCoTaskMemUni(String.Empty); } else { password = SecureStringMarshal.SecureStringToCoTaskMemUnicode(startInfo.Password); } try { } finally { retVal = Interop.mincore.CreateProcessWithLogonW( startInfo.UserName, startInfo.Domain, password, logonFlags, null, // we don't need this since all the info is in commandLine commandLine, creationFlags, environmentPtr, workingDirectory, startupInfo, // pointer to STARTUPINFO processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != (IntPtr)Interop.INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != (IntPtr)Interop.INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(processInfo.hThread); } } if (!retVal) { if (errorCode == Interop.ERROR_BAD_EXE_FORMAT || errorCode == Interop.ERROR_EXE_MACHINE_TYPE_MISMATCH) { throw new Win32Exception(errorCode, SR.InvalidApplication); } throw new Win32Exception(errorCode); } } finally { if (password != IntPtr.Zero) { Marshal.ZeroFreeCoTaskMemUnicode(password); } } } else { try { } finally { retVal = Interop.mincore.CreateProcess( null, // we don't need this since all the info is in commandLine commandLine, // pointer to the command line string unused_SecAttrs, // address to process security attributes, we don't need to inheriat the handle unused_SecAttrs, // address to thread security attributes. true, // handle inheritance flag creationFlags, // creation flags environmentPtr, // pointer to new environment block workingDirectory, // pointer to current directory name startupInfo, // pointer to STARTUPINFO processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } if (processInfo.hProcess != (IntPtr)0 && processInfo.hProcess != (IntPtr)Interop.INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != (IntPtr)0 && processInfo.hThread != (IntPtr)Interop.INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(processInfo.hThread); } } if (!retVal) { if (errorCode == Interop.ERROR_BAD_EXE_FORMAT || errorCode == Interop.ERROR_EXE_MACHINE_TYPE_MISMATCH) { throw new Win32Exception(errorCode, SR.InvalidApplication); } throw new Win32Exception(errorCode); } } } finally { // free environment block if (environmentHandle.IsAllocated) { environmentHandle.Free(); } startupInfo.Dispose(); } } if (startInfo.RedirectStandardInput) { Encoding enc = GetEncoding((int)Interop.mincore.GetConsoleCP()); _standardInput = new StreamWriter(new FileStream(standardInputWritePipeHandle, FileAccess.Write, 4096, false), enc, 4096); _standardInput.AutoFlush = true; } if (startInfo.RedirectStandardOutput) { Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.mincore.GetConsoleOutputCP()); _standardOutput = new StreamReader(new FileStream(standardOutputReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } if (startInfo.RedirectStandardError) { Encoding enc = startInfo.StandardErrorEncoding ?? GetEncoding((int)Interop.mincore.GetConsoleOutputCP()); _standardError = new StreamReader(new FileStream(standardErrorReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } bool ret = false; if (!procSH.IsInvalid) { SetProcessHandle(procSH); SetProcessId((int)processInfo.dwProcessId); threadSH.Dispose(); ret = true; } return(ret); }
/// <summary>Starts the process using the supplied start info.</summary> /// <param name="startInfo">The start info with which to start the process.</param> private unsafe bool StartWithCreateProcess(ProcessStartInfo startInfo) { // See knowledge base article Q190351 for an explanation of the following code. Noteworthy tricky points: // * The handles are duplicated as non-inheritable before they are passed to CreateProcess so // that the child process can not close them // * CreateProcess allows you to redirect all or none of the standard IO handles, so we use // GetStdHandle for the handles that are not being redirected StringBuilder commandLine = BuildCommandLine(startInfo.FileName, StartInfo.Arguments); Process.AppendArguments(commandLine, StartInfo.ArgumentList); Interop.Kernel32.STARTUPINFO startupInfo = new Interop.Kernel32.STARTUPINFO(); Interop.Kernel32.PROCESS_INFORMATION processInfo = new Interop.Kernel32.PROCESS_INFORMATION(); Interop.Kernel32.SECURITY_ATTRIBUTES unused_SecAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES(); SafeProcessHandle procSH = new SafeProcessHandle(); SafeThreadHandle threadSH = new SafeThreadHandle(); // handles used in parent process SafeFileHandle parentInputPipeHandle = null; SafeFileHandle childInputPipeHandle = null; SafeFileHandle parentOutputPipeHandle = null; SafeFileHandle childOutputPipeHandle = null; SafeFileHandle parentErrorPipeHandle = null; SafeFileHandle childErrorPipeHandle = null; lock (s_createProcessLock) { try { startupInfo.cb = sizeof(Interop.Kernel32.STARTUPINFO); // set up the streams if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { if (startInfo.RedirectStandardInput) { CreatePipe(out parentInputPipeHandle, out childInputPipeHandle, true); } else { childInputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_INPUT_HANDLE), false); } if (startInfo.RedirectStandardOutput) { CreatePipe(out parentOutputPipeHandle, out childOutputPipeHandle, false); } else { childOutputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_OUTPUT_HANDLE), false); } if (startInfo.RedirectStandardError) { CreatePipe(out parentErrorPipeHandle, out childErrorPipeHandle, false); } else { childErrorPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_ERROR_HANDLE), false); } startupInfo.hStdInput = childInputPipeHandle.DangerousGetHandle(); startupInfo.hStdOutput = childOutputPipeHandle.DangerousGetHandle(); startupInfo.hStdError = childErrorPipeHandle.DangerousGetHandle(); startupInfo.dwFlags = Interop.Advapi32.StartupInfoOptions.STARTF_USESTDHANDLES; } // set up the creation flags parameter int creationFlags = 0; if (startInfo.CreateNoWindow) { creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_NO_WINDOW; } // set up the environment block parameter string environmentBlock = null; if (startInfo._environmentVariables != null) { creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_UNICODE_ENVIRONMENT; environmentBlock = GetEnvironmentVariablesBlock(startInfo._environmentVariables); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == string.Empty) { workingDirectory = Directory.GetCurrentDirectory(); } bool retVal; int errorCode = 0; if (startInfo.UserName.Length != 0) { if (startInfo.Password != null && startInfo.PasswordInClearText != null) { throw new ArgumentException(SR.CantSetDuplicatePassword); } Interop.Advapi32.LogonFlags logonFlags = (Interop.Advapi32.LogonFlags) 0; if (startInfo.LoadUserProfile) { logonFlags = Interop.Advapi32.LogonFlags.LOGON_WITH_PROFILE; } fixed(char *passwordInClearTextPtr = startInfo.PasswordInClearText ?? string.Empty) fixed(char *environmentBlockPtr = environmentBlock) { IntPtr passwordPtr = (startInfo.Password != null) ? Marshal.SecureStringToGlobalAllocUnicode(startInfo.Password) : IntPtr.Zero; try { retVal = Interop.Advapi32.CreateProcessWithLogonW( startInfo.UserName, startInfo.Domain, (passwordPtr != IntPtr.Zero) ? passwordPtr : (IntPtr)passwordInClearTextPtr, logonFlags, null, // we don't need this since all the info is in commandLine commandLine, creationFlags, (IntPtr)environmentBlockPtr, workingDirectory, ref startupInfo, // pointer to STARTUPINFO ref processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } } finally { if (passwordPtr != IntPtr.Zero) { Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr); } } } } else { fixed(char *environmentBlockPtr = environmentBlock) { retVal = Interop.Kernel32.CreateProcess( null, // we don't need this since all the info is in commandLine commandLine, // pointer to the command line string ref unused_SecAttrs, // address to process security attributes, we don't need to inherit the handle ref unused_SecAttrs, // address to thread security attributes. true, // handle inheritance flag creationFlags, // creation flags (IntPtr)environmentBlockPtr, // pointer to new environment block workingDirectory, // pointer to current directory name ref startupInfo, // pointer to STARTUPINFO ref processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } } } if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != new IntPtr(-1)) { procSH.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != new IntPtr(-1)) { threadSH.InitialSetHandle(processInfo.hThread); } if (!retVal) { if (errorCode == Interop.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH) { throw new Win32Exception(errorCode, SR.InvalidApplication); } throw new Win32Exception(errorCode); } } finally { childInputPipeHandle?.Dispose(); childOutputPipeHandle?.Dispose(); childErrorPipeHandle?.Dispose(); threadSH?.Dispose(); } } if (startInfo.RedirectStandardInput) { Encoding enc = startInfo.StandardInputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleCP()); _standardInput = new StreamWriter(new FileStream(parentInputPipeHandle, FileAccess.Write, 4096, false), enc, 4096); _standardInput.AutoFlush = true; } if (startInfo.RedirectStandardOutput) { Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); _standardOutput = new StreamReader(new FileStream(parentOutputPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } if (startInfo.RedirectStandardError) { Encoding enc = startInfo.StandardErrorEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); _standardError = new StreamReader(new FileStream(parentErrorPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } if (procSH.IsInvalid) { return(false); } SetProcessHandle(procSH); SetProcessId((int)processInfo.dwProcessId); return(true); }
internal static extern int ResumeThread(SafeThreadHandle threadHandle);
internal static partial bool SetThreadPriority(SafeThreadHandle handle, int priority);
internal static extern int SuspendThread(SafeThreadHandle threadHandle);
internal static extern void WaitForSingleObject(SafeThreadHandle handle, int millisecondsToWait);
internal static extern bool Wow64SetThreadContext(SafeThreadHandle threadHandle, ref Wow64Context context);
public static bool CreateProcess(ProcessStartInfo startInfo, bool createSuspended, out SafeProcessHandle process, out SafeThreadHandle thread, out uint processID, out uint threadID) { StringBuilder cmdLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments); STARTUPINFO lpStartupInfo = new STARTUPINFO(); PROCESS_INFORMATION lpProcessInformation = new PROCESS_INFORMATION(); SafeProcessHandle processHandle = new SafeProcessHandle(); SafeThreadHandle threadHandle = new SafeThreadHandle(); GCHandle environment = new GCHandle(); int creationFlags = 0; bool success; creationFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_PRESERVE_CODE_AUTHZ_LEVEL; if (createSuspended) creationFlags |= CREATE_SUSPENDED; if (startInfo.CreateNoWindow) creationFlags |= CREATE_NO_WINDOW; IntPtr pinnedEnvironment = IntPtr.Zero; if (startInfo.EnvironmentVariables != null) { bool unicode = false; if (IsNt) { creationFlags |= CREATE_UNICODE_ENVIRONMENT; unicode = true; } environment = GCHandle.Alloc(EnvironmentToByteArray(startInfo.EnvironmentVariables, unicode), GCHandleType.Pinned); pinnedEnvironment = environment.AddrOfPinnedObject(); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == "") workingDirectory = Environment.CurrentDirectory; success = CreateProcess(null, cmdLine, null, null, false, creationFlags, pinnedEnvironment, workingDirectory, lpStartupInfo, lpProcessInformation); if ((lpProcessInformation.hProcess != IntPtr.Zero) && (lpProcessInformation.hProcess != INVALID_HANDLE_VALUE)) processHandle.InitialSetHandle(lpProcessInformation.hProcess); if ((lpProcessInformation.hThread != IntPtr.Zero) && (lpProcessInformation.hThread != INVALID_HANDLE_VALUE)) threadHandle.InitialSetHandle(lpProcessInformation.hThread); if (environment.IsAllocated) environment.Free(); lpStartupInfo.Dispose(); if (success && !processHandle.IsInvalid && !threadHandle.IsInvalid) { process = processHandle; thread = threadHandle; processID = lpProcessInformation.dwProcessId; threadID = lpProcessInformation.dwThreadId; return true; } process = null; thread = null; processID = 0; threadID = 0; return false; }
=> new byte[0]; // TODO: this is only used for communication between BuildXL and external sandboxed process, which we don't do yet on Unix systems. /// <inheritdoc /> public CreateDetouredProcessStatus CreateDetouredProcess(string lpcwCommandLine, int dwCreationFlags, IntPtr lpEnvironment, string lpcwWorkingDirectory, SafeHandle hStdInput, SafeHandle hStdOutput, SafeHandle hStdError, SafeHandle hJob, IProcessInjector injector, bool addProcessToSilo, out SafeProcessHandle phProcess, out SafeThreadHandle phThread, out int pdwProcessId, out int errorCode) => throw new NotImplementedException();