#36677 util: Make files opened with fdbridge::fopen noninheritable
| Reviewability | Reviews | Agreement | Size | ||||
|---|---|---|---|---|---|---|---|
| #36677 util: Make files opened with fdbridge::fopen noninheritable | Ready | 0 | Strong | 47 + 41 tests | |||
|
|
|
|
| |||
Reviewability: ReadyStalePaused Agreement: StrongPositivePositive w/ caveatsNeutralMildDisputedBlockedCrickets Reviews: current code-review ACKs, then (+stale ACKs) and -NACKs; greener = more ACKs. Size: lines added or modified outside tests, then in tests; greener = smaller. | |||||||
Goal
Marks files opened through fsbridge::fopen as non-inheritable and close-on-exec across platforms. It appends the 'e' mode specifier on Linux, appends 'N' on Windows, and implements an open() fallback with O_CLOEXEC followed by fdopen() for other POSIX operating systems like macOS and BSD. A unit test is included to assert that opened files lack the inheritance flag.
Problem: File descriptors and handles opened through fsbridge::fopen remain inheritable across process boundaries by default, risking descriptor leaks into child processes executed by Bitcoin Core (such as external signers or notification scripts).
Evidence of importance:
- Addresses issue #36668 ('util: Make files opened via `fsbridge::fopen()` not inheritable by child processes').
Risk of a mistake: low (other, tests). A mistake in the fopen wrapper or mode parsing could cause file open failures across utility callers on non-Linux POSIX systems.
Changed since the previous assessment: The pull request is now linked to issue #36668.
Reviewability
Ready
Nothing known that would invalidate a review now.
Waiting on (from the thread read):
- reviewer: hebasto to re-review the revised implementation addressing race condition concerns 2026-10-28
Agreement
Strong
substantive support, no open objection (ValeraFinebits)
Thread notes: winterrdog commented suggesting to add Fixes #36668 to the PR description to auto-close the issue on merge; this is a procedural comment and introduces no claims.
Objections, suggestions, and questions:
| Reviewer | Type | Harm, request, or question | Status | Must be | Author replied | Quote |
|---|---|---|---|---|---|---|
| hebasto (member) | question, correctness | Is the 'e' mode flag in fopen supported across all non-Windows systems? | answered · author changed implementation into three cases addressing Linux, Windows, and POSIX | answered | yes | 2026-10-27: 'Is "e" available on all non-Windows systems?' Status from: 2026-10-28: SirECMG: 'I changed implementation into three cases' |
| ValeraFinebits (none) | objection, correctness | Compilation errors in fs_tests.cpp prevent test_bitcoin from building on Windows | fixed · fix pushed · tests now build and pass on Windows | changed | no | 2026-10-28: 'The compilation errors in fs_tests.cpp prevent test_bitcoin from building on Windows.' Status from: 2026-10-28: ValeraFinebits: 'Tested on Windows at 0c9ab56: the new test passes with the fix' |
| ValeraFinebits (none) | suggestion, maintenance | Add <cstring> for std::strchr | fixed · fix pushed · author added the missing include | answered | yes | 2026-10-28: 'Could we also add <cstring> for std::strchr?' Status from: 2026-10-28: SirECMG: 'Added the missing include!' |
| hebasto (member) | objection, safety | Consecutive fopen and fcntl(FD_CLOEXEC) calls are not atomic and race in multithreaded processes | fixed · fix pushed · author implemented separate Linux/Windows/POSIX paths to avoid the non-atomic race | changed | yes | 2026-10-28: 'Unfortunately, the consecutive fopen and fcntl(..., FD_CLOEXEC) calls are not atomic, which is a race in a multithreaded process.' Status from: 2026-10-28: SirECMG: 'I changed implementation into three cases' |
| ValeraFinebits (none) | suggestion, approach | Keep 'e' on Linux and use open with O_CLOEXEC followed by fdopen on macOS/POSIX | fixed · fix pushed · implemented by author across platform-specific branches | answered | yes | 2026-10-28: 'Could we keep the original e approach on Linux and handle macOS separately with open using O_CLOEXEC, followed by fdopen?' Status from: 2026-10-28: SirECMG: 'I changed implementation into three cases' |
Support:
- ValeraFinebits (none) (2026-10-28) [tested]: Verified on Windows that the test passes with the fix and fails without it on HANDLE_FLAG_INHERIT
Participants:
- hebasto (member, objection, 2 statements 2026-10-27 to 2026-10-28): objected to non-atomic fopen and fcntl race condition in multithreaded processes, and questioned 'e' support on POSIX
- ValeraFinebits (none, support, 7 statements 2026-10-28 to 2026-10-28): tested on Windows, suggested implementation improvements and fixes for macOS/POSIX
- winterrdog (contributor, neutral, 2 statements 2026-10-28 to 2026-10-30): requested squashing commits and suggested adding Fixes to PR description
Files
41 lines under test/bench/ci.
- src/util/fs.cpp +47/-4
- src/test/fs_tests.cpp +41/-0
Card
The short text the ranking pass compares across PRs.
Makes files opened with fsbridge::fopen non-inheritable across process boundaries by appending 'e' on Linux, 'N' on Windows, and falling back to open() with O_CLOEXEC and fdopen() on other POSIX platforms. This prevents file descriptors from leaking into child processes spawned for external signers or notification hooks. The change addresses issue #36668 and includes unit tests checking the handle flags on Windows and POSIX.
Data
thread read through 2026-10-30 (16 statements), head 17ea8dd818
labels: Utils/log/libs
Categories
Utilities (logging, arguments, libraries)
P3 · bug fix (ranking pass: Moved up: descriptor leaks into spawned signer/notification processes are a security-hygiene issue in a shared file primitive.)
Prevents file descriptor leaks by ensuring fsbridge::fopen sets close-on-exec/non-inheritable flags across platforms. The problem description notes handles 'remain inheritable across process boundaries by default, risking descriptor leaks into child processes executed by Bitcoin Core (such as external signers or notification scripts)'. This is worthwhile security hygiene and robustness for utility primitives, but deferrable as it is not actively causing critical failures.
Membership: Matches the 'Utils/log/libs' label and edits src/util/fs.cpp to harden shared filesystem wrapper primitives.
Factors: security/stability 1, bug 1, performance 0, user value 0, leverage 0