โฌข DragonFlyBSD Kernel Audit
โ† dashboard
DF-0108

Unvalidated d_secsize in writedisklabel enables oversized I/O transfer

Field Value
ID DF-0108
Status new
Severity Low
CVSS 3.1 CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:L/A:H
CWE CWE-787 Out-of-bounds Write
File sys/kern/subr_disklabel32.c
Lines 336-341
Area kern
Confidence medium
Discovered 2026-06-30
Reported pending

Summary

l32_writedisklabel uses lp->d_secsize directly as bp->b_bcount (:340) and as a loop bound (:360), with only a KKASSERT (no-op on production kernels) to verify it fits in the buffer. A user who supplies a label with d_secsize exceeding the pbuf's b_bufsize can trigger an oversized I/O transfer, potentially corrupting kernel memory depending on the device strategy routine.

Root cause

l32_writedisklabel at :336-340:

KKASSERT((int)lp->d_secsize <= bp->b_bufsize);
bp->b_bio1.bio_offset = (off_t)LABELSECTOR32 * lp->d_secsize;
...
bp->b_bcount = lp->d_secsize;

KKASSERT is #ifdef INVARIANTS only (sys/sys/systm.h:94-118) โ€” a no-op on production kernels. lp->d_secsize comes from the new label supplied via DIOCWDINFO ioctl. If d_secsize exceeds bp->b_bufsize (typically MAXPHYS = 128KB), the strategy routine receives b_bcount > b_bufsize.

Additionally, the loop bound at :359-360:

((char *)bp->b_data + lp->d_secsize - sizeof(*dlp))

If d_secsize < sizeof(*dlp) (e.g. 0), the pointer arithmetic wraps, making the loop condition enormous โ€” though the first iteration reads bp->b_data which is valid, limiting immediate impact.

Threat model & preconditions

  • Attacker position: Root or operator with write access to disk device node.
  • Impact: Potential kernel memory corruption via oversized I/O. Severity depends on the underlying device driver's handling of b_bcount > b_bufsize.
  • Required config: Production kernel (no INVARIANTS).
  • Reachability: ioctl(fd, DIOCWDINFO32, &label) where label has d_secsize > MAXPHYS and p_offset[RAW_PART] == 0.

Proof of concept

PoC source: findings/poc/DF-0108/ (scaffold)

Build & run

cc -o poc_secsize poc_secsize.c
sudo ./poc_secsize /dev/da0s1

Expected output

Depends on driver behavior: kernel panic, memory corruption, or silent data transfer past buffer end.

Impact

Low. Requires root/operator privileges. Whether the oversized transfer actually corrupts memory depends on the specific disk driver โ€” many drivers clamp b_bcount to b_bufsize internally. This is primarily a hardening gap.

Replace the KKASSERT with a real validation:

--- a/sys/kern/subr_disklabel32.c
+++ b/sys/kern/subr_disklabel32.c
@@ -333,7 +333,10 @@
    if (lp->d_partitions[RAW_PART].p_offset != 0)
        return (EXDEV);         /* not quite right */

-   bp = getpbuf_mem(NULL);
+   bp = getpbuf_mem(NULL);
+   if (lp->d_secsize < DEV_BSIZE || lp->d_secsize > bp->b_bufsize)
+       return (EINVAL);
+
    KKASSERT((int)lp->d_secsize <= bp->b_bufsize);
    bp->b_bio1.bio_offset = (off_t)LABELSECTOR32 * lp->d_secsize;

Timeline

  • 2026-06-30 Discovered during automated audit.