Commit Graph

17 Commits

Author SHA1 Message Date
Tianyi Cui a2d0f7f411 refactor: apply repository naming contract
Apply the accepted pre-release package, service, type, directory, and role renames as one repository-wide change.
2026-08-13 00:54:38 +08:00
Tianyi Cui 6f21d00169 docs(sandbox): align capability SID terminology 2026-08-10 18:08:22 +08:00
Tianyi Cui 9435ca62a6 fix(sandbox): reject overlapping Windows temp roots 2026-08-10 18:08:22 +08:00
Tianyi Cui 10ba0f8ad2 docs(windows): align sandbox ownership 2026-08-10 16:38:00 +08:00
Tianyi Cui fd650af340 fix(sandbox): isolate Windows temp capabilities 2026-08-10 16:15:59 +08:00
Tianyi Cui 9a3c89d04a fix(sandbox): report Windows ACL limits 2026-08-10 15:41:37 +08:00
Huanqi Cao 976020f2bb refactor(sandbox): derive the private temp dir; drop the acl-session record
The durable sandbox/acl-session event carried a workspace binding that
always equals the session cwd and a random temp path that only needed
to be stable per session. Both are now derived: the temp subdirectory
is sha256(session id + workspace), created exclusively and removed on
provider dispose, so fork/resume semantics fall out of the derivation
and the record, its fold/provision/tamper validation, the immediate
flush kick, and the session-store dependency all disappear.
2026-08-10 01:03:29 +08:00
Huanqi Cao 33e4c6580f feat(tool-pwsh): teach the confined named-pipe capture boundary to the model
Under read-only and workspace-write the Windows ACL sandbox leaves
programs unable to open named pipes, so a piped-stdio spawn fails with
EPERM. State that boundary in the pwsh tool description next to the
ConstrainedLanguage contract, pin it in the tool tests, and bring the
package README and both implemented Agent Notes current with it.
2026-08-09 16:34:25 +08:00
Huanqi Cao 01a3b454f6 fix(sandbox): extend the restricted token's default DACL with a write-SID ACE
New objects created without an explicit security descriptor take
their DACL from the token's default DACL, which CreateRestrictedToken
builds from the user's ambient SIDs — none of them a restricting SID.
Confined children therefore failed the write pass-2 check when
creating anonymous pipes (CreatePipe: ERROR_ACCESS_DENIED, surfaced
as Node EPERM), breaking PowerShell pipelines and other CreatePipe
consumers. Merge a full-access write-SID ACE (Everyone under
read-only) into the token default DACL at init via
SetTokenInformation(TokenDefaultDacl).

Named pipes are EXEMPT: their default security descriptor is the
kernel's PUBLIC template (owner/SYSTEM/Admins full, Everyone
read-only), which no token change influences, so libuv's piped stdio
capture stays denied for confined grandchildren — the POC-documented
boundary, now pinned by the runner suite (inherit/ignore OK, pipe
DENIED) and documented in the README pair. The NUL paragraph is
corrected to the measured matrix (Everyone has 0x1201BF on the
device: cmd/node writes land; Set-Content fails at the PS layer).
2026-08-09 12:34:48 +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 6478da61e3 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.
2026-08-08 23:23:38 +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 2dd9af6f4b fix(sandbox): keep read-only strictly zero-grant by dropping the write-allowlist SID from list I
A session that materialized its workspace-write grant and then switched to read-only (or crashed and resumed under read-only) kept a writable workspace for the server lifetime: the standing orphan-SID ACE survived the downgrade and list I still carried the orphan, so the write-restricted pass-2 check granted it. List I is now [logon SID, EVERYONE] only — the standing ACE stays inert under read-only while the unrevoked ACE keeps the re-upgrade free (map hit, no re-propagation). Pinned by the runner's real-token mode-downgrade regression (standing ACE denied under read-only, effective again on re-upgrade), the acl-session mode-switch cycle (nothing under read-only, one materialization on upgrade, no revoke on downgrade), and ConstrainedLanguage pins in both modes.
2026-08-08 20:11:01 +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 fa591b5ebd docs(sandbox): record the DACL churn limitation and the win32 snapshot substitution
Known Limitations gains the per-command DACL mutation entry (inheritance is lazy, not a per-file walk; per-session grant reuse is deferred work); the design note gains a Testing section stating why the win32-only roster flip cannot ride macOS/Linux snapshot fixtures and naming the substitute evidence.
2026-08-08 13:44:10 +08:00
Huanqi Cao aa790346e4 docs(sandbox): explain why the token intersection needs no new identity
Add the mechanism section to the Windows rung Agent Note: identity routes (restricted-user, AppContainer) default-deny everything from a fresh SID and pay per-path ACE writes for every read, while the WRITE_RESTRICTED token keeps the caller's SID and double-checks write-class access only — reads pass on the normal check alone. Covers DISABLE_MAX_PRIVILEGE/LUA_TOKEN as the token-side limited-user synthesis and why SidsToDisable read restriction is unused.
2026-08-08 02:42:47 +08:00
Huanqi Cao 264420127a docs(sandbox): record the Windows rung design choice — raw ACL restricted tokens over mxc and AppContainer
Add the implemented Agent Note owning the win32 rung decision: mxc rejected (OS floor 24H2, BaseContainer tier only on 25H2+ with the OS feature enabled, and arbitrary-path reads demand wholesale host DACL writes), AppContainer rejected (no ambient read access — arbitrary-path reads unsupported), landstrip already rejected and AppContainer-shaped. Link the note from the backend README pair and restate the choice in the PR description.
2026-08-08 02:32:54 +08:00