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

DIOCRECLUSTER has no privilege check and the kernel services dmsg peers with root credentials (raw RW with proc0.p_ucred, no open/keyid validation on I/O) β€” gated today only by diskopen's SYSCAP_RESTRICTEDROOT

Field Value
ID DF-2874
Status new
Severity Info
CVSS 3.1 CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N
CWE CWE-862 Missing Authorization
File sys/kern/subr_diskiocom.c
Lines 108-130 (root open :281-282; gate subr_disk.c:78-80)
Area kern
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

diskioctl forwards DIOCRECLUSTER with no priv_check and no FWRITE-on-node requirement; holdfp accepts any fd; disk_blk_open then does dev_dopen(rawdev, FREAD|FWRITE, SIFCHR, proc0.p_ucred) β€” the kernel opens the raw disk READ-WRITE with root credentials at the message peer's request β€” and the read/write/flush/freeblks handlers perform raw I/O with no BLK_OPEN/keyid validation. On this system the unprivileged chain is blocked because diskopen enforces SYSCAP_RESTRICTEDROOT on every disk-volume open (verified EPERM for operator-group) β€” filed as defense-in-depth: the entire dmsg peer trust model hangs on that one incidental gate. PoC verified the peer-position chain on stock (kernel opened the mounted raw boot disk RW; 4KB write landed on raw disk, md5-verified); unprivileged claim honestly not reproduced. Fix: explicit FWRITE gate on DIOCRECLUSTER.

Validated fix.diff in findings/poc/DF-2874/.

Timeline

  • 2026-09-02 Discovered during pass-2 audit of subr_diskiocom.c (GLM 5.3); peer chain reproduced + fix validated same run.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2874 Β· 12 files
FileTypeDescriptionSize
dfpeer.c β€” 15.4 KB view raw
run_f1.sh β€” 1.8 KB view raw
run_f1b.sh β€” 932 B view raw
run.log β€” 1.6 KB view raw
fix.diff β€” 664 B view raw
build.sh β€” 51 B view raw
run.sh β€” 391 B view raw
env.txt β€” 373 B view raw
VERDICT.md β€” 2.2 KB ↓ raw
run.fix.log β€” 456 B view raw
verdict.json β€” 2.7 KB view raw
README.md β€” 1.8 KB ↓ raw

DF-2874 β€” DIOCRECLUSTER: no privilege check; kernel opens the raw disk

FREAD|FWRITE with proc0.p_ucred on the dmsg peer's request (Info β€”

mitigated by diskopen's SYSCAP_RESTRICTEDROOT gate)

What this pack contains

  • dfpeer.c β€” dmsg wire peer; openwr mode issues BLK_OPEN(RD|WR) and prints the kernel's reply (error=0 = dev_dopen(rawdev, FREAD|FWRITE, S_IFCHR, proc0.p_ucred, ...) succeeded).
  • run_f1.sh β€” full chain attempt as an unprivileged operator-group user.
  • run_f1b.sh β€” the chain at the dmsg-peer position (root harness): BLK_OPEN(RD|WR) β†’ raw write through the channel β†’ root dd readback shows the payload on the raw disk.

Outcome

  • Peer position (verified): BLK_OPEN modes=3 -> reply error=0; a 4KB 0x5a write at gap offset 0x77F000000 lands on the raw disk (confirmed by root dd md5) and reads back through the channel.
  • Unprivileged position (blocked): a member of group operator cannot even open /dev/vbd0 read-only β€” diskopen() (sys/kern/subr_disk.c:78-80) enforces caps_priv_check_self(SYSCAP_RESTRICTEDROOT) on every disk volume open, so the ioctl path is effectively root-only on this system. The missing priv_check in diskioctl()/disk_iocom_ioctl() is therefore a defense-in-depth gap (the 0640 root:operator node perms and the absence of any FWRITE-on-node requirement would otherwise let an operator-group user turn read-only device access into kernel-mediated root-credential raw disk R/W).
  • Also demonstrated: disk_blk_write/disk_blk_read perform raw I/O with no BLK_OPEN/keyid validation at all β€” every message the iocom receives is executed with root credentials.

fix.diff

Require FWRITE on the device node for DIOCRECLUSTER (devfs then enforces write permission at open time), making the gate explicit instead of incidental.

VERDICT.md
↓ download raw

DF-2874 VERDICT

Status: not_reproduced for the unprivileged-escalation claim

(blocked by an external gate); the root-credential proxy behavior

itself is verified at the peer position.

Guest: DragonFly 6.5-DEVELOPMENT X86_64_GENERIC (env.txt).

What was verified

  1. Peer position (root harness == stand-in for a routed cluster node): BLK_OPEN modes=3 β†’ reply error=0, i.e. dev_dopen(dp->d_rawdev, FREAD|FWRITE, S_IFCHR, proc0.p_ucred, NULL, NULL) (sys/kern/subr_diskiocom.c:281-282) succeeded β€” the kernel opened the raw boot disk READ-WRITE with root credentials on the message peer's request, even though the device node perms are 0640 root:operator (no write for group) and the fs is mounted. A 4KB write through the channel landed on the raw disk (root dd md5-verified) and read back through the channel.
  2. No open validation for I/O: disk_blk_write/disk_blk_read/ _flush/_freeblks never check that a BLK_OPEN happened or validate keyid β€” every message the iocom receives executes raw I/O with root credentials.
  3. Unprivileged chain (blocked): user poc (member of group operator) cannot open /dev/vbd0 even read-only: diskopen() enforces caps_priv_check_self(SYSCAP_RESTRICTEDROOT) (sys/kern/subr_disk.c:78-80) on every disk-volume open, returning EPERM before the DIOCRECLUSTER branch in diskioctl is reachable. Therefore the missing priv_check/FWRITE requirement in diskioctl (subr_disk.c:1191) / disk_iocom_ioctl (subr_diskiocom.c:108-130) is currently mitigated by that gate. Had the gate not been there, 0640 root:operator + O_RDONLY would have been sufficient for operator→root-equivalent raw disk R/W.

Why filed as Info

The kernel-side authorization gap is real (no priv_check, arbitrary fd types accepted via holdfp, proc0.p_ucred raw opens, no peer revalidation), but on this system it is unreachable for unprivileged users. Defense-in-depth recommendation: require FWRITE on the node (devfs then enforces write permission) β€” fix.diff does exactly that.

Fix validation

fix.diff (FWRITE required for DIOCRECLUSTER) applied, kernel rebuilt: openwr via an O_RDONLY fd returns EPERM; via O_RDWR (root) still works (run.fix.log).

Fix verification

fixed
baseline no→ patch + rebuild →patched clean

Fix kernel: DIOCRECLUSTER via O_RDONLY fd returns EPERM; via O_RDWR (root) still works. Gate explicit.

['run.fix.log']
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Wed Sep 2 18:43:16 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (fix.diff applied, make nativekernel)

Confirmed kernel references

Detail

Evidence (decisive lines)

['run.log (BLK_OPEN modes=3 -> error=0; raw write md5-verified on disk; unpriv open EPERM)', 'VERDICT.md', 'run.fix.log (fixed: O_RDONLY ioctl -> EPERM, O_RDWR works)']

PoC changes

No seed; wrote dfpeer.c (openwr/write/read modes) plus the operator-user orchestration run_f1.sh/run_f1b.sh

Verified recommended fix

Require FWRITE on the device node for DIOCRECLUSTER so the gate is explicit (devfs then enforces write permission at open)

Verdict

The authorization gap is real at the kernel-service level - DIOCRECLUSTER has no priv_check and accepts any fd; BLK_OPEN then does dev_dopen(rawdev, FREAD|FWRITE, S_IFCHR, proc0.p_ucred, ...) (subr_diskiocom.c:281) and BLK_WRITE/READ/FLUSH/FREEBLKS execute raw I/O with zero open/keyid validation - and the peer-position chain was verified (BLK_OPEN error=0; a write through the channel landed on the raw boot disk and was md5-verified by root dd). BUT the unprivileged claim does not reproduce on this system: diskopen() gates every disk-volume open with caps_priv_check_self(SYSCAP_RESTRICTEDROOT) (subr_disk.c:78-80), so an operator-group user cannot even open /dev/vbd0 O_RDONLY (EPERM) and never reaches the ioctl. Filed as Info/defense-in-depth: had the gate not been there, 0640 root:operator + O_RDONLY would have sufficed for operator->root-equivalent raw disk R/W.