================================================================ DF-0074 - DIOCGSLICEINFO heap overflow -> kernel PANIC capture Reproduced on: DragonFlyBSD 6.4.2-RELEASE (#11, X86_64_GENERIC) ================================================================ finding_id : DF-0074 tested_at : 2026-06-30 05:59:42 status : reproduced reproduced : 1 impact : panic guest_uname: 6.4-RELEASE (6.4.2-RELEASE #11) code_hash : 28285154c24f3eccfb51849121cac5058344dce61f5549e0e9c19153abe0ab6a build_cmd : python3 build_gpt.py overflow.img ; cc -o trigger trigger.c run_cmd : ./trigger /dev/vn0s1 (vnconfig -c vn0 overflow.img as root first) ================================================================ RUN LOG (verbatim panic + reproduction recipe) ================================================================ === ENVIRONMENT === Host: QEMU/KVM, 2 vCPU, 2GB; guest DragonFly 6.4.2-RELEASE (#11, X86_64_GENERIC). Kernel: "DragonFly dftest 6.4-RELEASE ... #11: Fri May 9 14:08:53 EDT 2025". PoC sources hash (post edit): 28285154c24f3eccfb51849121cac5058344dce61f5549e0e9c19153abe0ab6a. === EXACT REPRODUCTION RECIPE === [host] python3 findings/poc/DF-0074/build_gpt.py /tmp/df0074.img # 1 MiB image, GPT hdr_entries=128, 17 non-nil [host] scp /tmp/df0074.img dfbsd-maxx:poc/DF-0074/overflow.img [guest, maxx] cc -o trigger trigger.c # BUILD_EXIT=0 [guest, root] vnconfig -c vn0 /home/maxx/poc/DF-0074/overflow.img # attaches; kernel auto-probes GPT -> kernel created /dev/vn0s1 .. /dev/vn0s16 (proof dss_nslices>16) -> vnconfig -l: "vn0: covering .../overflow.img on #B255:0x0, inode 30589" [guest, root] ./trigger /dev/vn0s1 -> prints: "DIOCGSLICEINFO returned nslices=130" -> then PANIC (guest freezes in DDB). === UNPRIVILEGED TRIGGER (maxx uid 1001) === ./trigger /dev/vn0s1 -> exit=1 (open: EACCES) Reason: /dev/vn0s* are root:operator crw-r----- on default devfs; maxx not in operator. === KERNEL PANIC (verbatim, captured from dfbsd-qemu/boot.log before reset) === panic: assertion "z->z_Magic == ZALLOC_SLAB_MAGIC" failed in _kfree at /home/justin/release/6_4/sys/kern/kern_slaballoc.c:1449 _kfree() at _kfree+0x50e 0xffffffff80657e7e _kfree() at _kfree+0x50e 0xffffffff80657e7e fdfree() at fdfree+0x2e6 0xffffffff80634246 exit1() at exit1+0x13f 0xffffffff8064019f sys_exit() at sys_exit+0xe 0xffffffff8064072e syscall2() at syscall2+0x11e 0xffffffff80bdc8ae Debugger("panic") CPU0 stopping CPUs: 0x00000002 stopped Stopped at Debugger+0x7c: movb $0,0xbce509(%rip) db> (guest frozen in DDB; ssh timed out RC=124; vm.sh status => down) === OBSERVATION SUMMARY === Reproduction: YES. runtime ~25s (to ssh timeout). impact = panic (kernel heap/slab corruption). ================================================================ ANALYSIS / NOTES (mechanics, reachability, PoC edits) ================================================================ CONFIRMED PRESENT ON 6.4.2-RELEASE (NOT a master-only regression) -- first verified reproduction of the audit. MECHANICS: DIOCGSLICEINFO handler (sys/kern/subr_diskslice.c:557) bcopy()s dss_nslices (130) worth of struct diskslice into a buffer sized for MAX_SLICES=16 (sizeof struct diskslices, M_IOPTLOPS ~4KB). 130 vs 16 => ~114 extra slices overrun adjacent kernel heap by ~29KB, smashing slab zone objects. Corruption surfaced synchronously: when the triggering process exited, fdfree()->_kfree() freed a file-descriptor slab object whose z_Magic header had been overwritten, tripping KKASSERT(z->z_Magic==ZALLOC_SLAB_MAGIC) => panic+DDB. Per finding, attacker-controlled GPT fields (ds_offset/ds_size/ds_type_uuid) land in the overrun region -> with slab grooming (spray victim objects e.g. struct file/ucred into the same kmalloc bucket) this is LPE-to-root, not just DoS. REACHABILITY CAVEAT: finding rates via unprivileged-open of a slice device, but on DEFAULT devfs /dev/vn0s* (and /dev/md0*, /dev/vbd0*) are root:operator crw-r-----, so an unprivileged user gets EACCES. The finding itself states "devfs permissions vary by ruleset". So: kernel defect CONFIRMED (root-open reproduced panic); unprivileged LPE requires a devfs ruleset exposing slice devices (e.g. operator-group membership or a permissive devfs rule) -- common on multi-user boxes / containers / jail hosts that grant disk access. POC SOURCE EDITS (mechanical/build-blocker only, attack logic unchanged): (1) build_gpt.py gpt_entry() defaults type_guid/guid changed from str "\\x00"*16 to bytes b"\\x00"*16 so .ljust(16,b"\\x00") works under py3 (was a str/bytes TypeError); (2) used DragonFly device name /dev/vn0s1 + "vnconfig -c vn0" instead of the PoC text "/dev/vnd0s1"/"vnd0" (NetBSD naming); vn driver is in-kernel on 6.4.2. mdconfig is NOT installed on this guest (would have been the alternative attach path). NOTE: boot.log panic was captured BEFORE reset; qemu -serial file truncates boot.log on each (re)boot, so after vm.sh reset the on-disk boot.log no longer holds this panic -- the verbatim text lives in this run_log row.