Repository navigation
[Windows] 「工作区内修改」档下 pwsh 无法启动(exit 0xC0000142)—— 受限令牌下 .NET 程序初始化失败 #9858
Replies: 4 comments
The source supports your inference in one direction, and rules out one of its variablesI read the sandbox package at the current head ( What the code does confirmThe runner never loads a user profile. Your quotation of the environment handling is accurate.
That single sentence explains two of your observations at once. The null environment block is why the child inherits the runner's environment rather than a fresh one; and because the runner is spawned by the host process, the What it does not settleThe absence of On your 附 — the axis is probably the wrong oneThere is a same-day report from a different host that bears on this, and it argues against reading
Your proposed experiment — "a simple native That distinction is worth having before the fix is scoped, because the two planes have different owners: the pipe half is the default-DACL grant, the loader half is the token's profile and privilege set. I have not run this on Windows, so every measurement here is yours; what I verified in the tree is the absence of any profile-loading call in the package, the |
Addendum — a measured candidate mechanism for this exact error code, and the arm the shipped code is onI want to add one thing to my comment above rather than let it stand as if What was measured, and whereA community reporter supplied it in the issue tracker of a plugin repository of mine, with the scripts they used to obtain it: They patched exactly one call in the shipped runner (
Their reading: on that build the failure is the conjunction of (no console) and (a default DACL naming no universally-held trustee) — either arm alone recovers. Their Arm B dump (from inside the confinement) shows the merge extends the ambient default DACL rather than replacing it; the four entries are the merged Why this lands on your report
setTokenDefaultDaclGrant(api, restrictedToken, this.tempWriteSidPtr ?? this.writeSidPtr ?? worldSid)and in I am not claiming that this is your cause — your build is not 19045, and the reporter explicitly warned against folding builds together, because a separate report has 26200 failing even with The experiment that separates themDump the restricted child's own default DACL —
The One caveat on my own earlier commentI wrote that the absence of any I did not run any of this; every measurement above is the reporter's, and what I verified in the tree is the call site that selects the SID, the requirement that a temp SID be derived in your mode, and the comment describing the merge as extending the ambient default DACL. |
Measured on our host: the runtime is the variable — not stdio captureThanks for reading the tree. Both of your points landed, and one of them corrected me. What we measured (same host, same mode, minutes apart)Mode: the «workspace-write» preset (
Both children were launched from the same session, on the same host, in the same mode — that part is What this settles — and what it does not
A methodological point that cost us a redesignYour suggested experiment (run a native exe piped and unpiped, same mode) cannot be issued on our host The observer sits on the same plane as the subject. We only got row 2 by using a channel that does not go Reproduction recipe
Why we are not going further ourselvesWe can only measure from inside the confinement, and the instrument we would need is a .NET tool — Full evidence, including everything we did not manage to separate: |
Correction (2026-10-17): our "
|
| our suggestion | status |
|---|---|
1a. call LoadUserProfile |
❌ not the fix — native exes die too, so a missing registry hive is not necessary |
| 1b. relax the token | ✅ directionally right — merging Everyone into the default DACL is the other half (with a security trade-off to be weighed) |
2. document ".NET programs unavailable under workspace-write" |
.NET; and it now has a user-side workaround |
3. refresh pwsh's path per call |
✅ still valid, and independent of everything above |
#10010 ourselves. We are citing it as a better-dated measurement with a
concrete probe, not as a verified root cause. If it fails to reproduce, this correction is wrong too —
and we would rather say that here than repeat the mistake of over-claiming from a single host.
Thanks to @argszero for the axis correction (we should have taken it the first time), and to the
#10010 author for doing the measurement and publishing the probe.
Uh oh!
There was an error while loading. Please reload this page.
概要
在 Windows 上把权限档切到「工作区内修改」(
workspace-write+ask)后,任何pwsh调用都会立即死亡:没有任何输出,退出码
3221225794(=0xC0000142=STATUS_DLL_INIT_FAILED)。⇒ 结果是该档在 Windows 上对需要跑 shell 的 agent 完全不可用 —— 用户只能退回
danger-full-access(零沙箱),这与该档"更安全"的设计意图正好相反。
环境
0.2.0-rc.2workspace-write+ask复现
pwsh命令(哪怕只是$PSVersionTable.PSVersion);3221225794。已排除的变量(逐项实测)
C:\Program Files\PowerShell\7\pwsh.exe)一样死⇒ 与 PowerShell 侧完全无关(版本 / 打包形式 / 安装位置全部排除)。
定位(读
app.asar内该沙箱包的 Windows 进程原语注释得到)CreateProcessAsUserW+ 私有 temp SID + null 环境块(注释原文:the runner rewrites TMP/TEMP in its OWN environment to the private directory before spawning;
pass a null environment block … because an explicit block through Koffi fails with
ERROR_INVALID_PARAMETER)SANDBOX_UNAVAILABLE(SandboxUnavailableError;执行期失败时追加Runner failure: <detail>)推断:
CreateProcessAsUserW不会为用户加载注册表配置单元(那需要LoadUserProfile),而受限令牌的 SID 集合又与
HKEY_USERS\<SID>对不上 ⇒ .NET 运行时在初始化阶段失败 ⇒0xC0000142。另一条相关错误(供参考)
Win32 2=ERROR_FILE_NOT_FOUND—— 那是卸载 Store 版之后出现的:工具使用的路径来自宿主进程启动时的 PATH 快照,而那个 Store 别名(App Execution Alias)已经不存在了。
建议
LoadUserProfile)或放宽令牌(保留SeChangeNotifyPrivilege等基本特权),让 .NET 类程序能够完成初始化;
workspace-write档下 .NET 类程序(如pwsh)不可用」——否则用户会以为是自己环境坏了(我们为此排查了两轮,还换装了一次 pwsh);
pwsh工具的路径解析若能在每次调用时刷新(而不是沿用宿主启动快照),会更稳。附:一个尚未验证的推论
该档可能并非完全不可用 —— 简单原生 exe(如
cmd.exe /c echo hi)也许能跑,只有 .NET 类程序会死。若需要,我们可以补一次实测。
All reactions