β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3002

Forged btree leaf with data_offset==0: hammer_btree_extract returns cursor->data==NULL with error==0 (CRC skipped) β†’ NULL-deref kernel panics in readdir/readlink/nresolve/dounlink/strategy_read sinks on crafted HAMMER images

Field Value
ID DF-3002
Status new
Severity Low
CVSS 3.1 CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H
CWE CWE-476
File sys/vfs/hammer/hammer_vnops.c
Lines sinks :1734-1738, :1877-1880, :2866-2870, :1254-1255, :3343-3346 (root: hammer_btree.c:730)
Area vfs/hammer
Confidence certain
Discovered 2026-09-02
Pass 2 (GLM 5.3 second pass)
Bucket base:vfs
Reported pending
Known CVE none
CVE match novel

Summary

hammer_btree_extract reports SUCCESS with a NULL data pointer for a crafted record leaf whose data_offset is 0 β€” the leaf/data CRC is never computed on this path, so a crafted image (attacker owns the media CRCs anyway) passes straight through. This file's sinks then dereference it: readdir vop_write_dirent(cursor.data->entry.obj_id/ name), readlink uiomove(cursor.data->symlink.name, data_len), strategy_read bcopy(cursor.data + roff), nresolve bcmp, dounlink bcmp/obj_id read. Deterministic NULL-page kernel panic, INVARIANTS or not (the KKASSERT passes for any data_len>7). Crafted-media local DoS: mount of a maliciously modified HAMMER image (vnconfig + mount -t hammer; requires privilege to mount, the DF-2902-2912 crafted-media threat model), then one getdents/readlink/unlink/strategy on the forged directory panics the kernel. Not run (Low, crafted-image class); sink reachability source-deterministic. Fix: return EINVAL for data_off==0 (one-liner in hammer_btree.c).

Timeline

  • 2026-09-02 Discovered during pass-2 audit of hammer_vnops.c (GLM 5.3). DF-0769/DF-2698 re-verified, not re-reported.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3002 Β· 11 files
FileTypeDescriptionSize
README.md β€” 778 B ↓ raw
VERDICT.md β€” 2.2 KB ↓ raw
build.sh β€” 125 B view raw
df3002_run.log β€” 129 B view raw
env.txt β€” 401 B view raw
fix.diff β€” 387 B view raw
fix_run.log β€” 193 B view raw
h1patch2.py β€” 6.1 KB view raw
manifest.json β€” 759 B view raw
run.sh β€” 152 B view raw
verdict.json β€” 2.7 KB view raw

DF-3002 PoC evidence pack

What

Crafted leaf data_offset==0: hammer_btree_extract success + NULL data -> NULL-deref panics in readdir/nresolve.

Build

guest: newfs_hammer -f on 12G sparse vn image; host: python3 h1patch2.py IMG 3002 file_2902

Run

vnconfig -c vn0 IMG; mount_hammer /dev/vn0 /mnt/h1t; ls /mnt/h1t; ls -la /mnt/h1t/d  -> panic

Expected

Fatal trap 12, fault VA 0x0, hammer_vop_readdir+0x1e8 on ls of the crafted dir

Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 All logs are full untrimmed captures unless noted. fix.diff is the git-apply-able verified fix (authored after verification; never applied to the audit tree).

VERDICT.md
↓ download raw

DF-3002 - verification verdict

Status: reproduced | reproduced: 1 | impact: panic | confidence: certain

Crafted-image panic at the exact predicted sink. A HAMMER1 filesystem image was built with newfs_hammer, populated, then offline-patched (CRC32C-verified leaf matching; node CRCs recomputed via the v6-crc32 fallback the kernel accepts) so that the DIRENTRY leaf for d/file_2902 has data_offset == 0. hammer_btree_extract returns cursor->data = NULL with error == 0 (hammer_btree.c:705,:730 - the data CRC is never computed on this path). Mount succeeds clean; ls of the crafted directory dereferenced the NULL data pointer in kernel mode: Fatal trap 12, fault virtual address = 0x0, Stopped at hammer_vop_readdir+0x1e8 - the vop_write_dirent sink (:1734 area); nresolve/readlink/strategy_read sinks are the same NULL-data shape. Deterministic, INVARIANTS or not (KKASSERT at :1728 passes for data_len>7). Mount of crafted media requires privilege (DF-2902-2912 family threat model). Fix (EINVAL for data_off==0) A/B validated on the fix-all kernel.

Evidence pointers

df3002_panic.txt: Fatal trap 12 fault VA 0x0 Stopped at hammer_vop_readdir+0x1e8; df3002_run.log: mount clean, root ls ok, crafted-dir ls -> panic

Kernel references

PoC changes vs the filing sketch

wrote a scan-based offline patcher: b-tree leaf located by CRC32C-matching the direntry data blob; node CRC rewritten with v6 crc32 (accepted fallback)

Fix

recommendation: return EINVAL for data_off == 0 in hammer_btree_extract

fix status: fixed

A/B on fix-all kernel: same crafted image, readdir of crafted dir returns clean error (no panic)

Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

A/B on fix kernel #2: same crafted image mounts; ls of the crafted dir completes with rc=0 and the diagnostic hammer_btree_extract: illegal zero data_offset logged twice - NO panic (stock: NULL-deref at hammer_vop_readdir+0x1e8).

↓ fix.diffper-fix-DF-3002

Confirmed kernel references

Detail

Exploit chain

crafted HAMMER1 image with direntry leaf data_offset=0 -> mount (root) -> getdents on crafted dir -> hammer_btree_extract success+NULL -> vop_write_dirent deref NULL -> kernel page fault at 0x0

Evidence (decisive lines)

df3002_panic.txt: Fatal trap 12 fault VA 0x0 Stopped at hammer_vop_readdir+0x1e8; df3002_run.log: mount clean, root ls ok, crafted-dir ls -> panic

PoC changes

wrote a scan-based offline patcher: b-tree leaf located by CRC32C-matching the direntry data blob; node CRC rewritten with v6 crc32 (accepted fallback)

Verified recommended fix

return EINVAL for data_off == 0 in hammer_btree_extract

Verdict

Crafted-image panic at the exact predicted sink. A HAMMER1 filesystem image was built with newfs_hammer, populated, then offline-patched (CRC32C-verified leaf matching; node CRCs recomputed via the v6-crc32 fallback the kernel accepts) so that the DIRENTRY leaf for d/file_2902 has data_offset == 0. hammer_btree_extract returns cursor->data = NULL with error == 0 (hammer_btree.c:705,:730 - the data CRC is never computed on this path). Mount succeeds clean; ls of the crafted directory dereferenced the NULL data pointer in kernel mode: Fatal trap 12, fault virtual address = 0x0, Stopped at hammer_vop_readdir+0x1e8 - the vop_write_dirent sink (:1734 area); nresolve/readlink/strategy_read sinks are the same NULL-data shape. Deterministic, INVARIANTS or not (KKASSERT at :1728 passes for data_len>7). Mount of crafted media requires privilege (DF-2902-2912 family threat model). Fix (EINVAL for data_off==0) A/B validated on the fix-all kernel.