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

Unbounded md device auto-creation on open allows kernel memory exhaustion (DoS) by operator-group users

Summary

mdopen() auto-creates brand-new malloc md device whenever highest existing unit is opened: if(sc->unit+1==mdunits) mdcreate_malloc() (:135-136). Each new device allocates md_s devstat entry disk/cdev via disk_create and initial secp array mdunits incremented without cap (:410). Each freshly created /dev/mdN again 0640 root:operator so operator-group user can repeatedly open newest unit to force creation of unbounded number of md devices exhausting kernel memory and devstat slots system-wide DoS/panic. No MD_MAXUNITS-style limit anywhere in file. [VERIFIED pass2: reproduced - auto-create-on-open confirmed live creating md1, no cap anywhere; THREAT ARM REFUTED live - operator-group open is EPERM RESTRICTEDROOT so root-only growth; 256 cap compile-validated]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2478 Β· 8 files
FileTypeDescriptionSize
README.md β€” 1006 B ↓ raw
VERDICT.md β€” 1.9 KB ↓ raw
build.sh β€” 99 B view raw
run.log β€” 293 B view raw
env.txt β€” 963 B view raw
fix.diff β€” 1.2 KB view raw
manifest.json β€” 742 B view raw
verdict.json β€” 2.3 KB view raw

DF-2478 -- md auto-creation on open is unbounded (kernel memory exhaustion)

Verification used the shared rig tree at /root/rigs on the audit guest (see manifest). The rig for this finding: dfv_md (rig.c = harness, gen.sh = verbatim extractor, dfv_*_extract.h = generated production text). The decisive outputs below were captured live on the guest during the 2026-10-24 verification session; full session logs are summarized per run.

Build

sh build.sh            # extracts verbatim driver text + builds the KLD

Run (guest, root)

kldload ./dfv_rig.ko

kldload md (built-in); ./md_grow 3; ls /dev/md*; su -m operator_user -c dd if=/dev/md0 ...

Expected

run.log: /dev/md1 auto-created by opening /dev/md0; operator-group dd: Operation not permitted (EPERM) x3; root dd: 1+0 records in/out.

Fix validation

fix.diff caps the auto-create branch at mdunits < 256; explicit root creation stays unlimited.

Verdict: reproduced / impact=denial_of_service (see verdict.json, VERDICT.md)

VERDICT.md
↓ download raw

DF-2478 verdict -- md auto-creation on open is unbounded (kernel memory exhaustion)

status: reproduced reproduced: 1 impact: denial_of_service confidence: certain attempts: 1 runtime_sec: 300

Mechanism reproduced live on the stock kernel: opening the highest md unit auto-creates the next one (opening /dev/md0 produced /dev/md1 with a fresh md_s, devstat entry and cdev; mdopen md.c:135-136 fires whenever sc->unit+1 == mdunits and nothing caps mdunits anywhere in md.c). IMPORTANT threat-model correction, same gate as DF-2504: raw disk opens require SYSCAP_RESTRICTEDROOT (sys/kern/subr_disk.c:1070-1073) - a member of group operator gets EPERM opening /dev/md0 (demonstrated live, three attempts), so the filed unprivileged-operator exhaustion arm is REFUTED on current master; only root (or a RESTRICTEDROOT principal) can drive the growth, and root can already create units without limit by design (mdconfig). Effective severity: Low, privileged. Fix (cap auto-create at 256 units) compile-validated in the md module build.

Evidence (decisive lines)

before: /dev/md0 only after ./md_grow (opens md0): /dev/md0 /dev/md0s0 /dev/md1 /dev/md1s0 <- auto-created operator-group user (testuser, groups=wheel,operator): dd: /dev/md0: Operation not permitted (x3) <- RESTRICTEDROOT gate root: dd if=/dev/md1 ...: 1+0 records in, 1+0 records out

Exploit chain / privesc assessment

no unpriv path (RESTRICTEDROOT gate demonstrated); privileged resource-exhaustion only.

Fix + A/B

fix.diff caps the auto-create branch at mdunits < 256; explicit root creation stays unlimited.

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
↓ fix.diffper-fix-DF-2478

Confirmed kernel references

Detail

Exploit chain

no unpriv path (RESTRICTEDROOT gate demonstrated); privileged resource-exhaustion only.

Evidence (decisive lines)

run.log: /dev/md1 auto-created by opening /dev/md0; operator-group dd: Operation not permitted (EPERM) x3; root dd: 1+0 records in/out.

PoC changes

live guest test (no rig); unpriv arm refuted live; growth cap fix compile-validated.

Verified recommended fix

cap mdopen auto-creation at 256 units

Verdict

Mechanism reproduced live on the stock kernel: opening the highest md unit auto-creates the next one (opening /dev/md0 produced /dev/md1 with a fresh md_s, devstat entry and cdev; mdopen md.c:135-136 fires whenever sc->unit+1 == mdunits and nothing caps mdunits anywhere in md.c). IMPORTANT threat-model correction, same gate as DF-2504: raw disk opens require SYSCAP_RESTRICTEDROOT (sys/kern/subr_disk.c:1070-1073) - a member of group operator gets EPERM opening /dev/md0 (demonstrated live, three attempts), so the filed unprivileged-operator exhaustion arm is REFUTED on current master; only root (or a RESTRICTEDROOT principal) can drive the growth, and root can already create units without limit by design (mdconfig). Effective severity: Low, privileged. Fix (cap auto-create at 256 units) compile-validated in the md module build.