Repository navigation
【Windows 缺陷】Electron 桌面宿主无控制台,ACL 沙箱受限子进程全部以 0xC0000142 崩溃(cmd/pwsh 均然);CLI web 正常 #9238
Replies: 1 comment
|
Your root cause is correct, and it is worth saying explicitly that the two arms of it — "the restricted token may inherit a console but not create one" and "this host owns none" — are both already written down in the tree, which is what makes your matrix line up with them. The restriction is documented at both ends
Your rows 2/3/4 all supply a console from the parent side (CREATE_NO_WINDOW on the runner host, CREATE_NEW_CONSOLE, or inheriting a real one), and row 6 supplies a hidden one. That is the same distinction the source draws: the flag is fatal on the confined child, benign on the runner host. Row 1 is the Electron case exactly — nothing in the tree owns a console, so there is nothing to inherit and the child asks for one of its own. The part that is invisible from the outside: why it is silentThe reason the model retries a command that can never start is that const WINDOWS_ACL_RUNNER_FAILURE_EXIT = 127
// packages/sandbox/sandbox-local/src/index.ts:241
'windows-acl': [{ allowedExitCodes: [WINDOWS_ACL_RUNNER_FAILURE_EXIT], fatalSignatures: ['windows-acl-run: '] }],and This producer was already measured — the packaged desktop is named as its instanceThe console-less runner is not a new mechanism in this codebase's history: it was established in the two earlier reports that your matrix re-confirms, and both console-less shapes are already enumerated — a GUI-subsystem host image (which is what the packaged desktop is) and a real Existing plugin for exactly thisThis is the case Mount it by adding the patch to your profile (or applying the - insert:
- id: sandbox-grant-advisor
name: '@argszero/cordis-plugin-sandbox-grant-advisor'Your fix suggestion 4 ("when the exit code is 0xC0000142, give a human-readable cause") is what it does today, so it can serve as the interim while the host-side fix lands — and it is honest about its own limit: it explains, it does not repair. On
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
邮件标题:
【Windows 缺陷】Electron 桌面宿主无控制台,ACL 沙箱受限子进程全部以 0xC0000142 崩溃(cmd/pwsh 均然);CLI web 正常
Issue title (English):
Windows: Electron desktop host has no console, so every ACL-sandboxed child dies with 0xC0000142 (STATUS_DLL_INIT_FAILED); dsh web from a console works
一、概述(Summary)
在 Windows 桌面版(Electron)DSH 中,只要访问模式为 Workspace Write(工作区内修改,默认沙箱模式),agent 执行的任何子进程命令——包括最简单的 cmd /c echo 和 node -v——都会在进程加载阶段直接崩溃,退出码 3221225794(0xC0000142 / STATUS_DLL_INIT_FAILED),零输出;PowerShell 7 是否安装与此无关。
我们用贵方自带的沙箱源码做了对照实验,确认根因是:ACL 沙箱用受限令牌(WRITE_RESTRICTED)+ CreateProcessAsUserW 创建的子进程必须继承宿主控制台,而 Electron GUI 宿主进程树中不存在任何控制台(无 conhost),子进程在 DLL 初始化阶段死亡。同版本的 CLI web(dsh web)从真实/隐藏控制台启动时一切正常,danger-full-access(完全权限)模式也正常(因为它绕过了受限令牌)。
这不是某台机器的个例,而是桌面宿主与 Windows 沙箱实现之间的结构性兼容缺陷。下文给出源码依据、可 100% 复现/消除故障的最小实验矩阵,以及修复建议。
二、环境(Environment)
三、故障现象(Symptoms)
四、根因分析(Root cause,含贵方源码原文)
4.1 沙箱的进程创建方式
Workspace Write 模式下,真实命令不是直接执行,而是加一层 runner 前缀:
node ...@deepseek-ai\dsh-sandbox-windows-acl\lib\runner.js --workspace
--temp --mode workspace-write -- <真实命令>runner 通过 CreateRestrictedToken(含 WRITE_RESTRICTED 等限制,实测 flags=13)生成受限令牌,再以 CreateProcessAsUserW 启动真实命令,子进程继承宿主的 stdio/控制台。danger-full-access 模式则直接 super.execute(),完全不创建受限令牌。
4.2 贵方源码已明确记载该限制
@deepseek-ai/dsh-sandbox-windows-acl/lib/types-Cl_DXjhk.js 第 1171–1173 行(lib/types/index.d.ts 第 29–31 行内容相同)原文:
(CREATE_NO_WINDOW / CREATE_NEW_CONSOLE children die with
STATUS_DLL_INIT_FAILED under the restriction);
@deepseek-ai/dsh-win32-process/README.md 第 35 行原文:
Process creation sets STARTF_USESHOWWINDOW with SW_HIDE before target code runs. It preserves console inheritance and does not add CREATE_NO_WINDOW or CREATE_NEW_CONSOLE, which can fail DLL initialization under the restricted token. Existing parent console windows are not hidden.
即:受限子进程只能共享宿主已有的控制台;一旦没有控制台可继承,就会以 STATUS_DLL_INIT_FAILED 死亡。这是受限令牌的固有限制,但调用方(桌面宿主)没有满足它的前置条件。
4.3 Electron 桌面宿主恰好不提供控制台
五、最小复现与对照实验矩阵(Reproduction)
我们编写了一个约 90 行的 C# 启动器 DetachedLauncher.cs(源码见附件),仅用 Win32 CreateProcessW,可按四种控制台拓扑启动贵方官方 runner.js,由 runner 再以受限令牌执行 cmd.exe /c echo CMD_SANDBOX_OK,stdout/stderr 重定向到文件。同一台机器、同一时刻结果如下:
#1 DETACHED_PROCESS(完全无控制台,等价 Electron GUI 宿主)|经过受限令牌|退出码 3221225794 / 0xC0000142|输出为空——与桌面版故障逐字节一致
#2 CREATE_NO_WINDOW(Windows 为 runner 分配不可见控制台)|经过受限令牌|退出码 0|输出 CMD_SANDBOX_OK
#3 CREATE_NEW_CONSOLE(新建可见控制台)|经过受限令牌|退出码 0|输出 CMD_SANDBOX_OK
#4 继承已有控制台(等价 cmd 启动的 CLI web)|经过受限令牌|退出码 0|输出 CMD_SANDBOX_OK
#5 DETACHED_PROCESS,但不经过 runner/受限令牌(等价 full-access)|不受限|退出码 0|输出 FULLACCESS_OK
#6 wscript 以窗口样式 0(隐藏)启动 cmd 再跑 runner(无黑窗绕过方案)|经过受限令牌|退出码 0|输出 HIDDEN_CONSOLE_SANDBOX_OK
原始记录(每格均有文件):
detached.launcher.txt : detached child exit code: 3221225794 (0xC0000142)
detached.out.txt : (空,0 字节)
nonewconsole.launcher.txt: nonewconsole child exit code: 0 (0x00000000)
nonewconsole.out.txt : CMD_SANDBOX_OK
newconsole.launcher.txt : newconsole child exit code: 0 (0x00000000)
newconsole.out.txt : CMD_SANDBOX_OK
inherit.launcher.txt : inherit child exit code: 0 (0x00000000)
inherit.out.txt : CMD_SANDBOX_OK
fullaccess.launcher.txt : detached child exit code: 0 (0x00000000)
fullaccess.out.txt : FULLACCESS_OK
hidden-console-result.txt: HIDDEN_CONSOLE_SANDBOX_OK / runner exit=0
runner 的调用方式(第 6 组实际批处理原文):
"%NODE%" "%...%\dsh-sandbox-windows-acl\lib\runner.js" --workspace "%ROOT%\ws" --temp "%ROOT%\temp" --mode workspace-write -- C:\Windows\System32\cmd.exe /c echo HIDDEN_CONSOLE_SANDBOX_OK
一个需要澄清的细节:第 2 组外层使用 CREATE_NO_WINDOW 成功,与源码注释中“CREATE_NO_WINDOW children die”并不矛盾——注释指的是给受限子进程本身加 CREATE_NO_WINDOW/CREATE_NEW_CONSOLE 会失败;而第 2 组是给 runner 宿主加 CREATE_NO_WINDOW,Windows 会为 runner 分配一个不可见控制台,受限子进程随后继承该控制台,正好满足注释要求。这也直接指明了修复方向。
结论:故障的唯一开关是“宿主有没有控制台 + 是否套受限令牌”,与 PowerShell、PATH、工作区路径、超时、杀软均无关。
六、为什么 doctor 没有发现
dsh-win32 doctor 在真实控制台(cmd/pwsh 窗口)中运行,自身始终有控制台可继承,因此 8 项全绿,但它无法覆盖“GUI 宿主无控制台”这一拓扑。建议 doctor 增加一项:检测当前进程/进程树是否实际持有控制台(如 GetConsoleWindow()/conhost 归属),并从 GUI 宿主上下文执行一次受限子进程探针。
七、临时绕过方案(已在用户侧验证,仅供参考)
以“GUI 子系统的 wscript 隐藏启动 cmd”的方式承载 CLI web:wscript 以窗口样式 0 启动 cmd /c "npx --yes @deepseek-ai/dsh web --port 3080",Windows 会为该 cmd 分配一个隐藏控制台,沿 cmd→node 链被沙箱子进程继承。用户看不到黑窗,双击桌面图标即用,沙箱完整保留。
在 3080 网页端、Workspace Write 模式下实测 4 条命令全部退出码 0:Get-Location、node -v(v22.23.2)、cmd /c "echo SANITY_OK"(SANITY_OK)、where.exe pwsh(正确路径)。
八、修复建议(Suggested fix)
九、附带问题(P2,建议一并修正文案)
DSH 系统提示中给出的原生模块路径
D:\Program Files\deepseek harness\resources\app.asar\dsh...
是 asar 归档内的虚拟路径(app.asar 是单个文件,并非目录);物理解包目录实际为
D:\Program Files\deepseek harness\resources\app.asar.unpacked\dsh\。
该虚拟路径会误导 agent 在文件系统中查找不存在的路径,建议提示文案区分“归档内逻辑路径”与“unpacked 物理路径”。
十、附件清单(可提供)
All reactions