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

disklabel64 read-path trust: crafted-media partition fields yield OOB absolute-media-offset I/O β€” cross-slice access, mod-2^64 wraparound slice escape, and ds_reserved EROFS label-area write bypass (concrete impact upgrade of DF-0134)

Field Value
ID DF-2910
Status new
Severity Medium
CVSS 3.1 CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H
CWE CWE-20 / CWE-1284
File sys/kern/subr_disklabel64.c
Lines 183-193 (consumer: subr_diskslice.c:206-212, 280-281)
Area kern/disk
Confidence certain
Discovered 2026-09-02
Pass 2 (GLM 5.3 second pass)
Bucket base:kern
Reported pending
Known CVE none
CVE match novel

Summary

l64_readdisklabel accepts any CRC-valid on-media disklabel64 with completely uncontained p_boffset/p_bsize/d_bbase/d_total_size (only magic, d_npartitions≀16 and CRC are checked; whole struct copied in-core). The kernel auto-parses such labels at media attach for BSD-typed MBR slices and creates partition devices for them. dscheck then routes partition I/O via l64_getpartbounds computing nbio->bio_offset = (sp->ds_offset + slicerel_secno) * dss_secsize with NO containment check against sp->ds_size and mod-2^64 wrap β€” unlike the WHOLE_DISK/WHOLE_SLICE branches which use ds_size. Demonstrated on the guest (vn, 3/3 deterministic): (a) cross-slice read β€” /dev/vn0s1a of a 1MiB slice with p_boffset=2MiB returned slice s2's marker at abs LBA 6144; (b) backwards wraparound β€” p_boffset=2^64-983040 made the kernel report media_offset=65536 and /dev/vn0s1b read abs LBA 128, BEFORE the slice start; (c) universal window β€” one partition with p_boffset=p_bsize=2^64-512 yields a 2^55-1-sector window whose user-relative seeks map to arbitrary absolute offsets; (d) EROFS bypass β€” a write to slice-rel sector 1 via the whole-slice device is correctly rejected EROFS, but the same byte via the crafted partition succeeded and clobbered the on-disk label magic at abs LBA 2049 ('PWNED-PARTITION-WRITE' read back raw). No panic, guest stable β€” DF-0134's old 'offset overflow panic' speculation disproven; the real impact is clean, kernel-mediated OOB read/write at attacker-chosen absolute media offsets. Not kernel-memory corruption; no unprivileged local trigger (partition nodes root:operator 0640; install path separately bounded per DF-0135). Attacker crafts media; root/automount attaches β†’ cross-slice data theft and targeted corruption (MBR, foreign labels, other OS partitions) on that disk.

Proof of contest

VERIFIED (findings/poc/DF-2910/): makeimg.py builds the crafted 16MiB image; all four primitives observed 3/3 on stock kernel #0 (cross-slice marker, wraparound LBA-128 marker, universal window, EROFS bypass write at abs LBA 2049). Fix validated on rebuilt kernel #1: crafted label rejected ('cannot find label (disklabel64 corrupted, partition)'), valid contained label still installs with working I/O and intact EROFS. user→root: N/A — disk-data redirection, not kernel memory corruption; escalation ceiling is corruption of other slices' data (e.g. another OS partition's setuid binaries) on media root attaches.

Structural validation in l64_readdisklabel (total/boot area and every partition sector-aligned, no-wrap, contained within sp->ds_size Γ— secsize) β€” validated fix.diff in findings/poc/DF-2910/.

Timeline

  • 2026-09-02 Discovered during pass-2 audit of subr_disklabel64.c (GLM 5.3); all four primitives reproduced + fix validated same run.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2910 Β· 20 files
FileTypeDescriptionSize
README.md β€” 3.6 KB ↓ raw
VERDICT.md β€” 5.2 KB ↓ raw
makeimg.py β€” 5.5 KB view raw
df2910.img β€” 16.0 MB ↓ download
valid.img β€” 16.0 MB ↓ download
probe.c β€” 722 B view raw
wprobe.c β€” 740 B view raw
dump.c β€” 950 B view raw
pinfo.c β€” 599 B view raw
run.sh β€” 1.5 KB view raw
run.log β€” 1.9 KB view raw
run.2.log β€” 1.9 KB view raw
run.3.log β€” 1.9 KB view raw
run.fixed.log β€” 552 B view raw
run.fixed2.log β€” 582 B view raw
build.log β€” 4.6 KB view raw
env.txt β€” 266 B view raw
fix.diff β€” 2.5 KB view raw
verdict.json β€” 5.5 KB view raw
manifest.json β€” 1.4 KB view raw

DF-2910 β€” disklabel64 read-path trust β†’ arbitrary absolute-media-offset I/O via partition devices of crafted media

Impact upgrade of DF-0134 (which established the missing structural validation; this pack concretely demonstrates and fixes the resulting I/O redirection primitives).

What was proven (baseline, stock INVARIANTS kernel #0, 3/3 deterministic runs)

Attacker-controlled media (image file / USB disk) containing a CRC-valid disklabel64 with uncontained partition fields is auto-parsed by the kernel at attach time (disk_probe β†’ disk_probe_slice, sys/kern/subr_disk.c:491). l64_readdisklabel (sys/kern/subr_disklabel64.c:145-201) checks only magic / d_npartitions<=16 / CRC β€” never bounds. Partition devices are then created, and dscheck (sys/kern/subr_diskslice.c:206-212,280-281) routes their I/O using (sp->ds_offset + slicerel_secno) * dss_secsize β€” mod-2^64 arithmetic with no containment check against the slice:

  1. Cross-slice read/write β€” p_boffset beyond the slice end: /dev/vn0s1a (partition of the 1 MiB slice s1) reads/writes slice s2's data at absolute LBA 6144. β†’ slice isolation broken; a mounted attacker slice can read/modify other slices of the same disk (e.g. an OS partition, the running system's raw data).
  2. Wraparound slice escape (backwards) β€” p_boffset = 2^64-983040: (2048 + 2^55-1920)*512 mod 2^64 = 65536 β†’ /dev/vn0s1b reads absolute LBA 128, before the slice start (kernel itself reports media_offset=65536 via DIOCGPART).
  3. Universal window β€” one partition p_boffset = p_bsize = 2^64-512 yields a 2^55-sector window (media_offset=LBA 2047, media_blocks=2^55-1); the user's own partition-relative seek selects the absolute target.
  4. EROFS label-area protection bypass β€” writing slice-rel sector 1 via the whole-slice device is correctly rejected EROFS (ds_reserved=8), but the same byte written through the crafted partition (slicerel_secno β‰ˆ 2^55 β†’ not < ds_reserved) succeeds: write(/dev/vn0s1c, sec=2) = 512 and the on-disk label magic at absolute LBA 2049 is overwritten ("PWNED-PARTITION-WRITE" on raw read-back).

No panic; guest stays up; primitives are fully controlled read/write at attacker-chosen absolute media offsets. Ceiling: with root attaching/opening attacker media (automount, vnconfig, USB), all slice/label protections on that disk are void β€” cross-slice data theft and targeted corruption (MBR, foreign labels, other OS's data). It is disk-data redirection, not kernel-memory corruption.

Build / run (in guest, as root)

# host: generate the crafted image (python3, no deps)
python3 makeimg.py df2910.img
# guest: attach; kernel auto-probes the crafted label
vnconfig -c vn0 /root/df2910.img
sh run.sh          # full sequence: dump label, 3 read primitives, EROFS control+bypass

Expected (vulnerable kernel): SLICE2-SECRET-MARKER via vn0s1a, SECTOR128-SECRET-MARKER via vn0s1b, EROFS via vn0s1 control, write=512 ok via vn0s1c and PWNED-PARTITION-WRITE at raw LBA 2049.

Expected (patched kernel): vn0s1: cannot find label (disklabel64 corrupted, partition) in the message buffer; only /dev/vn0s1 exists; every primitive absent; valid labels (valid.img) still install with working partition I/O and EROFS intact.

Fix

fix.diff adds structural validation to l64_readdisklabel (label total/boot-area and every partition bounded within sp->ds_size * secsize, sector-aligned, wrap-safe sums). Validated in-guest: baseline reproduces, patched kernel rejects the crafted label and accepts valid ones (run.fixed.log, run.fixed2.log).

VERDICT.md
↓ download raw

DF-2910 VERDICT β€” reproduced / OOB I/O (disk-data redirection, slice escape, EROFS bypass)

Classification

  • status: reproduced (3/3 deterministic baseline runs; no panic; guest stable)
  • impact: dos-level ceiling is not the point β€” this is out-of-bounds I/O: kernel-mediated read/write at attacker-chosen absolute media offsets through partition devices created from attacker-crafted media. Not kernel-memory corruption; disk-data boundary break.
  • confidence: certain β€” every step traced to source and demonstrated empirically.

Root cause chain (path:line)

  1. sys/kern/subr_disk.c:491 β€” every BSD-type MBR slice is label-probed at attach (disk_probe_slice), zero user interaction beyond media presence.
  2. sys/kern/subr_disklabel64.c:183-187 β€” l64_readdisklabel validates only d_magic, d_npartitions<=16, CRC. p_boffset/p_bsize/d_bbase/d_total_size are never checked against the media/slice (this is the DF-0134 gap).
  3. sys/kern/subr_disk.c:228-269 β€” partition devices are created for every partition with nonzero p_fstype, regardless of geometry.
  4. sys/kern/subr_diskslice.c:206-212 β€” dscheck takes start/blocks straight from l64_getpartbounds (subr_disklabel64.c:64-82) with no clamp to sp->ds_size (contrast the WHOLE_DISK/WHOLE_SLICE branches at :189/:197 which use ds_size).
  5. sys/kern/subr_diskslice.c:280-281 β€” nbio->bio_offset = (off_t)(sp->ds_offset + slicerel_secno) * ssp->dss_secsize β€” mod-2^64 arithmetic: huge p_boffset wraps the product to any small absolute offset; the EROFS reserved check at :227 (slicerel_secno < sp->ds_reserved) never fires because the wrapped slicerel_secno is astronomically large.

What was demonstrated (baseline, kernel #0 stock INVARIANTS)

  • Cross-slice read: /dev/vn0s1a (partition of 1 MiB slice s1, p_boffset=2 MiB) returned SLICE2-SECRET-MARKER living in slice s2 (abs LBA 6144) β€” run.log Β§1.
  • Wraparound backwards read: p_boffset=0xffffffffff10000 β†’ kernel-reported media_offset=65536 (DIOCGPART) β†’ /dev/vn0s1b returned the marker at abs LBA 128, before the slice start β€” run.log Β§2.
  • Universal window: p_boffset=p_bsize=0xfffffffffffffe00 β†’ media_blocks=2^55-1 (16 EiB) partition whose user-relative seeks map to arbitrary absolute offsets β€” run.log Β§3/pinfo.
  • EROFS bypass write: control write via /dev/vn0s1 at slice-rel sec 1 β†’ EROFS (errno 30); identical byte via /dev/vn0s1c at sec 2 β†’ write()=512 ok, raw read-back at abs LBA 2049 shows PWNED-PARTITION-WRITE β€” the on-disk label magic clobbered through a partition device. run.log Β§4-6.
  • Stable across runs (run.log, run.2.log, run.3.log); guest alive; no panic.

Threat model

Unprivileged attacker supplies the media (USB stick, disk image, cloud volume); root (or an automount daemon) attaches it and the kernel auto-parses the label. Partition devices appear root:operator 0640. Root opening/mounting the crafted slice gives the attacker cross-slice read/write of the same physical disk β€” including the MBR, foreign labels, and other OS partitions β€” plus voiding of the label-area EROFS protection. On the PoC guest the trigger is vnconfig (root). Severity Medium: powerful primitive, but requires privileged attach/open of attacker media (no unprivileged local trigger found; the DIOCSDINFO/WDINFO64 install path is separately bounds-checked in l64_setdisklabel modulo DF-0135).

PoC changes vs. seed

Seed sketch did not exist (finding filed from this run). Generator initially computed the wrap p_boffset as target - ds_offset*512 per-partition; corrected after guest ground-truth (DIOCGPART media_offset) showed the general form: backwards reach comes from (ds_offset + p_boffset/512)*512 mod 2^64 β€” best expressed as one partition with p_boffset = p_bsize = 2^64-512 plus a user seek. CRC32 is zlib-compatible (sys/libkern/crc32.c table = 0xEDB88320 reflected).

Fix validation (mandatory β€” memory-boundary class)

  • fix.diff: structural validation in l64_readdisklabel (total/boot-area contained; each partition sector-aligned, p_boffset<=slicebsize, p_bsize<=slicebsize, p_boffset+p_bsize<=slicebsize β€” terms bounded first so the sum cannot wrap).
  • Baseline reproduced on kernel #0; guest vm.sh reset with-src, patch applied to /usr/src, make -j6 nativekernel && make installkernel, reboot β†’ kernel #1.
  • Patched result: kernel log vn0s1: cannot find label (disklabel64 corrupted, partition); no vn0s1a/b/c devices; all primitives absent (run.fixed.log, run.fixed2.log); label magic at LBA 2049 intact.
  • No false positives: a fully-contained label (valid.img) is accepted on the patched kernel; vn1s1a created with correct in-slice media_offset, read/write round-trip works, EROFS reserved protection enforced (EROFS on whole-slice write at sec 1).
  • Note: on the patched kernel an unlabeled slice has ds_reserved=0, so whole-slice writes into the (absent) label area succeed β€” pre-existing behavior for label-less slices, not a regression of this fix.

fix_status: fixed β€” baseline reproduced / patched behavior gone / valid labels unaffected.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

vm.sh reset with-src; fix.diff applied to guest /usr/src; make -j6 nativekernel + make installkernel; reboot into kernel #1. Crafted label now rejected ('vn0s1: cannot find label (disklabel64 corrupted, partition)'), no vn0s1a/b/c devices, label magic intact, all OOB primitives absent. Valid contained label (valid.img) still accepted with correct in-slice media_offset, working read/write, and EROFS reserved protection enforced.

['findings/poc/DF-2910/run.fixed.log', 'findings/poc/DF-2910/run.fixed2.log', 'findings/poc/DF-2910/build.log', 'findings/poc/DF-2910/fix.diff']
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Thu Sep 3 07:29:24 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64

Confirmed kernel references

Detail

Exploit chain

1) attacker crafts media: MBR slice type 0xA5 containing disklabel64 with CRC-valid but uncontained partitions; 2) root attaches (vnconfig -c / USB automount) -> kernel auto-probes (subr_disk.c:491) and creates partition devices; 3) read/write via e.g. /dev/vn0s1a (p_boffset beyond slice) hits other slices' data; 4) p_boffset near 2^64 wraps dscheck's offset arithmetic to arbitrary small absolute offsets incl. before the slice start; 5) p_boffset=p_bsize=2^64-512 gives a universal window (media_blocks=2^55-1) where user seeks choose the absolute target; 6) wraparound makes slicerel_secno huge so the ds_reserved EROFS check never fires -> write to the label/MBR area through a partition device.

Evidence (decisive lines)

['findings/poc/DF-2910/run.log Β§1: SLICE2-SECRET-MARKER read via /dev/vn0s1a (cross-slice)', 'findings/poc/DF-2910/run.log Β§2: SECTOR128-SECRET-MARKER read via /dev/vn0s1b (wrap to pre-slice LBA 128; DIOCGPART media_offset=65536)', 'findings/poc/DF-2910/run.log Β§4-6: control write EROFS errno=30 vs bypass write()=512 ok via /dev/vn0s1c; raw LBA 2049 shows PWNED-PARTITION-WRITE', "findings/poc/DF-2910/run.fixed.log: patched kernel logs 'vn0s1: cannot find label (disklabel64 corrupted, partition)'; DIOCGDINFO64 -> EINVAL; no vn0s1a/b/c", 'findings/poc/DF-2910/run.fixed2.log + VERDICT.md: valid.img label still accepted on patched kernel, partition I/O round-trips, EROFS enforced', 'findings/poc/DF-2910/makeimg.py: image generator with exact struct packing and zlib CRC32']

PoC changes

No seed existed; written fresh. Initial generator expressed the wrap as per-target p_boffset=target-ds_offset*512; guest ground truth (DIOCGPART) showed the general primitive is one partition with p_boffset=p_bsize=2^64-512 plus user-relative seeks; corrected accordingly. dd error lines must not be truncated (tail swallowed EROFS errors) - wprobe.c uses write(2) and prints errno.

Verified recommended fix

Validate on-media disklabel64 structure in l64_readdisklabel: label total/boot area and every partition sector-aligned and contained within sp->ds_size*secsize with wrap-safe sums (see fix.diff).

Verdict

l64_readdisklabel (sys/kern/subr_disklabel64.c:183-187) accepts any CRC-valid on-media disklabel64 with uncontained p_boffset/p_bsize; dscheck (sys/kern/subr_diskslice.c:280-281) then routes partition I/O at (ds_offset+slicerel)*secsize with mod-2^64 wrap and no slice containment. Demonstrated on the stock guest via vn: cross-slice read of another slice's data, backwards wraparound read to pre-slice absolute LBA 128 (kernel-reported media_offset=65536), a single 2^55-sector universal-window partition, and a write through a partition device that clobbers the on-disk label magic while the identical whole-slice write is EROFS-rejected. Impact is disk-data redirection (slice isolation + label-area EROFS protection voided for crafted media), not kernel memory corruption; trigger requires root to attach/open attacker media (vnconfig/automount), so Medium. Concrete impact upgrade of DF-0134. Fix validated: structural bounds in the read path reject the crafted label (kernel #1) while valid labels still install and EROFS protection still works.