[Windows][Desktop] 双击启动的桌面端下所有 shell 工具以 STATUS_DLL_INIT_FAILED (0xC0000142) 失败,命令行 dsh web 宿主正常 #6822
Replies: 4 comments
|
先说结论:你的报告我逐条对照了本地 master 检出(0.1.6-alpha.1,与你运行的版本一致),三处引用全部核对无误;"双击启动的宿主不持有控制台 → 子进程新控制台分配失败"这条推断在机制上说得通,但最后一环你我都无法在宿主侧直接观测,目前只能算高概率推断。你提出的判定性实验(从带控制台的终端启动同一份桌面端 exe)确实是下一步最该做的。 证据侧我补充两点细节。其一,你引用的
而沙箱 shell 工具实际走的是受限令牌路径
其二,README.zh.md:117(控制台隔离不可用)与 :94(保活组缺失 → 0xC0000142)两段引文逐字无误;桌面端宿主在 master 上也没有任何补救: 临时规避(我自己会用这个顺序):1) 终端里 未验证部分:宿主侧控制台所有权没有直接探测手段(你也标注了);desktop 包内 如果方便,把"终端启动桌面端"的对照结果、或 Application 事件日志里 conhost/pwsh 相关的崩溃记录补上,能进一步缩小范围。 |
官方回复稿(中文版)· 直接贴到 Discussion #6822
我把这个问题查到了结论,先说一条否定结论:控制台假说在这台机器上不成立。 1. 控制台假说已被推翻我跑了 #6822 里说「无法在无头环境完成」的那个判定性实验——从带控制台的终端启动同一个 exe: 仍然失败。 2. 更强的否定:
|
| 命令 | 退出码 |
|---|---|
Write-Output test |
3221225794(0xC0000142) |
$PSVersionTable.PSVersion |
3221225794 |
cmd /c echo test |
3221225794 |
cmd.exe 是完全不同的二进制,跟 PowerShell 毫无关系,却以同样方式死掉。这把 shell 从嫌疑里彻底摘了出去,指向令牌 / 沙箱层——走这条路的每一个子进程都受影响。
3. 我发现的东西:版本错位掩盖了真正的根因
把本地源码检出和装好的 app.asar 对比后,我发现一个存在于发布二进制里、但在源码树中完全不存在的函数:
// 存在于装好的 0.2.0-rc.2;源码 token.ts 里完全没有
function restrictTokenIntegrity(api, token, lowLabelSidPtr) {
...
api.setTokenInformation(token, 25, info, info.length)
// "Lower the restricted token's integrity level to Low (S-1-16-4096) ...
// a token left at Medium would ignore them"
}TokenIntegrityLevel 在 packages/sandbox/sandbox-windows-acl/src/token.ts 里出现 0 次,在发布包里出现 1 次。本地检出是 0.1.2-alpha.4(2026-09-01),装好的构建是 0.2.0-rc.2(9 月底)——检出太旧,装不下关键的那条代码路径。
4. 这个调用在本机失败,而且没有 fail-closed
我直接复现了这一步。降低令牌完整性级别需要 SeRelabelPrivilege:
SetTokenInformation(TokenIntegrityLevel, Low) -> Win32 998 (ERROR_NOACCESS)
而本账户的情况:
| 检查项 | 结果 |
|---|---|
IsInRole(Administrator) |
True |
| 当前完整性级别 | High Mandatory Level(S-1-16-12288) |
SeDebugPrivilege |
存在 |
SeRelabelPrivilege |
该账户上完全不存在 |
所以 0.2.0-rc.2 引入了一个在默认 Windows 账户上不可能成功的令牌构造步骤——因为 SeRelabelPrivilege 默认不授予。
由此形成的因果链:
CreateRestrictedToken(..., WRITE_RESTRICTED)成功 → 令牌此时已带写限制。SetTokenInformation(TokenIntegrityLevel, Low)失败,返回ERROR_NOACCESS。- 令牌于是停在 Medium 完整性,却已经背着
WRITE_RESTRICTED。 - 强制完整性控制要求写入目标携带匹配或更低的标签;本该让二者一致的那次降级从未发生。
- 子进程在 DLL 初始化阶段死亡 →
0xC0000142;因为死在执行到命令之前,stdout/stderr 全空。
这也解释了为什么 cmd.exe 和 pwsh 一样受害——它走的是同一条受限路径,不是 shell 的问题。
5. 判定性实验:权限策略往返切换
同一会话内,不重启 DSH、不改任何配置:
| 顺序 | 策略 | 命令 | 结果 |
|---|---|---|---|
| 1 | workspace-write |
Write-Output test |
❌ 0xC0000142,零输出 |
| 2 | danger-full-access |
Write-Output test |
✅ 打印出 test |
| 3 | 切回 workspace-write |
Write-Output test |
❌ 0xC0000142,零输出 |
唯一的变量是文件沙箱策略:workspace-write 下每次必挂,danger-full-access 下每次必过,完全可复现。
这一条同时排除三类替代解释:
| 替代解释 | 为何被排除 |
|---|---|
| 「是不是排查过程把 DSH 弄坏了」 | 切回 workspace-write 后复现完全相同的失败 |
| 「是不是要重启才能恢复」 | 三轮之间从未重启 |
| 「是不是会话状态变脏了」 | 切换后立刻复现,无累积效应 |
一个强化判断的旁证:danger-full-access 那轮 harness 成功写出了 run.log(+4 行),而两轮 workspace-write 连日志都没写出来——故障发生在 CreateProcessAsUserW 调用处,还没跑到任何能写日志的代码。故障点极早。
6. 关键矛盾:同文件里的邻居调用是 fail-closed 的
if (api.setTokenInformation(token, abi.TokenDefaultDacl, info, info.length) === 0) {
throwWin32(api, 'SetTokenInformation', win32Code, 'TokenDefaultDacl')
}而 restrictTokenIntegrity()——它自己的文档注释声称 "fails closed before any child is spawned"(在任何子进程被创建前就 fail-closed)——在本机并没有拦住那次 spawn。这个自相矛盾之处,看起来就是真正的缺陷所在。
7. 请求
- 请确认
restrictTokenIntegrity()的失败路径是否真的 fail-closed。 实际观察到的行为是:一个带着WRITE_RESTRICTED却没有配套完整性降级的令牌,仍被传给了CreateProcessAsUserW。 - 改善可诊断性。 目前这个失败表现为完全静默——无 stdout、无 stderr、无
Win32Error、无 runner 侧诊断文本。完整性降级失败应当被识别为沙箱基础设施故障,与普通命令失败明确区分。 - 考虑一条不依赖 relabel 的路径。 任何依赖
SeRelabelPrivilege的设计,在原版 Windows 桌面账户上都不成立。让用户改用danger-full-access确实能绕过,但那等于把沙箱整个关掉了。 - 环境差异说明:本机为 Windows 10 Pro 19045(本报告)vs Windows 11 26100([Windows][Desktop] 双击启动的桌面端下所有 shell 工具以 STATUS_DLL_INIT_FAILED (0xC0000142) 失败,命令行 dsh web 宿主正常 #6822);DSH 0.2.0-rc.2 vs 0.1.6-alpha.1。该缺陷在两个 Windows 版本、两个 DSH 版本上似乎都存在。
ERROR_NOACCESS 是用一个独立探针复现文档所述调用序列测得的,并非通过插桩 DSH 自身的执行取得——因此我无法排除 DSH 内部走了另一条错误处理路径。确认这一点需要在那个失败分支加一行日志。以上其余内容均为本机直接观察所得。
如果需要,我可以提供探针源码和完整诊断报告。
|
独立复现 + 两个可直接测量的事实(补充 PerryLink 与 HXYUE2020 的分析) 环境:Windows 10 22H2(19045.6216)、官方桌面版 0.2.0-rc.2、内置 Administrator(SID …-500)、High 完整性级别、PowerShell 7.6.6(与 5.1 同样复现)。 1. 判定性实验:固定其它一切,只换承载 runner 的宿主同一台机器、同一个官方 runner(
→ 可观测差异不止“双击 vs 终端”:宿主二进制本身就是一个可独立证伪的变量。 2. 宿主控制台所有权的直接测量(PerryLink 标注为“没有直接探测手段”的那一环)从同一个带控制台的父进程、同样的 stdio(
顺带说明一点逻辑问题:“从带控制台的终端启动桌面端 exe 仍然失败”不能反驳控制台假说——Windows 上 GUI 子系统进程不会因为父进程持有控制台就附着上去,实测它从带控制台的父进程启动后依然 3. 与 HXYUE2020 的
|
Uh oh!
There was an error while loading. Please reload this page.
[Windows][Desktop] 双击启动的桌面端下所有 shell 工具以 STATUS_DLL_INIT_FAILED (0xC0000142) 失败,命令行
dsh web宿主正常环境
Microsoft Windows NT 10.0.26100.0;注册表DisplayVersion=24H2、CurrentBuild=26100.9168、EditionID=Professional、ProductName=Windows 10 Pro(24H2/26100 上该键值仍报 Windows 10,属已知表现)AMD640.1.6-alpha.124.17.0,win32/x64($DSH_HOME/profiles/desktop/desktop-runtime-state.json)workspace-write(实测于命令行宿主)Administrator,非提升(IsInRole(Administrator) = False)C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe(5.1.26100.9168,PSEdition=Desktop);Get-Command pwsh -All无结果,未安装 PowerShell 7复现步骤
实验组(失败):
pwsh工具调用。最简命令1即可复现。对照组(成功):
pnpm dsh web,在浏览器中打开 Web UI,使用同一工作区。pwsh调用。实际结果
dsh web宿主3221225794(0xC0000142)0DENIED :: UnauthorizedAccessExceptionALLOWEDFullLanguagewhoami.exeAccess is denied关键点:命令行宿主下 ACL 沙箱仍在正常强制执行——工作区外写入被拒、工作区内写入通过、受限令牌在场(
whoami.exe被拒正是文档记录的受限令牌现象)。因此这不是"沙箱坏了"或"沙箱未生效",而是宿主环境差异。预期结果
两种宿主下 shell 工具都应正常工作,且沙箱边界一致。
根因分析
代码事实(已核实)
1. 进程创建不携带任何控制台 flag
packages/subprocess/win32-process/src/process.ts:563:即没有
CREATE_NO_WINDOW、没有CREATE_NEW_CONSOLE、也没有DETACHED_PROCESS。对packages/subprocess/win32-process全目录grep -i console零命中。2. 文档把"共享宿主控制台"当作对策,并记录了该错误码
packages/sandbox/sandbox-windows-acl/README.zh.md:117("已验证边界"):3. 同一错误码的另一条已知成因
packages/sandbox/sandbox-windows-acl/README.zh.md:94:保活组(登录 SID + Everyone)缺失时"早期 DLL 初始化会以0xC0000142死亡"。4. shell 解析在本机落到最后一个候选
packages/shell/pwsh-local/src/resolve.ts:21-37的解析顺序为%ProgramFiles%\PowerShell\7\pwsh.exe→ PATH 中的pwsh.exe→%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe。本机上前两个候选均不存在(已逐路径核实:C:\Program Files\PowerShell、C:\Program Files (x86)\*PowerShell*、D:\Program Files\PowerShell、Store 别名...\WindowsApps\pwsh*、scoop、chocolatey 均不存在),因此实际执行的是 Windows PowerShell 5.1。推断(环境前提已确认,宿主侧仍无法直接测得)
文档第 117 条把"子进程共享宿主控制台"作为既定对策,但该对策隐含要求宿主自身持有控制台。
本缺陷的宿主是双击启动的 Electron GUI 进程(由 Explorer 拉起),在 Windows 上不持有控制台。因此不带控制台 flag 的
CreateProcessW会让 console 子进程转为分配一个新控制台,而这一步在WRITE_RESTRICTED受限令牌下失败,表现为子进程在 DLL 初始化阶段死亡——与观测到的空输出、0xC0000142、且没有 runner 侧windows-acl-run:诊断(该诊断会伴随退出码 127)完全一致。两次运行可观测到的差异是宿主进程及其启动方式(双击 Electron GUI vs 终端 node CLI)。文件策略的差异不会影响这一阶段:
read-only下 pwsh 同样能够启动,只是语言模式降为ConstrainedLanguage,不会产生进程初始化失败。残留不确定性:桌面端宿主下没有任何可用执行通道可以探测控制台所有权,因此推断的最后一环("新控制台分配失败")未能直接测得。请维护者协助确认
ProcessCreation路径在宿主无控制台时的预期行为,并考虑文档第 117 条是否需要补充"宿主必须持有控制台"这一前提。已排除的假设
PSVersion=5.1.26100.9168windows-acl-run: <detail>stderr 文本,退出码也不是 127D:\Program Files\...下曾被列为次要嫌疑,但命令行宿主下同一工作区写入正常,故排除影响
双击启动的 Windows 桌面端下所有 shell 工具不可用(
bash走同一条沙箱路径)。这是阻断性缺陷:桌面端用户可以对话,但无法执行任何命令,因此桌面端在 Windows 上实际不可用。建议的验证与修复方向
packages/sandbox/sandbox-windows-acl/README.zh.md第 117 条的对策中补充"宿主必须持有控制台"这一前提;若桌面端确实无法保证,则该后端在桌面端宿主下需要一条显式的降级或探测路径(而非静默产生无法诊断的空输出失败)。STATUS_DLL_INIT_FAILED死亡"识别为沙箱基础设施故障并上报,与普通命令失败区分开。node-pty与 ConPTY 的OpenConsole.exe(resources/app.asar.unpacked/dsh/node_modules/node-pty/...),是否可作为伪控制台来源值得评估——仅为方向,未验证。附:诊断命令
在 DSH 之外的普通 PowerShell 窗口中执行,用于补充环境信息:
取证说明:本报告的环境数据(含双击启动方式)、沙箱边界探测与命令行为均为实测;代码与文档引用来自仓库
0.1.6-alpha.1的本地检出。根因部分中"宿主无控制台导致新控制台分配失败"为机制推断,其环境前提(双击启动、宿主为 Electron GUI)已确认,但最后一环未能在宿主侧直接测得,已在文中明确标注,未作为既定结论陈述。All reactions