[PR #7145] fix: treat other-user-namespace processes as withheld during cleanup #7672

Open
opened 2026-11-03 13:39:32 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/7145
Author: @hsaki11
Created: 10/25/2026
Status: 🔄 Open

Base: main ← Head: hsaki11-patch-1


📝 Commits (8)

  • 18eff56 fix: treat other-user-namespace processes as withheld during cleanup
  • 3592bc9 fix: treat other-user-namespace processes as withheld during cleanup
  • 9138f37 Delete src/process/ProcessOwnership.procIdentity.test.ts
  • 5ca6e0b Delete src/process/LinuxProcessStatus.test.ts
  • 391ef64 Delete src/process/ProcessOwnership.identity.test.ts
  • bdddd42 fix: treat other-user-namespace processes as withheld during cleanup
  • 8ed115d Rename ProcessOwnership_identity_test.ts to ProcessOwnership.identity_test.ts
  • d0c5956 Add files via upload

📊 Changes

6 files changed (+821 additions, -181 deletions)

View changed files

📝 src/process/LinuxProcessStatus.ts (+33 -6)
📝 src/process/LinuxProcessStatus_test.ts (+56 -0)
📝 src/process/ProcessOwnership.identity_test.ts (+123 -48)
📝 src/process/ProcessOwnership.ts (+231 -99)
📝 src/process/ProcessOwnershipObservation.ts (+285 -19)
📝 src/process/ProcessOwnership_procIdentity_test.ts (+93 -9)

📄 Description

Summary

Fixes #7143

open_binary failed with cleanup_incomplete when same-UID processes in another user namespace (for example bwrap sandboxes) returned EACCES on /proc/<pid>/environ. Such unrelated processes are now recorded as unverified instead of failing cleanup. Related, descendant and same-group processes still fail closed.

This PR was prepared with AI assistance (Claude).

Problem and expected behavior

Trigger: any same-UID process in a different user namespace is running while REA verifies cleanup. /proc/<pid>/status shows the same UID, so the process was not classified as withheld and the scan failed with environment_errno_EACCES.

Expected: an unrelated process whose environment the kernel withholds is recorded as unverified; a clean capture is not failed.

Change and scope

Add a user-namespace environment restriction. It is derived by comparing /proc/<pid>/uid_map with the caller's own /proc/self/uid_map. Maps are rendered relative to the reader, so different text proves different namespaces; equal or unreadable maps stay unknown and fail closed. The maps are read only when the credentials and non-dumpable checks did not already apply, and only for token-unreadable candidates. The caller's map is read once per call.

Not included: treating EACCES alone as withheld (an existing test requires it to stay fail-closed), and any change to Darwin or Windows.

Contribution scope: not applicable, an ordinary fix within existing boundaries.

Contract and boundary impact

  • Semantic owner and earliest changed stage: LinuxProcessStatus.ts derives the restriction and ProcessOwnershipObservation.ts produces it in processIdentities; environmentWithheldFromInspection in ProcessOwnership.ts consumes it unchanged. No superseded paths removed.
  • Contribution scope fit and linked maintainer decision: not applicable.
  • CLI and MCP/tool-catalog contract: none.
  • Provider, bridge, target-format, or platform compatibility: Linux only.
  • Evidence, artifact, provenance, or reconstruction contract: the process is reported in the existing unverified list with its original diagnostic; no new fields.
  • Target selection, authority, upstream behavior, and cleanup details: related, descendant and same-group processes stay strict.
  • Generated metadata, package, or installation impact: none.

Expected effects:

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

Source-derived and executed against mocked procfs, plus a one-off check against real procfs.

  • Tests added or updated: LinuxProcessStatus.test.ts (restriction derivation, map comparison), ProcessOwnership.procIdentity.test.ts (observation, unreadable map), ProcessOwnership.identity.test.ts (unrelated process recorded as unverified; same group still fails closed). One existing test was changed to answer by path instead of by call order.
  • Base reproduction or other evidence: I could not reproduce the original EACCES; in my sandbox a same-UID child user namespace process had a readable environ. I verified only that a real unshare -Ur child is detected as user-namespace and a plain process is not (temporary test, not included).
  • User-visible CLI/MCP output: none.
  • Remaining proof gaps: no real Ghidra open_binary run. If the reporter's EACCES comes from SELinux within the same namespace, this change does not cover it.

Validation performed

  • npx vitest run src/process/ProcessOwnership src/process/LinuxProcessStatus — 18 files, 295 tests passed
  • scoped tsc --noEmit on the touched files — passed
  • Not run: full tsc (killed for memory), oxlint (crashed in my environment), full test suite, docs:check, verify:module-boundaries.

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: none.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: a REA-owned process that left the run's process group and moved into its own user namespace would now be recorded as unverified instead of failing. Related and descendant processes are unaffected.

Author readiness

Human owner: @hsaki11

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/7145 **Author:** [@hsaki11](https://github.com/hsaki11) **Created:** 10/25/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `hsaki11-patch-1` --- ### 📝 Commits (8) - [`18eff56`](https://github.com/morluto/rea/commit/18eff563523e8ccb9f7531ed6cc04a3e18c80e7f) fix: treat other-user-namespace processes as withheld during cleanup - [`3592bc9`](https://github.com/morluto/rea/commit/3592bc9f8d68a8a2bf109e01987f97da6f7a310c) fix: treat other-user-namespace processes as withheld during cleanup - [`9138f37`](https://github.com/morluto/rea/commit/9138f37b129d6850d3d0c652202ef556c80284c3) Delete src/process/ProcessOwnership.procIdentity.test.ts - [`5ca6e0b`](https://github.com/morluto/rea/commit/5ca6e0be59d7a4a728f549fd3e3790a83d714a51) Delete src/process/LinuxProcessStatus.test.ts - [`391ef64`](https://github.com/morluto/rea/commit/391ef642b75460e21aefcc3962fbc6e3ebb148fd) Delete src/process/ProcessOwnership.identity.test.ts - [`bdddd42`](https://github.com/morluto/rea/commit/bdddd42a90aa2c95b856e54dd04633d3e207923e) fix: treat other-user-namespace processes as withheld during cleanup - [`8ed115d`](https://github.com/morluto/rea/commit/8ed115d6eca1bb0a2cd391b9093d5a872d1ea921) Rename ProcessOwnership_identity_test.ts to ProcessOwnership.identity_test.ts - [`d0c5956`](https://github.com/morluto/rea/commit/d0c5956a42371b5f075436f3818de60b71276181) Add files via upload ### 📊 Changes **6 files changed** (+821 additions, -181 deletions) <details> <summary>View changed files</summary> 📝 `src/process/LinuxProcessStatus.ts` (+33 -6) 📝 `src/process/LinuxProcessStatus_test.ts` (+56 -0) 📝 `src/process/ProcessOwnership.identity_test.ts` (+123 -48) 📝 `src/process/ProcessOwnership.ts` (+231 -99) 📝 `src/process/ProcessOwnershipObservation.ts` (+285 -19) 📝 `src/process/ProcessOwnership_procIdentity_test.ts` (+93 -9) </details> ### 📄 Description ## Summary Fixes #7143 `open_binary` failed with `cleanup_incomplete` when same-UID processes in another user namespace (for example bwrap sandboxes) returned EACCES on `/proc/<pid>/environ`. Such unrelated processes are now recorded as unverified instead of failing cleanup. Related, descendant and same-group processes still fail closed. This PR was prepared with AI assistance (Claude). ## Problem and expected behavior Trigger: any same-UID process in a different user namespace is running while REA verifies cleanup. `/proc/<pid>/status` shows the same UID, so the process was not classified as withheld and the scan failed with `environment_errno_EACCES`. Expected: an unrelated process whose environment the kernel withholds is recorded as unverified; a clean capture is not failed. ## Change and scope Add a `user-namespace` environment restriction. It is derived by comparing `/proc/<pid>/uid_map` with the caller's own `/proc/self/uid_map`. Maps are rendered relative to the reader, so different text proves different namespaces; equal or unreadable maps stay unknown and fail closed. The maps are read only when the credentials and non-dumpable checks did not already apply, and only for token-unreadable candidates. The caller's map is read once per call. Not included: treating EACCES alone as withheld (an existing test requires it to stay fail-closed), and any change to Darwin or Windows. Contribution scope: not applicable, an ordinary fix within existing boundaries. ## Contract and boundary impact - Semantic owner and earliest changed stage: `LinuxProcessStatus.ts` derives the restriction and `ProcessOwnershipObservation.ts` produces it in `processIdentities`; `environmentWithheldFromInspection` in `ProcessOwnership.ts` consumes it unchanged. No superseded paths removed. - Contribution scope fit and linked maintainer decision: not applicable. - CLI and MCP/tool-catalog contract: none. - Provider, bridge, target-format, or platform compatibility: Linux only. - Evidence, artifact, provenance, or reconstruction contract: the process is reported in the existing `unverified` list with its original diagnostic; no new fields. - Target selection, authority, upstream behavior, and cleanup details: related, descendant and same-group processes stay strict. - Generated metadata, package, or installation impact: none. Expected effects: - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage Source-derived and executed against mocked procfs, plus a one-off check against real procfs. - Tests added or updated: `LinuxProcessStatus.test.ts` (restriction derivation, map comparison), `ProcessOwnership.procIdentity.test.ts` (observation, unreadable map), `ProcessOwnership.identity.test.ts` (unrelated process recorded as unverified; same group still fails closed). One existing test was changed to answer by path instead of by call order. - Base reproduction or other evidence: I could not reproduce the original EACCES; in my sandbox a same-UID child user namespace process had a readable environ. I verified only that a real `unshare -Ur` child is detected as `user-namespace` and a plain process is not (temporary test, not included). - User-visible CLI/MCP output: none. - Remaining proof gaps: no real Ghidra `open_binary` run. If the reporter's EACCES comes from SELinux within the same namespace, this change does not cover it. ## Validation performed - `npx vitest run src/process/ProcessOwnership src/process/LinuxProcessStatus` — 18 files, 295 tests passed - scoped `tsc --noEmit` on the touched files — passed - Not run: full `tsc` (killed for memory), `oxlint` (crashed in my environment), full test suite, `docs:check`, `verify:module-boundaries`. ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: none. - Package or release metadata impact: none. - Security, privacy, process, or containment review: a REA-owned process that left the run's process group and moved into its own user namespace would now be recorded as unverified instead of failing. Related and descendant processes are unaffected. ## Author readiness Human owner: @hsaki11 - [ ] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [ ] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [ ] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [ ] Tests cover changed observable behavior and meaningful failure paths. - [ ] Owning docs, contracts, and generated metadata are updated where needed. - [ ] User-visible CLI/MCP changes include representative output. - [ ] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
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#7672
No description provided.