Repository navigation
[Bug] Windows: 受限沙箱档下子进程创建必现 0xC0000142(STATUS_DLL_INIT_FAILED),danger-full-access 档正常
环境
症状
已排除的嫌疑
定位从
Workaround把会话文件策略切到 建议
复现记录:2026-10-14,Windows 11 23H2 / DeepSeek Harness 0.2.0-rc.2 / PowerShell 7.6.7 |
Replies: 3 comments 3 replies
|
老毛病了, 你在这个 repo 里搜 sandbox 或者沙箱, 你就能看到一串受害者. 我比较在意的是为什么一直没有解决 |
|
补充一个经过复现验证的真正根本原因与已验证可用的修复补丁: 1. 为什么 Web 端正常,而 Desktop 桌面端必现 0xC0000142?在
2. 稳定复现方式在普通命令行 Node 脚本中: // 先显式剥离父进程控制台,模拟 Electron GUI 进程环境
FreeConsole();
// 此时再通过 AclSandbox 以 workspace-write 模式 spawn 任何受限子进程(cmd.exe 或 pwsh.exe)
// 结果:100% 稳定复现 exitCode = 3221225794 (0xC0000142)3. 已验证有效的修复补丁(已在本地实测通过)在 let hostConsoleEnsured = false;
function ensureHostConsole() {
if (hostConsoleEnsured) return;
try {
const { kernel32, bind } = bindingContext();
const getConsoleWindow = bind(kernel32, "GetConsoleWindow", "void*", []);
if (getConsoleWindow() === null) {
const allocConsole = bind(kernel32, "AllocConsole", "int", []);
if (allocConsole() !== 0) {
const user32 = requireKoffi().load("user32.dll");
const showWindow = user32.func("__stdcall", "ShowWindow", "int", ["void*", "int"]);
const hwnd = getConsoleWindow();
if (hwnd !== null) {
showWindow(hwnd, 0); // 0 = SW_HIDE
}
}
}
hostConsoleEnsured = true;
} catch {}
}
function createRestrictedProcess(api, options, commandLine, creationFlags, startupInfo, processInfo) {
ensureHostConsole();
return api.createProcessAsUserW(options.token, null, commandLine, null, null, 1, creationFlags, null, options.cwd, startupInfo, processInfo);
}实测效果: |
|
@poeylizn 补一句操作层面的信息:这个仓库目前不接受外部 PR—— 顺着楼上 bianhongjun38 的结论,我把它落到了源码层(楼上贴的是
--- a/packages/subprocess/win32-process/src/ffi.ts 2026-10-19 15:12:01.754799094 +0800
+++ b/packages/subprocess/win32-process/src/ffi.ts 2026-10-19 15:12:06.798632000 +0800
@@ -70,6 +70,9 @@
args: null,
): number
createPipe(readHandle: NativePtr, writeHandle: NativePtr, attributes: null, size: number): number
+ getConsoleWindow(): NativePtr | null
+ allocConsole(): number
+ showWindow(window: NativePtr, command: number): number
setHandleInformation(handle: NativePtr, mask: number, flags: number): number
createProcessAsUserW(
token: NativePtr,
@@ -274,6 +277,7 @@
const koffi = requireKoffi()
const { PVOID, PPVOID, STARTUPINFOW, PROCESS_INFORMATION } = win32Types()
const { kernel32, advapi32, bind } = bindingContext()
+ const user32 = koffi.load('user32.dll')
const node = koffi.load(null)
cached = {
closeHandle: bind(kernel32, 'CloseHandle', 'int', [PVOID]),
@@ -283,6 +287,9 @@
'uint32', PVOID, 'uint32', 'uint32', PVOID, 'uint32', PVOID,
]),
createPipe: bind(kernel32, 'CreatePipe', 'int', [PPVOID, PPVOID, PVOID, 'uint32']),
+ getConsoleWindow: bind(kernel32, 'GetConsoleWindow', PVOID, []),
+ allocConsole: bind(kernel32, 'AllocConsole', 'int', []),
+ showWindow: bind(user32, 'ShowWindow', 'int', [PVOID, 'int']),
setHandleInformation: bind(kernel32, 'SetHandleInformation', 'int', [PVOID, 'uint32', 'uint32']),
createProcessAsUserW: bind(advapi32, 'CreateProcessAsUserW', 'int', [
PVOID, 'str16', 'str16', PVOID, PVOID, 'int', 'uint32', PVOID, 'str16',
--- a/packages/subprocess/win32-process/src/process.ts 2026-10-19 15:12:01.752799160 +0800
+++ b/packages/subprocess/win32-process/src/process.ts 2026-10-19 15:12:06.799631967 +0800
@@ -173,6 +173,30 @@
owned.clear()
}
+let hostConsoleEnsured = false
+
+/**
+ * Give a console-less host (Electron GUI, or a process that called
+ * FreeConsole()) one hidden console before the first restricted spawn.
+ *
+ * Without it CreateProcessAsUserW routes through conhost, where the
+ * low-integrity restricted token is refused during DLL initialization and the
+ * child dies with 0xC0000142 (STATUS_DLL_INIT_FAILED). Allocating the console
+ * once and hiding its window keeps the desktop free of a black frame.
+ * @param api - active binding table.
+ */
+function ensureHostConsole(api: Win32ProcessBindings): void {
+ if (hostConsoleEnsured) return
+ try {
+ if (api.getConsoleWindow() === null && api.allocConsole() !== 0) {
+ const window = api.getConsoleWindow()
+ if (window !== null) api.showWindow(window, 0)
+ }
+ } finally {
+ hostConsoleEnsured = true
+ }
+}
+
function createRestrictedProcess(
api: Win32ProcessBindings,
options: RestrictedProcessSpawnOptions,
@@ -181,6 +205,7 @@
startupInfo: NativePtr,
processInfo: NativePtr,
): number {
+ ensureHostConsole(api)
// The sandbox mutates its process environment before this call. Passing an
// explicit block through Koffi makes CreateProcessAsUserW reject the request
// with ERROR_INVALID_PARAMETER, so lpEnvironment remains NULL.验证方法(需要 Windows):先 说明:我这边只有 Linux 环境,没做 Windows 编译和实测;补丁基于 代码也放到了我的 fork 分支上,方便直接看 diff: |
老毛病了, 你在这个 repo 里搜 sandbox 或者沙箱, 你就能看到一串受害者. 我比较在意的是为什么一直没有解决