fix(sandbox): harden the per-session record and the ACL runner failure paths (review round v6)

Durable record: bound to the owning session id and validated at the fold (orphan-SID shape, temp path inside the host temp root) — a fork's copied parent record no longer provisions the child, and a tampered record fails loud. Private temp dir: random unguessable name persisted in the record, created exclusively (pre-existing entries and reparse points fail EEXIST). Persistence: a fresh provision kicks an immediate flush (no write-behind debounce), narrowing the crash window to the flush latency — documented as the one self-healing gap. Runner-failure rules: exit-gated on 127 so a confined command that prints the signature on a non-127 exit is never misclassified. Spawn: AssignProcessToJobObject failure terminates the suspended child (no hanging orphans). SandboxExecutionPolicy.sessionId is the branded SessionId. Boundary docs: qualifying clause on the absolutist sentences, NULL-DACL Known Limitation, 'full' scoped to the supported NTFS surface, CLM gate comment.
This commit is contained in:
Huanqi Cao
2026-08-08 23:23:38 +08:00
parent 441927c526
commit 6478da61e3
27 changed files with 472 additions and 278 deletions
@@ -5,8 +5,14 @@
* token whose restricting SIDs include an orphan SID (`S-1-4-x-y`) that only
* this sandbox instance adds to the target directories' DACLs — the
* intersection check then allows writes exactly where that SID has a Write
* ACE, and nowhere else. Unlike the POC, every API failure throws with the
* API name and exact Win32 code; a child is NEVER spawned unrestricted.
* ACE, and nowhere else the orphan SID is concerned (the token's write check
* ALSO inherits the ambient write ACEs of the other restricting SIDs — the
* keep-alive group logon SID + Everyone; Authenticated Users,
* INTERACTIVE, and LOCAL are absent from both lists — see the seam's
* dual-list contract in `packages/sandbox/sandbox-local` and the package
* README's Modes section for the complete boundary). Unlike the POC, every
* API failure throws with the API name and exact Win32 code; a child is
* NEVER spawned unrestricted.
*
* Known boundaries (inherent to restricted tokens, not this port):
* - writes are restricted; reads, network, and process visibility are NOT