Replies: 3 comments
|
Thanks — this is the third report of Why nothing in the pipeline acts on it. The code is never treated as a runner failure. One correction to the report's causal note. The mechanism your report measures. The restricted token is derived from the current process's token ( Plugin-form stopgap. Thanks for the matrix — it is what made the second shape visible. |
|
Follow-up on the same class, and the piece of your report I had not acted on: 0.7.0 named the two measured shapes of the desktop host (your report's contribution to the family) but still sent an Electron reader to
The advisory now says: host the runner on a real Two more things from your report are in the text now, because they are the parts a session reader would get wrong without them:
It is still a stopgap. It names the situation to a session that is stuck; it does not change Thanks — the host matrix in your report is what made the second shape visible, and the remedy ordering came from your "Suggested fix" section, not from us. |
Confirming this on 0.2.0-rc.2, plus one result that differs from row 3 of your table — this time measured in a real Desktop session, not just a standalone harness. Environment: DSH Desktop 1. The root cause you identified is still present in 0.2.0-rc.2
const builtEntry = this.internals.windowsAclRunnerEntry
?? fileURLToPath(import.meta.resolve("@deepseek-ai/dsh-sandbox-windows-acl/runner"));
if (existsSync(builtEntry)) return [process.execPath, builtEntry];So your suggested fix has not landed in the newest release. Your supporting claim also holds — 0.2.0-rc.2 ships exactly the interpreter you propose using: 2. Row 3 of your matrix does not reproduce:
|
| Observation | Result |
|---|---|
Foreground pwsh tool call |
✅ exit 0, normal output |
Background pwsh job |
✅ exit 0 |
| Token integrity of the confined shell | Low Mandatory Level (S-1-16-4096) — the confinement is real, not an unconfined run |
| Writing a file into the workspace | ❌ DENIED, file not created |
| Reading files | ✅ |
Child process (cmd /c echo) |
✅ |
python.exe / node.exe from the bundled runtime |
✅ 3.12.14 / v24.21.0 |
workspace-write on the same host still dies with 0xC0000142 for every target, foreground and background.
This agrees with #8062, which reports for an Electron parent: "workspace-write 必死 3221225794,read-only 正常". So two independent machines measure read-only working under an Electron host, and only row 3 of your table reports it failing.
Why I think this matters for the fix rather than just for the table. If the Electron host alone were fatal, read-only would have to die too — it derives its restricted token from the same Electron process token through the same openCurrentProcessToken path. It does not. That points at the combination rather than the host:
(Electron-hosted runner) × (write-restricted token carrying capability SIDs) is fatal; neither factor alone is.
Concretely, that is consistent with the two things workspace-write adds on top of read-only:
- the workspace/temp capability SIDs join the restricting list, and
createRestrictedToken()returns attypes-Cl_DXjhk.js:897— they never enter the token's normal SID list (:852-853,:884-893, Flags13 = … | WRITE_RESTRICTED); - the token default DACL gets a merged
FILE_ALL_ACCESSACE naming the write SID, where read-only namesEveryone(:786-796,:801-823).
I am not claiming that fully explains the mechanism — only that "the host image is the discriminator" cannot be the whole story while read-only survives under the same host. If you want a single discriminating run: keep the Electron host, use workspace-write, and drop the write SIDs from the restricting list (or name Everyone in the default DACL instead of the write SID).
Note also that the real argv differs by two variables at once, which is worth holding constant in any comparison: read-only is invoked without --write-sid/--temp-write-sid (standalone, manageDacls: true, --temp tmpdir()), while workspace-write carries the pair (seam, manageDacls: false). I tested standalone workspace-write as well — it fails identically, so the seam split is not the variable.
3. Controls that may save you a re-run (all on rc.2, Electron host)
- Target executable is irrelevant — Store/MSIX
pwsh, Windows PowerShell 5.1,cmd.exeandnode.exeall die the same way. - Path and ambient ACL state are irrelevant — clean directories outside
%TEMP%, a brand-new workspace (bypassing the standing-ACE reuse cache), and a%TEMP%tree already littered with inherited ACEs from another sandbox product all gave identical results. - A broken
TMP/TEMPis not sufficient —read-onlywithTMP/TEMPpointed at a non-existent path still spawned successfully, so theTMP/TEMPrewrite inrunner.js:153-156is not what kills the load. - Do not tune the
CREATE_NO_WINDOWboundary — as you noted, the restricted-token path spawns withCREATE_SUSPENDEDalone; I independently read the installeddsh-win32-processand confirm it passescreationFlags = 4for the inherited-stdio path and0for the piped path, both modes alike.
4. Side observation: confined sessions land in ConstrainedLanguage
In the confined session, $ExecutionContext.SessionState.LanguageMode is ConstrainedLanguage — .GetType(), .NET static calls and similar are refused ("此语言模式仅支持核心类型"). This matches #8219. It is not the 0xC0000142 bug, but it does mean shell snippets written for an unconfined session can fail in confined ones, and it may deserve its own note.
5. Agreed on the diagnosis gap
Your "surface the failure" point is what makes this expensive in practice. Confirming the shape from rc.2: dsh-pwsh-sandbox/lib/index.js:68-81 classifies a runner failure only from non-zero exit + a matching stderr line, and the windows-acl rules admit only exit 127 with the windows-acl-run: signature. Here the runner succeeds and the child dies at load with empty stderr, so nothing matches and the raw code is all the user sees. Treating 0xC0000142 / 0xE0434352 as confinement-induced child death even with empty stderr would turn this class from silent into self-explaining.
6. Practical note for the other reports in this family
Until the host is changed, read-only is a working confined mode on Windows Desktop — the shell runs at Low integrity with writes denied, and the bundled Python/Node toolchains still work. That is a better default answer for the ~64 threads in this family than "escalate to danger-full-access", which silently removes the sandbox. The obvious tradeoff is that it cannot write to the workspace, so it is only a fit for read-and-inspect work.
Thanks for the host matrix — it is what made the second shape visible, and it is why we did not file a 65th report.
Uh oh!
There was an error while loading. Please reload this page.
Summary
On DSH Desktop (Windows),
@deepseek-ai/dsh-sandbox-windows-aclcannot start any child process. The confined spawn dies withSTATUS_DLL_INIT_FAILED(0xC0000142) before any user code runs.The distinguishing variable is the executable hosting the ACL runner, not the token construction, not the ACLs, and not the target program:
node.exepwsh.exenode.execmd.exeDeepSeek Harness.exe,ELECTRON_RUN_AS_NODE=1)pwsh.exe0xC0000142cmd.exe0xC0000142cmd.exe— read-only mode, no ACL grants at all0xC0000142node.exepwsh.exe/cmd.exeWeb is unaffected because its host is a real
node.exe; Desktop is affected because its host is the Electron executable.This is a separate root cause from two adjacent reports, both of which I read carefully before filing (see Relation to existing reports).
Environment
10.0.262000.2.0-rc.1(resources/runtime/primary-runtime/runtime.json), Electron44.0.0@deepseek-ai/dsh/@deepseek-ai/dsh-sandbox-windows-acl0.1.7-rc.1~/.dsh/profiles/desktop), session file policyworkspace-write7.6.6(C:\Program Files\PowerShell\7\pwsh.exe)resources/runtime/primary-runtime/dependencies/node/bin/node.exe(v24.21.0)v24.15.0Symptom
Any shell tool call in a confined session returns immediately with no output:
3221225794=0xC0000142=STATUS_DLL_INIT_FAILED.pwsh,cmd, andnodeall fail identically. File tools (read/write/glob/grep) are unaffected, since they do not go through the process sandbox.Session log confirms the policy was confined and no error detail was surfaced:
{"type":"sandbox/mode","seq":1,"data":{"mode":"workspace-write"}}{"type":"tool/result","data":{"message":{"role":"tool", "content":[{"type":"text","text":"(no output)\n[exit code: 3221225794]"}], "isError":false}}}Failing code path
packages/sandbox/sandbox-local/src/index.ts—windowsAclRunnerInvocation():process.execPathis the Electron binary in Desktop. The sameprocess.execPathpattern appears inpackages/subprocess/subprocess-local/src/runner-launch.ts.Desktop's launcher shim makes this structural —
apps/desktop/scripts/node-bin/node.cmd:So every "node" the harness needs is the Electron executable in Node mode.
Process tree: the failure is in the SECOND runner
Live process monitoring (30 ms polling of
Win32_Process) on Desktop shows two distinct spawn chains:The same monitoring captured the Desktop host successfully launching
git.EXEandrg.exethrough the first-layer runner. So the first runner works under an Electron host; only the second one fails — i.e. the breakage is specifically in deriving aWRITE_RESTRICTED+ Low-integrity token from an Electron process token and spawning under it.Reproduction (does not need the Desktop UI)
Invoke the ACL runner directly over the seam's argv contract, varying only the host executable.
$writeSid/$tempSidmust be derived with the package's own algorithm (sha256, 30-bit subauthorities; temp sid carries a trailing-1).Between (A) and (B) nothing else changes: same workspace, same temp dir, same mode, same two SIDs, same target, same runner file (identical
sha256in both installed copies).Control: the Electron executable spawns
cmd /c vercorrectly when it does not go throughAclSandbox(spawnSyncreturnsstatus 0with normal output) — so the Electron process itself can create children; it is the combination with the restricted token that fails.What was ruled out
NOT_THIS_CLASS,packageAllowSidsempty,writeDac/writeOwnerboth availableC:\Windows\Temp(this host has 14 of them, injected by a different sandbox product's capability-SID registry, keyed per workspace path)icaclsshows the interactive user andEveryonestill at full control on the temp treepwshstill exited 41, i.e. succeeded)Low Mandatory Level:(OI)(CI)(NW); but read-only mode (which performs no label or grant work) fails under an Electron host toodsh-sandbox-windows-acl@0.1.7-rc.1;runner.jsis 7807 bytes with identicalsha256B58ACCC8…in bothpwshresolutionpwsh.exeon PATH (C:\Program Files\PowerShell\7\pwsh.exe), no shimTokenIsAppContainer= false); and the unconfined Electron spawn control above succeedsRelation to existing reports
I read both before filing; this looks like a third, distinct cause.
#8170 (
Windows ACL sandbox: native children with piped stdio silently never run; 0xC0000142 hard-error dialog,webprofile) attributes the0xC0000142part to the documented boundary:My measurements refine that boundary: it is not
CREATE_NO_WINDOWby itself.dsh-win32-processalready spawns withcreationFlags = 0x404(CREATE_SUSPENDED | CREATE_NO_WINDOW), and with a real-node host that path succeeds for bothpwsh.exeandcmd.exe. The same flags under an Electron host fail. So the flag is a necessary-but-insufficient ingredient; the host process token is the discriminator. #8170's reported case may well be the same mechanism if a non-node executable hosted the runner there — worth checking, since that author still has the exit-code watcher armed.#8174 (
Desktop leaks ELECTRON_RUN_AS_NODE into every child process) is the same underlying subsystem but a different failure. It correctly describesELECTRON_RUN_AS_NODEbeing inherited as a selector. Here the Electron binary is not merely inherited configuration — it is the process image that hosts the ACL runner and whose token the restricted token is derived from, so the[process.execPath, builtEntry]line is the direct cause.ELECTRON_RUN_AS_NODEin the shared child environment, the Desktop ACL runner (an Electron binary) may stop being able to executerunner.jsat all. Whatever fixes #8174 should land together with, or before, this one.Suggested fix
Prefer a real node executable over
process.execPathfor the sandbox runner (and thesubprocess-localWindows runner). Desktop already ships exactly that:Verified: with that binary as host, the confined
pwsh.exe/cmd.exespawns above succeed (exit 81 / 82).Implementation options, least invasive first:
windowsAclRunnerInvocation(), use the bundled standalone node path whenprocess.versions.electron !== undefined, instead ofprocess.execPath.apps/desktop/scripts/node-bin/node.cmdpoint at the standalone node, soDSH_DESKTOP_NODE_EXECUTABLEmeans "node interpreter" again.process.execPathchoice with an Electron-host check (process.versions.electron/ELECTRON_RUN_AS_NODE) and fall back to the standalone node.Also worth fixing independently: surface the failure. Today the user/agent sees
(no output)+ a rawSTATUS_DLL_INIT_FAILEDcode, with nowindows-acl-run: <detail>line and no indication that the sandbox — not the command — failed. Every shell tool call in a Desktop confined session is affected, so the practical effect is that Windows Desktop users must escalate to full access for all shell work, which silently removes the sandbox on that platform.Please do not "fix" this with
--disable-sandbox/--disable-gpu-sandbox. Those disable Chromium's renderer sandbox, which is a different layer from the DSH file policy; they are not the root cause and weaken browser-side isolation.Scope
node.exeand is unaffected.ctx.sandbox-mediated shell execution:pwsh,cmd, and anything wrapped.Diagnostics from a single machine; the four-row host comparison is deterministic and reproducible. I have the monitoring script and raw captures available and can re-run against a specific build.
All reactions