DF-3114 / verdict.json
{ "finding_id": "DF-3114", "status": "reproduced", "reproduced": 1, "impact": "none", "confidence": "certain", "verdict": "Reproduced on the audit guest: GETHISTORY with ATKEY key=nxt_key=0x7fffffffffffffff returns rc=0 with the files ENTIRE TID history (entries=3, flags=ATKEY|EOF) for a key offset at which no record can exist - the ++cursor.key_beg.key at hammer_ioctl.c:354 signed-overflows and wraps to INT64_MIN, starting the scan at the files first record. Correct result is 0 entries or EINVAL. As GETHISTORY is simultaneously ungated (DF-3112), any local user can trigger this. No memory-unsafety: add_history bounds-guards every hist_ary write (hammer_ioctl.c:470,493) and the cursor stays pinned to the open files obj_id/localization. Patched kernel returns EINVAL. The latent swallowed-EINVAL for non-REGFILE/DIR/DBFILE obj types (hammer_ioctl.c:367-370 overwritten at :386) is unreachable from userland (fifo vnodes route ioctls through soo_ioctl) but is fixed by the same diff.", "exploit_chain": "none (validation defect; disclosure limited to the callers own open files history TIDs)", "evidence": [ "findings/poc/DF-3114/run.log: [H] rc=0 entries=3 flags=0x9 as uid 1001", "findings/poc/DF-3114/run.root.log: identical wrap as root", "findings/poc/DF-3114/run.patched.root.log: [H] -> rc=-1 errno=22 (EINVAL) on the fix-built kernel", "findings/poc/DF-3114/fix.diff: reject key >= HAMMER_MAX_KEY in ATKEY validation + honor the obj_type switch error" ], "kernel_refs": [ "sys/vfs/hammer/hammer_ioctl.c:296", "sys/vfs/hammer/hammer_ioctl.c:352", "sys/vfs/hammer/hammer_ioctl.c:354", "sys/vfs/hammer/hammer_ioctl.c:367", "sys/vfs/hammer/hammer_ioctl.c:386", "sys/vfs/hammer/hammer_ioctl.c:419" ], "poc_changes": "Wrote from scratch (test [H] of the shared PoC). Needed the keep argv mode for the patched-kernel root run because DF-3112s fix gates GETHISTORY, making the EINVAL observable only when the gate is legitimately passed.", "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": 1380, "guest_dirty": 1, "build_cmd": "cc -I/usr/src/sys -o /tmp/poc /tmp/hammer_gate_poc.c", "run_cmd": "/tmp/poc /mnt/h1/histfile (test [H]; stock kernel: any user; patched kernel: root + keep)", "code_hash": "464fd8750494ffbfc0d5c269cc6d830527553311e503554d07ef7a7ae56f459e", "notes": "Key-arithmetic wrap family of DF-3111 (namekey wrap) at a new site, with no memory-safety consequence. Three-run stability confirmed. Baseline file history built with three write+`hammer synctid` cycles (TIDs 0x100008020/60/a0).", "recommended_fix": "Reject hist->key >= HAMMER_MAX_KEY in the ATKEY validation and return the obj_type switchs EINVAL instead of overwriting it with hammer_btree_first()s return.", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Sun Sep 6 13:09:37 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Patched kernel (fix.diff merged into the combined validation diff, rebuilt, rebooted): test [H] returns EINVAL (rc=-1 errno=22) as root; the wrap no longer occurs.", "fix_evidence": [ "findings/poc/DF-3114/run.patched.root.log", "findings/poc/DF-3114/fix.diff", "findings/poc/DF-3112/fix_combined_for_validation.diff" ] } |