Restrict the worker named pipe to the current user (R21-O8 / GWC-05) #187

Closed
opened 2026-11-06 15:25:02 -05:00 by dohertj2 · 1 comment
Owner

The worker pipe is created with no ACL and no CurrentUserOnly (SessionWorkerClientFactory.CreatePipe); only the unguessable name and maxNumberOfServerInstances: 1 limit access.

Source: archreview/2026-10-21/remediation/00-tracking.md row R21-O8 (cycle-1 GWC-05)

Next step (from the tracker): Add PipeOptions.CurrentUserOnly (or a PipeSecurity for the worker account); confirm the worker runs as the same user on windev; add a launch test. Confirmed 2026-11-06: no CurrentUserOnly anywhere under src/.

Current-state evidence: the row is still Open/Deferred in the latest (2026-10-21) tracker, and a code check on local main @ 8c0a51d (2026-11-06) found it still present unless noted below.

The worker pipe is created with no ACL and no `CurrentUserOnly` (`SessionWorkerClientFactory.CreatePipe`); only the unguessable name and `maxNumberOfServerInstances: 1` limit access. Source: `archreview/2026-10-21/remediation/00-tracking.md` row R21-O8 (cycle-1 GWC-05) Next step (from the tracker): Add `PipeOptions.CurrentUserOnly` (or a `PipeSecurity` for the worker account); confirm the worker runs as the same user on windev; add a launch test. Confirmed 2026-11-06: no `CurrentUserOnly` anywhere under `src/`. Current-state evidence: the row is still `Open`/`Deferred` in the latest (2026-10-21) tracker, and a code check on local `main` @ `8c0a51d` (2026-11-06) found it still present unless noted below.
dohertj2 added the area:gatewayarea:authpriority:p1type:review-findingmigrated labels 2026-11-06 15:25:02 -05:00
Author
Owner

Fixed on main in 34a7453 + 777fef9. The fix is on the gateway side: the gateway hosts the pipe server (SessionWorkerClientFactory.CreatePipe), and the net48 worker is only a NamedPipeClientStream client, so the worker code doesn't change.

  • Windows: each pipe is created with NamedPipeServerStreamAcl.Create and a PipeSecurity from the new WorkerPipeSecurity.CreateForCurrentUser(). The DACL is protected (no inherited entries), the owner is the gateway user, and its only entry is FullControl for the gateway process user. The worker runs as that same user because WorkerProcessLauncher sets no alternate credentials; on windev the service runs as LocalSystem.
  • Non-Windows (test matrix): PipeOptions.CurrentUserOnly. On Unix, .NET enforces this by checking the peer's credentials at accept time.
  • Found on windev and removed (777fef9): the first version also had a deny ACE for NT AUTHORITY\NETWORK. That SID marks a network logon, not a remote caller. The SSH session token on windev carries it, so the deny entry locked the gateway's own same-machine workers out (UnauthorizedAccessException on connect, 15 fake-worker tests failed).

Tests (WorkerPipeSecurityTests):

  • Create_GrantsOnlyTheUser (Windows): the ACL is protected, the owner is correct, and the only entry is an allow for the user.
  • CreatePipe_OnWindows_AppliesCurrentUserOnlyAcl (Windows): reads the ACL back from the created kernel pipe object. Exactly one entry (current user), and no Everyone or Anonymous allow.
  • CreatePipe_AcceptsClientRunningAsTheSameUser (all platforms; on windev it runs from a network-logon SSH session).
  • UnixPipeOptions_AreAsynchronousAndCurrentUserOnly.

Evidence at 777fef9:

  • macOS gateway suite: 1347 passed / 2 skipped (the Windows-only tests).
  • windev isolated clone C:\build\mxgw-issues-187 gateway suite: 1349/1349 passed, all 4 WorkerPipeSecurityTests passed.
  • windev x86 Worker build: 0 warnings / 0 errors. Worker.Tests: 609 passed / 12 skipped / 0 failed.
  • windev live MXAccess WorkerLiveMxAccessSmokeTests.GatewaySession_WithLiveWorker_RegistersAdvisesStreamsDataAndCloses passed. It launches the real x86 net48 worker through SessionWorkerClientFactory, so the real worker connects through the restricted pipe end to end. I ran only this read-only test; no Galaxy writes.
  • windev CI windev-worker-ci.ps1 -Mode test: SUCCESS at 777fef9.

The MxAccessGw NSSM service on windev was not touched.

Not tested: a negative test from a different local account. windev has no spare account to run one, so the "other users denied" side is proven from the ACL contents, not from a rejected connect.

Fixed on `main` in 34a7453 + 777fef9. The fix is on the gateway side: the gateway hosts the pipe server (`SessionWorkerClientFactory.CreatePipe`), and the net48 worker is only a `NamedPipeClientStream` client, so the worker code doesn't change. - **Windows:** each pipe is created with `NamedPipeServerStreamAcl.Create` and a `PipeSecurity` from the new `WorkerPipeSecurity.CreateForCurrentUser()`. The DACL is protected (no inherited entries), the owner is the gateway user, and its only entry is FullControl for the gateway process user. The worker runs as that same user because `WorkerProcessLauncher` sets no alternate credentials; on windev the service runs as LocalSystem. - **Non-Windows (test matrix):** `PipeOptions.CurrentUserOnly`. On Unix, .NET enforces this by checking the peer's credentials at accept time. - **Found on windev and removed (777fef9):** the first version also had a deny ACE for `NT AUTHORITY\NETWORK`. That SID marks a network *logon*, not a remote caller. The SSH session token on windev carries it, so the deny entry locked the gateway's own same-machine workers out (`UnauthorizedAccessException` on connect, 15 fake-worker tests failed). Tests (`WorkerPipeSecurityTests`): - `Create_GrantsOnlyTheUser` (Windows): the ACL is protected, the owner is correct, and the only entry is an allow for the user. - `CreatePipe_OnWindows_AppliesCurrentUserOnlyAcl` (Windows): reads the ACL back from the created kernel pipe object. Exactly one entry (current user), and no Everyone or Anonymous allow. - `CreatePipe_AcceptsClientRunningAsTheSameUser` (all platforms; on windev it runs from a network-logon SSH session). - `UnixPipeOptions_AreAsynchronousAndCurrentUserOnly`. Evidence at 777fef9: - macOS gateway suite: 1347 passed / 2 skipped (the Windows-only tests). - windev isolated clone `C:\build\mxgw-issues-187` gateway suite: **1349/1349 passed**, all 4 `WorkerPipeSecurityTests` passed. - windev x86 Worker build: 0 warnings / 0 errors. Worker.Tests: 609 passed / 12 skipped / 0 failed. - windev live MXAccess `WorkerLiveMxAccessSmokeTests.GatewaySession_WithLiveWorker_RegistersAdvisesStreamsDataAndCloses` **passed**. It launches the real x86 net48 worker through `SessionWorkerClientFactory`, so the real worker connects through the restricted pipe end to end. I ran only this read-only test; no Galaxy writes. - windev CI `windev-worker-ci.ps1 -Mode test`: SUCCESS at 777fef9. The MxAccessGw NSSM service on windev was not touched. Not tested: a negative test from a *different* local account. windev has no spare account to run one, so the "other users denied" side is proven from the ACL contents, not from a rejected connect.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/mxaccessgw#187