[PR #4435] [MERGED] fix(pwntools): preserve worker ownership across launcher exec #6241

Closed
opened 2026-10-31 01:12:58 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/4435
Author: @N0zoM1z0
Created: 10/16/2026
Status: ✅ Merged
Merged: 10/16/2026
Merged by: @N0zoM1z0

Base: main ← Head: fix/pwndbg-exec-ownership-4011


📝 Commits (2)

  • 0f3bd2e fix(pwntools): preserve worker ownership across launcher exec
  • 1f5ca5a test(pwntools): retain evidence on refused exec cleanup

📊 Changes

2 files changed (+101 additions, -23 deletions)

View changed files

📝 src/native/pwntools/PwntoolsDecoder.ts (+7 -4)
📝 tests/boundary/binaryDiagnostics/recordedCrashProvider.test.ts (+94 -19)

📄 Description

Summary

Fixes #4011. Recorded-core cancellation now retires the owned GDB after the Python launcher replaces itself with it, while retaining decoded evidence. Lifecycle audit: #4227.

Problem and expected behavior

The optional debugger deliberately uses execve, but inherited an expectation that its command was still Python. Cancellation consequently returned cleanup_incomplete and left authenticated GDB running. Cleanup should follow the same owned process across that transition.

Change and scope

Normalize the exec-aware default once in PwntoolsDecoder.#runCommand, shared by basic decoding and optional debugger stages, and remove the basic-stage special case. Explicit command pins remain honored. Parent, process-group and run-token checks remain required; a real exec with a foreign token is refused and retains retryable resources.

Contract and boundary impact

  • Semantic owner and earliest changed stage: pwntools decoder process acquisition, before either stage launches.
  • Contribution scope: ordinary cleanup fix within existing authority; new-capability maintainer decision not applicable.
  • CLI/MCP/catalog: shared implementation; no schema, input, pagination or success-output changes.
  • Provider compatibility: existing Linux x64 pwntools/pwndbg profile; no bridge or upstream modifications.
  • Evidence/provenance: source bytes and basic partial observations survive optional-stage cancellation.
  • Target/cleanup: existing core-only debugger launch; no live inferior attachment or execution during inspection. Unresolved ownership remains retained.
  • Generated/package/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.

These refer to the existing owned debugger/helper execution, termination and private temporary files; no new target authority is introduced.

Evidence and regression coverage

  • Existing production-boundary tests now execute an actual shell-to-worker exec, verify cancellation returns only after exit, and check foreign-token refusal, retained files, blocked reuse and cleanup retry. Shared wrong-parent/token controls remain.

  • Base d72d856f5: final exec regression fails; other 36 recorded-crash tests pass. With the fix: 100 passed, 1 existing skip across 10 affected files.

  • Real GNU GDB 13.1 + unchanged pwndbg 2026.09.15: an authored initialization wrapper loads the vendor entry and pauses immediately after native handoff. With the same core SHA-256, base returns cleanup_incomplete with the stale Python identity and GDB alive; head returns cancelled, GDB gone, basic evidence retained, unrelated GDB-named control alive, same-provider recovery successful. This is controlled real-engine fault injection, not an unmodified-vendor cancellation claim.

  • Unmodified public CLI/MCP suite: 42 cases passed on base and head, including traced core-only inspection, source integrity, bounded output, diagnostics and owned verifier-lineage cleanup.

  • Remaining gaps: other OSes/engine versions and MCP SDK raw-partial recovery after cancellation (#4276) are unverified here.

  • Observed, derived, and inferred claims remain distinguishable.

  • Artifact identity, source provenance, and failed attempts remain preserved.

  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

Executed on Linux x64. Production fix 0f3bd2e3d; final head 1f5ca5adeef985db50f06f3ed571f9cd6cf4c54d adds only the review-requested test assertions. Source checks ran immediately before their unchanged commits:

  • npm run test:focused -- the 10 affected recorded-crash/pwntools files — 100 passed, 1 existing skip.
  • Final recorded-crash file after review — 37 passed, including exact partial artifact digest, threads, notes and both stage diagnostics on refused cleanup.
  • npm run check:fast — passed again after review; npm run docs:check — passed with the unchanged production fix.
  • node scripts/verify-recorded-crash.mjs — 42 public CLI/MCP cases passed with real pwntools 4.15.0, GDB 13.1, pwndbg 2026.09.15 and strace 6.1.
  • Real production-adapter cancellation/recovery probe — passed on exact head; GDB stopped before returning cancellation (87 ms on final head), original core unchanged, partial observations retained, same-provider reuse successful, unrelated process preserved.

Performance: the same physical core through fresh CLI + first/repeated stdio MCP inspections on base/final head took 8.11/8.27 s wall, 9.31/9.45 s CPU, and 1.060/1.061 GiB peak sampled family RSS. Individual MCP calls: 1.229/1.269 s first, 1.191/1.230 s repeated. Serialized request + full reply proxy is exactly 32,465 o200k_base tokens per MCP call on both revisions; no schema/output growth. This proxy excludes schemas, initialization/control traffic, CLI output and model billing. Second MCP call reuses its connection; there is no new analysis cache. No speedup claim.

The full 42-case verifier passed twice per revision: base 82.0/81.4 s, fix 149.0/78.0 s. The slower first fixed run is retained as an observed outlier without an established cause. Two-core affinity, serial jobs, 3 GiB Node heap; filesystem/module caches uncontrolled on a shared host. RSS sampling may double-count shared pages or miss short children; CPU includes only reaped descendants. Full reports and selected-environment commands are retained locally under /tmp/rea-4011-pwndbg-exec-20261016/.

Compatibility, safety, and release

  • No breaking change, migration, dependency, generated-file or release-metadata change.
  • Real-provider coverage for this diff: Linux recorded cores, pwntools and GDB/pwndbg. Hopper/Ghidra are outside this focused change.
  • Cleanup still requires current ownership proof; foreign tokens are never signaled. Test-only fallback uses the fixture's retained creation handle. Core generation uses an explicitly selected minimal environment; ambient environment is not persisted into core fixtures.

Author readiness

Human owner: @N0zoM1z0

Readiness declarations are entered under the human owner's explicit instruction in the working session to complete them and request review. Implementation and validation review were performed by the assistant; this does not claim a separate manual human review.

  • 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/4435 **Author:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Created:** 10/16/2026 **Status:** ✅ Merged **Merged:** 10/16/2026 **Merged by:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Base:** `main` ← **Head:** `fix/pwndbg-exec-ownership-4011` --- ### 📝 Commits (2) - [`0f3bd2e`](https://github.com/morluto/rea/commit/0f3bd2e3d27b802fa2a63dd306dde5ec42b4dc93) fix(pwntools): preserve worker ownership across launcher exec - [`1f5ca5a`](https://github.com/morluto/rea/commit/1f5ca5adeef985db50f06f3ed571f9cd6cf4c54d) test(pwntools): retain evidence on refused exec cleanup ### 📊 Changes **2 files changed** (+101 additions, -23 deletions) <details> <summary>View changed files</summary> 📝 `src/native/pwntools/PwntoolsDecoder.ts` (+7 -4) 📝 `tests/boundary/binaryDiagnostics/recordedCrashProvider.test.ts` (+94 -19) </details> ### 📄 Description ## Summary Fixes #4011. Recorded-core cancellation now retires the owned GDB after the Python launcher replaces itself with it, while retaining decoded evidence. Lifecycle audit: #4227. ## Problem and expected behavior The optional debugger deliberately uses `execve`, but inherited an expectation that its command was still Python. Cancellation consequently returned `cleanup_incomplete` and left authenticated GDB running. Cleanup should follow the same owned process across that transition. ## Change and scope Normalize the exec-aware default once in `PwntoolsDecoder.#runCommand`, shared by basic decoding and optional debugger stages, and remove the basic-stage special case. Explicit command pins remain honored. Parent, process-group and run-token checks remain required; a real exec with a foreign token is refused and retains retryable resources. ## Contract and boundary impact - Semantic owner and earliest changed stage: pwntools decoder process acquisition, before either stage launches. - Contribution scope: ordinary cleanup fix within existing authority; new-capability maintainer decision not applicable. - CLI/MCP/catalog: shared implementation; no schema, input, pagination or success-output changes. - Provider compatibility: existing Linux x64 pwntools/pwndbg profile; no bridge or upstream modifications. - Evidence/provenance: source bytes and basic partial observations survive optional-stage cancellation. - Target/cleanup: existing core-only debugger launch; no live inferior attachment or execution during inspection. Unresolved ownership remains retained. - Generated/package/installation impact: none. Expected effects: - [x] Read existing files or captured data. - [x] Launch or attach to a process. - [x] Inject instrumentation or run scripts/code. - [x] Change process memory, registers, files, or configuration. These refer to the existing owned debugger/helper execution, termination and private temporary files; no new target authority is introduced. ## Evidence and regression coverage - Existing production-boundary tests now execute an actual shell-to-worker `exec`, verify cancellation returns only after exit, and check foreign-token refusal, retained files, blocked reuse and cleanup retry. Shared wrong-parent/token controls remain. - Base `d72d856f5`: final exec regression fails; other 36 recorded-crash tests pass. With the fix: 100 passed, 1 existing skip across 10 affected files. - Real GNU GDB 13.1 + unchanged pwndbg 2026.09.15: an authored initialization wrapper loads the vendor entry and pauses immediately after native handoff. With the same core SHA-256, base returns `cleanup_incomplete` with the stale Python identity and GDB alive; head returns `cancelled`, GDB gone, basic evidence retained, unrelated GDB-named control alive, same-provider recovery successful. This is controlled real-engine fault injection, not an unmodified-vendor cancellation claim. - Unmodified public CLI/MCP suite: 42 cases passed on base and head, including traced core-only inspection, source integrity, bounded output, diagnostics and owned verifier-lineage cleanup. - Remaining gaps: other OSes/engine versions and MCP SDK raw-partial recovery after cancellation (#4276) are unverified here. - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed Executed on Linux x64. Production fix `0f3bd2e3d`; final head `1f5ca5adeef985db50f06f3ed571f9cd6cf4c54d` adds only the review-requested test assertions. Source checks ran immediately before their unchanged commits: - `npm run test:focused --` the 10 affected recorded-crash/pwntools files — 100 passed, 1 existing skip. - Final recorded-crash file after review — 37 passed, including exact partial artifact digest, threads, notes and both stage diagnostics on refused cleanup. - `npm run check:fast` — passed again after review; `npm run docs:check` — passed with the unchanged production fix. - `node scripts/verify-recorded-crash.mjs` — 42 public CLI/MCP cases passed with real pwntools 4.15.0, GDB 13.1, pwndbg 2026.09.15 and strace 6.1. - Real production-adapter cancellation/recovery probe — passed on exact head; GDB stopped before returning cancellation (87 ms on final head), original core unchanged, partial observations retained, same-provider reuse successful, unrelated process preserved. Performance: the same physical core through fresh CLI + first/repeated stdio MCP inspections on base/final head took 8.11/8.27 s wall, 9.31/9.45 s CPU, and 1.060/1.061 GiB peak sampled family RSS. Individual MCP calls: 1.229/1.269 s first, 1.191/1.230 s repeated. Serialized request + full reply proxy is exactly 32,465 `o200k_base` tokens per MCP call on both revisions; no schema/output growth. This proxy excludes schemas, initialization/control traffic, CLI output and model billing. Second MCP call reuses its connection; there is no new analysis cache. No speedup claim. The full 42-case verifier passed twice per revision: base 82.0/81.4 s, fix 149.0/78.0 s. The slower first fixed run is retained as an observed outlier without an established cause. Two-core affinity, serial jobs, 3 GiB Node heap; filesystem/module caches uncontrolled on a shared host. RSS sampling may double-count shared pages or miss short children; CPU includes only reaped descendants. Full reports and selected-environment commands are retained locally under `/tmp/rea-4011-pwndbg-exec-20261016/`. ## Compatibility, safety, and release - No breaking change, migration, dependency, generated-file or release-metadata change. - Real-provider coverage for this diff: Linux recorded cores, pwntools and GDB/pwndbg. Hopper/Ghidra are outside this focused change. - Cleanup still requires current ownership proof; foreign tokens are never signaled. Test-only fallback uses the fixture's retained creation handle. Core generation uses an explicitly selected minimal environment; ambient environment is not persisted into core fixtures. ## Author readiness Human owner: @N0zoM1z0 Readiness declarations are entered under the human owner's explicit instruction in the working session to complete them and request review. Implementation and validation review were performed by the assistant; this does not claim a separate manual human review. - [x] 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. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] 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. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] 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>
bsakaguchi 2026-10-31 01:12:58 +00:00
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#6241
No description provided.