[GH-ISSUE #290] Create and verify private Windows runtime DACLs #162

Open
opened 2026-10-15 18:21:52 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @morluto on GitHub (Jul 16, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/290

Originally assigned to: @N0zoM1z0 on GitHub.

Problem Statement

PrivateRuntimeRoot and Ghidra's runtime files use POSIX mode requests such as 0700 and 0600. On Windows these mode values do not establish or verify a current-user-only DACL. The inherited ACL on the temporary parent therefore determines access to session descriptors, request tokens, endpoint records, snapshots, logs, and Ghidra project data.

The authenticated loopback protocol protects requests only if its token and session material remain private. REA currently documents this gap and declines to claim private-DACL enforcement.

Purpose and Benefit

Create a real Windows private-runtime boundary whose access policy is established by REA and verified from the resulting security descriptor.

This would:

  • protect session authentication material from other local principals;
  • give snapshots, logs, project files, and endpoint records one inherited security policy;
  • provide the ACL machinery needed by a future protected named-pipe transport; and
  • let capability reporting distinguish verified private storage from ordinary temporary-directory creation.

Proposed Direction

Extend the platform runtime-root adapter to create a directory with a protected DACL that grants only the current user and SYSTEM the access required for the session. Child files and directories should inherit the intended policy.

After creation, read the security descriptor back by handle and verify at least:

  • owner identity;
  • DACL presence and protected/inheritance state;
  • the admitted trustees and rights;
  • absence of null-DACL or broad allow entries; and
  • security support on the backing filesystem.

Creation and readback belong in the Windows native adapter from #287. Ghidra should receive only a verified private runtime root, not manipulate ACLs itself.

Desired Outcome

  • Windows runtime roots fail closed when the requested DACL cannot be created or read back.
  • Session descriptors, endpoint records, snapshots, logs, and project directories inherit or receive the verified policy.
  • A hostile permissive parent ACL does not broaden access to the runtime tree.
  • Capability and doctor output report verified availability and actionable failures.
  • Real Windows tests run as a non-administrator and verify allowed current-user/SYSTEM access plus denied unrelated-user access.
  • Cleanup remains idempotent and does not follow links outside the owned runtime tree.

Constraints and Non-goals

  • Depends on #287.
  • Do not use chmod success as Windows ACL evidence.
  • Avoid icacls or PowerShell orchestration as the authority boundary; creation and verification should be handle-based and race-aware.
  • Named-pipe transport can reuse this capability later but is not part of this issue.

Evidence and References

Originally created by @morluto on GitHub (Jul 16, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/290 Originally assigned to: @N0zoM1z0 on GitHub. ## Problem Statement PrivateRuntimeRoot and Ghidra's runtime files use POSIX mode requests such as 0700 and 0600. On Windows these mode values do not establish or verify a current-user-only DACL. The inherited ACL on the temporary parent therefore determines access to session descriptors, request tokens, endpoint records, snapshots, logs, and Ghidra project data. The authenticated loopback protocol protects requests only if its token and session material remain private. REA currently documents this gap and declines to claim private-DACL enforcement. ## Purpose and Benefit Create a real Windows private-runtime boundary whose access policy is established by REA and verified from the resulting security descriptor. This would: - protect session authentication material from other local principals; - give snapshots, logs, project files, and endpoint records one inherited security policy; - provide the ACL machinery needed by a future protected named-pipe transport; and - let capability reporting distinguish verified private storage from ordinary temporary-directory creation. ## Proposed Direction Extend the platform runtime-root adapter to create a directory with a protected DACL that grants only the current user and SYSTEM the access required for the session. Child files and directories should inherit the intended policy. After creation, read the security descriptor back by handle and verify at least: - owner identity; - DACL presence and protected/inheritance state; - the admitted trustees and rights; - absence of null-DACL or broad allow entries; and - security support on the backing filesystem. Creation and readback belong in the Windows native adapter from #287. Ghidra should receive only a verified private runtime root, not manipulate ACLs itself. ## Desired Outcome - Windows runtime roots fail closed when the requested DACL cannot be created or read back. - Session descriptors, endpoint records, snapshots, logs, and project directories inherit or receive the verified policy. - A hostile permissive parent ACL does not broaden access to the runtime tree. - Capability and doctor output report verified availability and actionable failures. - Real Windows tests run as a non-administrator and verify allowed current-user/SYSTEM access plus denied unrelated-user access. - Cleanup remains idempotent and does not follow links outside the owned runtime tree. ## Constraints and Non-goals - Depends on #287. - Do not use chmod success as Windows ACL evidence. - Avoid icacls or PowerShell orchestration as the authority boundary; creation and verification should be handle-based and race-aware. - Named-pipe transport can reuse this capability later but is not part of this issue. ## Evidence and References - Parent roadmap: #38 - Current implementation: src/process/PrivateRuntimeRoot.ts and src/ghidra/GhidraLauncher.ts - Current capability declaration: src/application/WindowsCapabilities.ts - Security descriptors: https://learn.microsoft.com/en-us/windows/win32/secauthz/security-descriptors - DACL behavior, including the difference between a null and empty DACL: https://learn.microsoft.com/en-us/windows/win32/secauthz/access-control-lists - Handle-based security descriptor operations: https://learn.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-operations
Author
Owner

@morluto commented on GitHub (Jul 17, 2026):

Status after #287 packaging research: this remains active and depends on the handle/file-identity boundary in #289. Private runtime-root DACL creation and verification should be performed by handle, preserve typed diagnostics, and be proven by the real non-admin Windows verifier. It should not duplicate path-opening logic from #289.

<!-- gh-comment-id:5001547558 --> @morluto commented on GitHub (Jul 17, 2026): Status after #287 packaging research: this remains active and depends on the handle/file-identity boundary in #289. Private runtime-root DACL creation and verification should be performed by handle, preserve typed diagnostics, and be proven by the real non-admin Windows verifier. It should not duplicate path-opening logic from #289.
Author
Owner

@morluto commented on GitHub (Jul 17, 2026):

Current-main contract update (2026-07-17):

The provider-neutral sealed-root boundary now parses DACL observations before publishing a WindowsPrivateRoot. It distinguishes five object classes:

  • root directory;
  • read-only directories;
  • read-only files;
  • writable directories; and
  • writable files inherited from a protected writable parent.

Each class commits object kind, explicit/inherited ACE disposition, propagation, owner, exact admitted trustee vocabulary, current-user/SYSTEM/OWNER RIGHTS semantics, verified object count, descriptor digest, and path-to-policy manifest digest. A versioned enclosing digest binds those five records to both the projection manifest and launch commitment. The parser cross-checks file/directory counts, rejects class/rights/propagation contradictions, null or broad DACL reports, additional trustees, malformed/unknown fields, and cross-projection security-manifest reuse, then poisons/closes malformed native tokens.

Independent review also exposed a stronger unresolved boundary: changing a DACL after construction cannot revoke write, delete, WRITE_DAC, or mapped-section rights already held by another same-user process. ADR-0004 now rejects “seal later.” The native design must apply final descriptors at creation or establish another proven construction principal/capability, close every mutation-capable construction handle before commit, and pass pre-open race tests. #290 can establish privacy against unrelated local principals, but it cannot silently satisfy same-user immutable launch authority.

Focused coverage now exercises the accepted five-class report plus rejection of null DACLs, broad/additional trustees, wrong owner/SYSTEM/OWNER RIGHTS, wrong protection/propagation/rights, malformed digests, unknown fields, count drift, security-digest drift, and projection-manifest substitution. The exact tree passes npm run check, including all 160 test files, generated docs, build, typecheck, lint, and formatting.

This issue remains open for the native descriptor creation/readback implementation, non-administrator unrelated-user access proof, cleanup proof, capability/doctor wiring, and the explicitly separate same-user construction-race decision.

<!-- gh-comment-id:5007976785 --> @morluto commented on GitHub (Jul 17, 2026): Current-main contract update (2026-07-17): The provider-neutral sealed-root boundary now parses DACL observations before publishing a WindowsPrivateRoot. It distinguishes five object classes: - root directory; - read-only directories; - read-only files; - writable directories; and - writable files inherited from a protected writable parent. Each class commits object kind, explicit/inherited ACE disposition, propagation, owner, exact admitted trustee vocabulary, current-user/SYSTEM/OWNER RIGHTS semantics, verified object count, descriptor digest, and path-to-policy manifest digest. A versioned enclosing digest binds those five records to both the projection manifest and launch commitment. The parser cross-checks file/directory counts, rejects class/rights/propagation contradictions, null or broad DACL reports, additional trustees, malformed/unknown fields, and cross-projection security-manifest reuse, then poisons/closes malformed native tokens. Independent review also exposed a stronger unresolved boundary: changing a DACL after construction cannot revoke write, delete, WRITE_DAC, or mapped-section rights already held by another same-user process. ADR-0004 now rejects “seal later.” The native design must apply final descriptors at creation or establish another proven construction principal/capability, close every mutation-capable construction handle before commit, and pass pre-open race tests. #290 can establish privacy against unrelated local principals, but it cannot silently satisfy same-user immutable launch authority. Focused coverage now exercises the accepted five-class report plus rejection of null DACLs, broad/additional trustees, wrong owner/SYSTEM/OWNER RIGHTS, wrong protection/propagation/rights, malformed digests, unknown fields, count drift, security-digest drift, and projection-manifest substitution. The exact tree passes npm run check, including all 160 test files, generated docs, build, typecheck, lint, and formatting. This issue remains open for the native descriptor creation/readback implementation, non-administrator unrelated-user access proof, cleanup proof, capability/doctor wiring, and the explicitly separate same-user construction-race decision.
Author
Owner

@morluto commented on GitHub (Jul 20, 2026):

Split into focused child issues:

These replace the broad remaining scope in this issue. Closing this parent can happen once all children are closed.

<!-- gh-comment-id:5023380863 --> @morluto commented on GitHub (Jul 20, 2026): Split into focused child issues: - [ ] #327 - [ ] #328 - [ ] #329 These replace the broad remaining scope in this issue. Closing this parent can happen once all children are closed.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#162
No description provided.