CreateProcessAsUser在新场景返回C0000142,原场景正常的问题排查
问题描述
我们遇到一个仅在新增支持场景中出现的问题。
原有正常运行场景(已稳定运行多年)
- 无管理员权限的交互用户启动wix bootstrapper,该程序启动
update-service,随后以local system身份启动wix bootstrapper的第二个实例。拥有local system权限的第二个实例负责安装软件。由于需要处理数据库操作,我们在自定义操作中执行dbinit工具——该工具需访问SQL Server,因此必须以原始用户权限运行。此场景运行正常。
[原有场景流程示意图]
新增场景问题
- 现在需要支持由Windows服务而非交互用户启动wix bootstrapper的场景,原本预期能直接运行,但实际出现问题。
[新增场景流程示意图]
在新场景中,CreateProcessAsUser执行成功,但dbinit进程随即退出,返回错误码C0000142。
我们尝试过以下操作,但均无效果:
- 创建自定义
WindowStation/Desktop,通过ProcessHacker确认权限正确,且将句柄标记为inheritable - 调整句柄是否为
inheritable、设置lpDesktop参数
发现当Windows服务运行用户属于本地管理员组时问题解决,但生产环境无法采用此配置。
另外,很多代码示例使用LogonUser获取令牌,但我们的用户大多是MSA(托管服务账户),无密码,此方法不可行。
更新1
将lpDesktop设置为空字符串时,约50%的情况能正常运行,说明问题与WindowStation和Desktop相关,但无法理解为何运行不稳定,且创建权限正确的自定义WindowStation/Desktop无效。
更新2
相关代码片段:
internal static SafeTokenHandle GetProcessAccessToken(int processId) { var process = Process.GetProcessById(processId); if (OpenProcessToken(process.Handle, TOKEN_DUPLICATE, out IntPtr tokenHandle)) return new SafeTokenHandle(tokenHandle); else throw new Win32Exception(); } internal static SafeTokenHandle DuplicateAccessToken(SafeTokenHandle token) { var success = DuplicateTokenEx(token, TOKEN_ALL_ACCESS, null, IMPERSONATION_LEVEL_SecurityIdentification, TOKEN_TYPE_TokenPrimary, out IntPtr newToken); return success ? new SafeTokenHandle(newToken) : throw new Win32Exception(); } private bool Start() { using (var processToken = GetProcessAccessToken(StartInfo.ProcessIdToImpersonateUserContext)) { using (var newToken = DuplicateAccessToken(processToken)) { var si = new STARTUPINFO(); var pi = new PROCESS_INFORMATION(); var safeProcessHandle = new SafeProcessHandle(); var safeThreadHandle = new SafeThreadHandle(); SafeFileHandle redirectedStandardOutputParentHandle = null; try { var profileInfo = new PROFILEINFO(); profileInfo.dwSize = Marshal.SizeOf(profileInfo); profileInfo.lpUserName = "LimitedUser"; var succeeded = LoadUserProfile(newToken, ref profileInfo); if (!succeeded) throw new Win32Exception(); var cmdLine = $"\"{StartInfo.FileName}\" {StartInfo.Arguments}".Trim(); if (StartInfo.RedirectStandardOutput) { CreatePipe(out redirectedStandardOutputParentHandle, out si.hStdOutput); si.dwFlags = STARTF_USESTDHANDLES; } int creationFlags = 0; if (StartInfo.CreateNoWindow) creationFlags |= CREATE_NO_WINDOW; creationFlags |= CREATE_UNICODE_ENVIRONMENT; int logonFlags = 0; if (StartInfo.LoadUserProfile) logonFlags |= (int)LogonFlags.LOGON_WITH_PROFILE; string workingDirectory = StartInfo.WorkingDirectory; if (string.IsNullOrEmpty(workingDirectory)) workingDirectory = Environment.CurrentDirectory; var envBlock = GetEnvironmentBlock(newToken); succeeded = CreateProcessAsUserW(newToken, null, cmdLine, null, null, true, creationFlags, new HandleRef(null, envBlock.DangerousGetHandle()), workingDirectory, si, pi); if (!succeeded) throw new Win32Exception(); if (pi.hProcess != (IntPtr)0 && pi.hProcess != INVALID_HANDLE_VALUE) safeProcessHandle.InitialSetHandle(pi.hProcess); if (pi.hThread != (IntPtr)0 && pi.hThread != INVALID_HANDLE_VALUE) safeThreadHandle.InitialSetHandle(pi.hThread); DestroyEnvironmentBlock(envBlock.DangerousGetHandle()); } finally { si.Dispose(); } if (StartInfo.RedirectStandardOutput) { var enc = StartInfo.StandardOutputEncoding ?? Console.OutputEncoding; StandardOutput = new StreamReader(new FileStream(redirectedStandardOutputParentHandle, FileAccess.Read, 4096, false), enc, true, 4096); } _processHandle = safeProcessHandle; safeThreadHandle.Dispose(); return true; } } }
内容的提问来源于stack exchange,提问作者roli09
相关产品推荐
相关产品推荐

