Commit Graph

6 Commits

Author SHA1 Message Date
Tianyi Cui 9a3c89d04a fix(sandbox): report Windows ACL limits 2026-08-10 15:41:37 +08:00
Huanqi Cao 5fea4b7c4b feat(sandbox): derive the windows-acl write SID per workspace, not per session
The per-session random write SID forced a full tree propagation per
session per server lifetime (minutes on large workspaces). The write
SID is now the per-workspace identity derived from the canonical
workspace path (workspaceWriteSid: sha256 -> S-1-4-x-y), stored
nowhere: the workspace-root ACE materializes once per workspace per
machine and every later provision hits the exact-ACE skip.

- workspace ACEs are STANDING (never revoked - the reuse cache); temp
  ACEs stay revocable (disposed with the provider), so an inheritable
  ACE never outlives its session's temp dir on the ambient temp root
- AclSandbox requires the write SID under workspace-write; read-only
  parses/grants nothing; the runner derives the SID itself (the
  --write-sid flag's presence still marks the seam-managed contract)
- the acl-session record drops writeSid (sessionId/workspace/tempDir
  remain): the SID-tamper surface and its validation are gone
- sandbox-local holds two grant maps: standing workspace grants and
  revocable per-session temp grants

Docs (README pair, design note pair, catalogs, type-equiv) and the
acl-session/grant/acl/probe/runner suites updated; workspace-sid.spec
pins the derivation contract.
2026-08-09 10:44:35 +08:00
Huanqi Cao 441927c526 fix(sandbox): drop Authenticated Users from both restricting lists — close the C:\\-root escape, CIM unavailable in every confined mode
workspace-write now runs [logon SID, Everyone, orphan]: the two lists differ only by the orphan, and the keep-alive group (logon SID + Everyone) is the single shared invariant. The WMI namespace security check fails in BOTH modes (0x80041003), so CIM/Get-ComputerInfo are unavailable everywhere — the price of closing the C:\\-root tree-creation escape (AU:(AD) + AU:(OI)(CI)(IO)(M)) in workspace-write too. The unused WinLocalSid/WinInteractiveSid/WinAuthenticatedUserSid constants and their ABI-probe prints are removed; the enforcement 'full' claim now stands on a closed NTFS surface. New regression: a C:\\Users\\Public subdirectory write is denied under BOTH modes (the ambient-writable blind spot the review flagged — INTERACTIVE is absent from both lists). FAT-class (non-ACL) targets outside the granted roots remain writable (no security descriptors to intersect) — documented as a legacy residue, warn-only, not engineered around. Docs/design note/PR body updated in both languages (list I/J terminology gone everywhere).
2026-08-08 21:55:02 +08:00
Huanqi Cao abfb933620 feat(sandbox): per-session windows-acl write grant with dual-mode restricting lists and a private temp subdirectory 2026-08-08 17:29:43 +08:00
Huanqi Cao 91d3ed6c5a fix(sandbox): address the ACL backend review findings — quoting, DACL merge+lock, failure paths
quoteArg doubles end-of-string backslashes (real CommandLineToArgvW round-trip test; first-token exemption noted); grantWrite merges into the current DACL instead of replacing it, and both grant/revoke hold a LockFileEx per-path lock under GetTempPathW/dsh-acl-locks (koffi crashes on NULL lpOverlapped — a zeroed OVERLAPPED is used); GRANT_MASK gains DELETE|FILE_DELETE_CHILD (never WRITE_DAC/WRITE_OWNER) though the win32 26200 second check only constrains the WRITE bit; failure paths close all handles (CreateProcessAsUserW pipe set, ResumeThread thread/process/job) with stub-api tests; getTempPathW refuses undersized buffers; drainPipe backs off; runner.spec pwshAvailable uses the resolvePwshPath probe; NTSTATUS exit codes mirror bit-exact (verified end-to-end); WinLocalSid JSDoc re-attributed to WinLocalLogonSid. All gates green: 42 passed/2 skipped, typecheck, oxlint, 0 clones, constraints, knip.
2026-08-08 14:32:01 +08:00
Huanqi Cao f64ba40f43 feat(sandbox): Windows ACL write-restriction sandbox (restricted-token runner)
Confine Windows command execution through a WRITE_RESTRICTED token whose restricting SIDs carry an orphan-SID write allowlist, ported from https://github.com/huoyaoyuan/windows-acl-restrict-poc (@ 10e4dfb). Every Win32 call is checked and fails closed - the POC silently ran children with the FULL token when CreateRestrictedToken failed.

- @deepseek-ai/dsh-sandbox-windows-acl: koffi primitives verified against the MinGW Windows headers (verify/abi-probe.cpp) plus the confinement runner ([node, runner, --workspace, --temp, --mode, --, argv...]: kill-on-close job, stdio passthrough, exit-code mirroring, windows-acl-run: failure signature, grant revocation). read-only = strict zero grants (NUL device not writable; documented). Windows-only execution: exempted from the Linux coverage lane (windowsOnlyCoverageExclusions).
- @deepseek-ai/dsh-sandbox-local: PLATFORM_CHAINS.win32 filled with the windows-acl runner (full enforcement, ACL denial dialect, runner-failure rules).
- @deepseek-ai/dsh-pwsh-sandbox: sandbox-consuming pwsh executor (call-for-call mirror of dsh-bash-sandbox) over a new argv-level seam in dsh-pwsh-local; per-file coverage complete via the fake-provider spec.
- bundle/base: the Windows platform layer mounts the confined pwsh roster - sandbox/policy/fs-sandbox/permission/approval re-enabled, the POSIX bash stack stays disabled.

Co-authored-by: Huo Yaoyuan <huoyaoyuan@hotmail.com>
2026-08-08 01:24:33 +08:00