DragonFlyBSD Kernel Audit
DF-0031 / fix_run.log
← back to finding ↓ download raw
=== DF-0031 PoC + regression test on PATCHED single-fix kernel #1 ===
Kernel: DragonFly 6.5-DEVELOPMENT #1: Sun Jul 12 22:43:48 UTC 2026
        BuildID[sha1]=949f92eeaf07bb84d765a22c915e4d89a3e795b5
        sha256(/boot/kernel/kernel)=635a182de371ae97cf645669811dbd8d3cdf57f46f3580570edd2d2cf385a0db

Fix applied: pipe_create() now sets pipe->open_count = 2 BEFORE the two pipespace() calls
             (sys/kern/sys_pipe.c:434), removing the late assignment at the old :445.
             => on a partial pipespace() failure, kern_pipe's double-pipeclose() cleanup
                decrements 2->1->0 and the second call (old==1) frees/caches the pipe,
                instead of underflowing 0->0xFFFFFFFF->0xFFFFFFFE and leaking.

--- Regression test: 5000 pipe write/read round-trips ---
OK: 5000 pipe write/read round-trips passed    (no functional regression)

--- PoC on patched kernel (timeout 25s) ---
[*] holding 32526 pipe fds to build kernel_map pressure
[*] opened=0  failures(likely underflow-leak path)=1000000
[*] check `vmstat -z` / pipe zone and kernel_map free space for cumulative KVA/struct leak
RUN_EXIT=0
(Same EMFILE behavior as baseline: the 1M failures are falloc() EMFILE at sys_pipe.c:292-297
 from exhausting kern.maxfilesperproc=32528, NOT the unreachable 2nd-pipespace ENOMEM path.
 No panic, no crash. kvm_free stable at ~8.79 TB before and after.)

--- Guest status: up, healthy (uptime 53 secs) ---

=== Fix validation verdict: not_testable (bug path unreachable on default config) ===
The leak precondition (kernel_map exhaustion -> 2nd pipespace ENOMEM) cannot be triggered by
an unprivileged user: kern.maxfilesperproc=32528 / kern.maxfiles=130112 cap system-wide pipes
at ~65K (~4 GB KVA) vs vm.kvm_size=8.8 TB. So there is no observable bad behavior on EITHER
the unpatched or patched kernel to contrast. The fix is validated by:
  (1) git apply --check passes;
  (2) make -j6 nativekernel rc=0 (no errors/warnings);
  (3) kernel boots (#1, new BuildID);
  (4) 5000-pipe regression test passes (no functional regression);
  (5) source inspection confirms the error path now decrements cleanly (2->1->0, 2nd frees).