{
  "finding_id": "DF-5696",
  "status": "reproduced",
  "reproduced": true,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Reproduced in the userland differential rig on the DragonFly guest (verbatim sys/libkern/qsort.c, sha256-pinned, compiled by the guests own gcc 8.3): partition byte-distances are kept in int variables (qsort.c:109); at a 2,160,000,000-byte partition the truncated (int)r = -2,134,967,296 passes the if ((r = pd - pc) > es) guard because r (int) is promoted to size_t against es, so a = pn - r; n = r / es; goto loop restarts the sort with the array pointer 2,134,967,296 bytes PAST the end and n ~ 2^64 - the comparator then receives args at base+7,894,967,296 and base+7,628,096,384 (an OOB read in any dereferencing comparator; the following swap(a, pm) is an 8-byte OOB write). Second family member demonstrated at 17.2 GiB: d = (n/8)*es wraps int and med3 feeds the comparator a pointer 2,144,967,296 bytes BELOW the array. Patched variant (size_t d/r2, size_t swapfunc n) sorts the identical 5.76 GiB input correctly (8.8e9 comparisons, 222 s) and shows 0 OOB med3 args. In-tree kernel reachability today: NONE - all five callers (ext2_htree.c:587, linux_sort.c:36, vinumio.c:760, ng_ppp.c:1747, ng_ppp7:2292) sort at most a few KB, far below the 2.16 GiB threshold - so impact is a latent primitive memory-corruption defect (severity Low), not a live kernel bug. Differential fuzz (28k arrays incl. odd es, unaligned bases, kqsort_r thunk checks) and 7k adversarial-comparator runs show all other behavior byte-identical to libc and memory-safe.",
  "exploit_chain": "",
  "evidence": "run.log (guest, full matrix, ALL_EXPECTATIONS_MET): lines with TRUNCATION OOB CONFIRMED ... x-base=7894967296 y-base=7628096384, PATCHED(f6) ... patched: array IS SORTED, OOB COMPARATOR ARGS CONFIRMED ... y-base=-2144967296 ... n*es=17200000000; VERDICT.md (byte-for-byte offset derivation vs the trace); fix.diff (size_t d/r2 + size_t swapfunc n); env.txt (guest uname, gcc, pinned sha256 of both kernel files); guest_build.log (sha pin verified against /usr/src)",
  "kernel_refs": [
    "sys/libkern/qsort.c:109",
    "sys/libkern/qsort.c:125",
    "sys/libkern/qsort.c:132",
    "sys/libkern/qsort.c:169-172",
    "sys/libkern/qsort.c:173",
    "sys/libkern/qsort.c:179-183",
    "sys/libkern/qsort.c:63",
    "sys/libkern/qsort_r.c:9",
    "sys/vfs/ext2fs/ext2_htree.c:587",
    "sys/dev/drm/linux_sort.c:36",
    "sys/dev/raid/vinum/vinumio.c:760",
    "sys/netgraph/ppp/ng_ppp.c:1747",
    "sys/netgraph7/ppp/ng_ppp.c:2292"
  ],
  "poc_changes": "Authored the rig from scratch (the finding had no seed PoC): verbatim-source compilation with symbol renames, bounds/alignment-checking counting comparator with ring-buffer arg tracing, byte canaries with absolute-pattern phase (an initial slice-relative phase bug produced false canary hits and was fixed after standalone replay disproved them), fork-based verdict exits, chunked MAP_FIXED contiguous mapping helper, patched-variant A/B. Trace mode added to decompose the exact wild-pointer origin; the observed mechanism (unsigned promotion through > es) is stronger than the initially suspected mis-sort.",
  "attempts": 4,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "runtime_sec": 418,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh (host, zig cc 18.1.6) ; sh guest_build.sh (guest cc 8.3, /usr/src verbatim + sha pin)",
  "run_cmd": "sh guest_run.sh (guest: fuzz/fuzz_lie/truncate/med3_oob/med3_oob_fixed/es0_*) ; sh run.sh (host small modes)",
  "code_hash": "05be04f52c6ac1e9c92a8bad7674ec985256615c9740d0b65a48bc4082aa085e",
  "notes": "Big-array modes need >=8 GiB RAM: the guest was temporarily booted with -m 12288 (vm.sh restored to 4096 and guest reset with-src after the run). The audit host sandbox gates >=3 GiB single mmaps for freshly built binaries (deterministic per-binary, cause not identified), which is why the decisive runs are guest-side. Member-2 demo touches only ~2 pages of a 17.2 GiB NORESERVE mapping (DragonFly lacks MAP_NORESERVE; rig defines it to 0 there). exit codes: 9 = truncate OOB confirmed, 3 = med3 OOB confirmed, 7 = es0 hang (DF-5697).",
  "recommended_fix": "Keep partition byte-distances and swapfuncs n in size_t: int r, swaptype, swap_cnt; size_t d, r2; with r2 used for the min()/vecswap/recursion/goto distances and swapfunc(char*, char*, size_t, int) - fixes kqsort and kqsort_r identically via the shared body (fix.diff).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Validated by same-input A/B on the guest: verbatim source exits with confirmed OOB comparator args (base+7,894,967,296 / base+7,628,096,384 on the 5.76 GiB input; y-base=-2,144,967,296 on the 17.2 GiB med3 input), while the patched source (fix.diff applied to the identical verbatim copy) sorts the same 5.76 GiB input correctly (8,795,877,536 comparisons) and shows 0 OOB med3 args in the first 1000 calls; 28k-iteration differential fuzz confirms the patched variant is still byte-identical to libc qsort. A patched-kernel build was not applicable: no in-tree caller can reach the >=2.16 GiB threshold, so a kernel build would show no observable delta.",
  "fix_evidence": "run.log: TRUNCATION OOB CONFIRMED ...  (verbatim) vs PATCHED(f6): ... patched: array IS SORTED; OOB COMPARATOR ARGS CONFIRMED ... y-base=-2144967296 vs PATCHED med3: 0 OOB comparator args in first 1000 calls; run_host.log: fuzz 20000 OK with f6 included; fix.diff in this pack"
}