install(security-scanner): gate post-start() deref on Ok to avoid over-deref - #31032
install(security-scanner): gate post-start() deref on Ok to avoid over-deref#31032robobun wants to merge 1 commit into
Conversation
|
Updated 3:17 PM PT - May 21st, 2026
❌ @robobun, your commit aa018cd has 2 failures in
🧪 To try this PR locally: bunx bun-pr 31032That installs a local version of the PR into your bun-31032 --bun |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughThis PR contains two unrelated corrections to runtime and package manager code. The security scanner now guards unsafe refcount operations behind a success check, and the SSL configuration documentation clarifies the allocator contract for a helper function. ChangesSafety and documentation fixes
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
Closing per the no-test gate — this one genuinely can't be covered by a regression test:
The refcount trace in the PR body is the proof of correctness. Branch |
There was a problem hiding this comment.
LGTM — verified start() self-derefs on Err (static_pipe_writer.rs:196/210), so gating the caller deref on is_ok() is correct and the Ok path is unchanged.
Extended reasoning...
Overview
Follow-up to #30875 addressing two inline review comments. In security_scanner.rs, wraps the post-start() RefCount::deref + started = false write in if start_result.is_ok(). In SSLConfig.rs, updates two stale doc-comment words (mi_free → free_sensitive, mimalloc → default-allocator) to match the already-updated block comment above them.
Verification
I checked src/spawn/static_pipe_writer.rs:175-228: start() does ref_() up front, and on the Err branch (both Windows :196 and POSIX :210) it self-deref()s and never sets started = true. So on Err the function is already refcount-neutral and started is already false — the caller's unconditional deref was indeed an over-deref, and the PR's refcount trace (2 → 3 → 2 → 1 → 0 → UAF/double-free via the scopeguard) is accurate. On Ok, the gated block runs exactly as before, so success-path behavior is byte-identical.
Security risks
None. No new inputs, no parsing, no auth/crypto surface. The change narrows when an unsafe deref runs; it cannot introduce a new unsafe path.
Level of scrutiny
This is intrusive-refcount code in unsafe Rust, which normally warrants care, but the diff is a 4-line conditional wrapper around existing code with no change to the common (Ok) path. Reachability of the fixed path is limited to PosixBufferedWriter::start failing on a fresh pipe fd (epoll/kqueue ENOMEM/ENOSPC), so risk of regression is very low. The SSLConfig changes are comment-only.
Other factors
This directly closes out two review-comment threads from #30875; cargo check and the security-scanner test suite pass per the description; no bugs were flagged by the bug-hunting pass.
…r-deref StaticPipeWriter::start() is now refcount-neutral on Err (it releases its own +1 and leaves started == false). The security-scanner caller was still unconditionally dropping start()'s +1, which over-derefs on the Err path: refcount hits zero while json_writer still holds a pointer, then the errdefer scopeguard touches freed memory (source.detach()) and double-frees on w.deref(). Also fix two stale doc comments in SSLConfig.rs that still referenced mi_free / mimalloc after dupe_z / free_sensitive moved to default_alloc. Follow-up to #30875.
4daf5f5 to
aa018cd
Compare
|
Reopened + rebased onto main (aa018cd onto 832edbc) per Discord — re-verified against current main:
No regression test: the Err path needs
|
There was a problem hiding this comment.
LGTM — verified StaticPipeWriter::start() self-derefs on Err (static_pipe_writer.rs:196/210), so gating the caller's deref on is_ok() is correct; Ok path is unchanged.
Extended reasoning...
Overview
Two changes, both follow-ups to review comments on #30875:
src/install/PackageManager/security_scanner.rs(finish_spawn): wraps the post-start()intrusivederef+started = falsereset inif start_result.is_ok(). I verified againstsrc/spawn/static_pipe_writer.rs:183/196/210thatstart()takes a+1at entry and self-releases it on theErrpath (both Windows and POSIX), leavingstarted == false. So the unconditional caller-side deref was indeed an over-deref onErr, and the refcount trace in the PR body (→ UAF in the scopeguard, double-free) is accurate. TheOkpath executes the exact same two statements as before, just inside theif— byte-for-byte identical happy-path behavior.src/runtime/socket/SSLConfig.rs: two doc-comment words updated (mi_free→free_sensitive,mimalloc→default-allocator) to match the adjacent block comment that already referencesbun_core::free_sensitive/default_alloc. Zero runtime impact.
Security risks
None. The refcount fix only affects an error path that requires epoll_ctl(ADD)/kevent to fail with ENOMEM/ENOSPC on a freshly-created socketpair fd — not attacker-reachable, and the change strictly removes a UAF/double-free rather than introducing one. The SSLConfig change is comment-only.
Level of scrutiny
Low. The diff is +8/-4 effective lines, the Ok path is provably unchanged, and the Err-path reasoning is mechanically verifiable against the start() source I checked. No CODEOWNERS entries cover either file.
Other factors
- Bug-hunting system found no issues; CodeRabbit found no actionable comments.
cargo checkand the security-scanner workspace test pass per the PR body / rebase comment.- The lack of a regression test is well-justified in the timeline (no fault-injection hook for the kernel error, and the
Okpath can't discriminate before/after). - Other
StaticPipeWriter::start()callers were already checked by the author (subprocess.rs:220 gates onstarted, shell/subproc.rs:891 doesn't extra-deref), so this was the only stale call site.
|
This over-deref was found again independently while working on the POSIX pipe writers, so I re-checked this PR against current main (b555e06), which includes #37774's rework of how
#37898 touches the same lines from the Windows side (it gates the scanner's release on the |
Follow-up to #30875 (#30875 (comment) and #30875 (comment)).
What
security_scanner.rsover-deref onstart()failure#30875 made
StaticPipeWriter::start()refcount-neutral onErr— it now releases its own+1before returning (static_pipe_writer.rs:196 Windows / :210 POSIX) and leavesstarted == false. ButSecurityScanSubprocess::finish_spawnwas still unconditionally releasing thestart()ref right after the call, which on theErrpath is an over-deref:json_writerfield +writer_localstart()ref_()start()failsErrarmwriter_local.deref()return Errjson_writer.take()→ danglingsource.detach()w.deref()Fix: gate the deref (and the
started = falsewrite) onstart_result.is_ok(). OnErr,start()has already balanced its own ref andstartedis alreadyfalse.Reachability is limited to
PosixBufferedWriter::startfailing on a fresh pipe fd (epoll/kqueueENOMEM/ENOSPC), so there's no practical repro, but the refcount trace is unambiguous.SSLConfig.rsstale doc commentsTwo function-level doc comments adjacent to the block comment rewritten in #30875 still said
mi_free/ "mimalloc allocation" afterdupe_z/free_sensitivemoved tobun_alloc::default_alloc. Updated to match.Verification
cargo check -p bun_install -p bun_runtimeclean;bun bd test bun-security-scanner-workspaces.test.tspasses (3/3).