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

Intel and nVidia parsers: unbounded config_size in checksum loop causes kernel OOB read / panic

Summary

Intel parser at :2151-2154: checksum loop iterates meta->config_size/4 u32 words from 1536-byte meta buffer. nVidia parser at :3046-3048: iterates meta->config_size from ~500-byte meta buffer. config_size is u32 from disk (up to 0xFFFFFFFF). Large value -> kernel OOB read past kmalloc into unmapped page -> panic. Magic only gate; no valid checksum needed since loop faults before comparison. Attacker: crafted Intel/nVidia disk. Fix: cap iteration to actual buffer size.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1175 Β· 11 files
FileTypeDescriptionSize
harness.c trigger-source userspace reconstruction of Intel + nVidia checksum loops with oversized config_size 6.5 KB view raw
build.sh build-script cc -O2 -Wall -o harness harness.c 214 B view raw
run.sh run-script ./harness 71 B view raw
build.log build-log successful in-guest build 87 B view raw
run.log run-log harness output: Intel + nVidia OOB-read magnitudes 1.0 KB view raw
env.txt environment uname, struct sizes, module-build validation summary 794 B view raw
fix.diff suggested-fix cap Intel/nVidia checksum loops to actual buffer sizes 1.8 KB view raw
VERDICT.md verdict full narrative + module-build validation 4.3 KB ↓ raw
README.md readme human-facing summary 3.8 KB ↓ raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
README.md readme human-facing summary
↓ download raw

DF-1175 β€” Intel/nVidia RAID metadata parser OOB read

Finding

Two checksum loops in sys/dev/disk/nata/ata-raid.c use a disk-controlled u_int32_t config_size field as their iteration bound, with only a small fixed-size kmalloc buffer to read into. A crafted metadata block with a large config_size causes the loop to read far past the allocation into unmapped kernel memory, producing a page-fault panic (DoS) β€” and for small over-reads, an info leak of slab-trailing kernel heap bytes.

Intel parser (ata_raid_intel_read_meta, line 2120)

/* ata-raid.c:2132 */  meta = kmalloc(1536, M_AR, M_WAITOK | M_ZERO);
...
/* ata-raid.c:2145 */  if (strncmp(meta->intel_id, INTEL_MAGIC, ...)) goto out;
...
/* ata-raid.c:2151-2154 */
for (checksum = 0, ptr = (u_int32_t *)meta, count = 0;
     count < (meta->config_size / sizeof(u_int32_t)); count++)
    checksum += *ptr++;

config_size is a u_int32_t from disk (ata-raid.h:307). The buffer is 1536 bytes but the loop will read up to config_size bytes (config_size/4 u32 words). A config_size of 0x10000 β†’ 64000-byte OOB read.

nVidia parser (ata_raid_nvidia_read_meta, line 3018)

/* ata-raid.c:3028 */  meta = kmalloc(sizeof(struct nvidia_raid_conf), ...);
...
/* ata-raid.c:3039 */  if (strncmp(meta->nvidia_id, NV_MAGIC, ...)) goto out;
...
/* ata-raid.c:3046-3048 */
for (checksum = 0, ptr = (u_int32_t*)meta, count = 0;
     count < meta->config_size; count++)
    checksum += *ptr++;

config_size is a u_int32_t from disk (ata-raid.h:592). The buffer is 512 bytes (verified sizeof(struct nvidia_raid_conf) == 512 in-guest), but the loop reads config_size u32 words = 4 * config_size bytes. A config_size of 0x400 β†’ 3584-byte OOB read.

Reachability without a valid checksum

In both parsers, the magic-string check runs BEFORE the loop (Intel:2145, nVidia:3039), but the checksum verification runs AFTER (Intel:2156, nVidia:3049). An attacker only needs to satisfy the 8/24-byte magic; the loop faults before the checksum is compared, so a self-consistent checksum is not required.

Reproducibility on the audit guest

Same constraints as DF-1174: nataraid is optional (sys/conf/files:143), not in X86_64_GENERIC; the module ships at /boot/kernel/nataraid.ko; the QEMU guest uses virtio-blk (not ATA), so the parsers never run on guest disks. Live triggering would require rebooting QEMU with an added IDE disk image containing crafted metadata.

A userspace harness (harness.c) reconstructs both loops with the exact kmalloc sizes (1536 / 512) and a matching magic, and drives them with an oversized config_size. Run on the guest (./build.sh && ./run.sh):

=== Case 1: Intel parser (ata-raid.c:2132-2154) ===
  meta = kmalloc(1536); magic OK; config_size = 0x10000 (65536)
  loop will run 16384 iterations, reading 65536 bytes (buffer = 1536 bytes -> 64000-byte OOB read)
  magic check: PASS (matches INTEL_MAGIC)
  BUG: OOB read faulted (signal 11) -- kernel equivalent: page fault past kmalloc(1536) ...

=== Case 2: nVidia parser (ata-raid.c:3028-3048) ===
  meta = kmalloc(sizeof(nvidia_raid_conf)=512); magic OK; config_size = 0x400 (1024)
  loop will run 1024 iterations, reading 4096 bytes (buffer = 512 bytes -> 3584-byte OOB read)
  magic check: PASS (matches NV_MAGIC)
  BUG: OOB read faulted (signal 11) -- kernel equivalent: page fault past kmalloc(512) ...

Threat model

Same as DF-1174: an attacker who can supply a disk with crafted RAID metadata triggers an automatic kernel panic (or info leak) at the next driver probe. No privilege required beyond disk-write capability.

Severity Medium: requires the legacy nata stack (opt-in); not in GENERIC. High (panic + small info leak) for systems that load nata/nataraid.

Cap the loop iteration count to the actual buffer size in both parsers. See fix.diff.

VERDICT.md verdict full narrative + module-build validation
↓ download raw

DF-1175 β€” VERDICT

Verdict: REPRODUCED (source+harness, module-build-validated). Not uid=0 β€” this is an OOB read with info-leak + DoS impact in optional legacy ATA RAID metadata parsing.

Bug confirmation

Two checksum loops in sys/dev/disk/nata/ata-raid.c use a disk-controlled u_int32_t config_size field as their iteration bound against a small fixed-size kmalloc buffer.

Intel parser β€” ata_raid_intel_read_meta (line 2120)

/* ata-raid.c:2132 */  meta = kmalloc(1536, M_AR, M_WAITOK | M_ZERO);
/* ata-raid.c:2145 */  if (strncmp(meta->intel_id, INTEL_MAGIC, ...)) goto intel_out;
/* ata-raid.c:2151-2154 */
for (checksum = 0, ptr = (u_int32_t *)meta, count = 0;
     count < (meta->config_size / sizeof(u_int32_t)); count++)
    checksum += *ptr++;

config_size is u_int32_t config_size at ata-raid.h:307 (offset 56 in the on-disk struct, populated by ata_raid_rw). The buffer is 1536 bytes (384 u32 words). Any config_size > 1536 over-reads; config_size = 0xFFFFFFFF walks ~4 GB past the allocation before faulting.

nVidia parser β€” ata_raid_nvidia_read_meta (line 3018)

/* ata-raid.c:3028 */  meta = kmalloc(sizeof(struct nvidia_raid_conf), ...);
/* ata-raid.c:3039 */  if (strncmp(meta->nvidia_id, NV_MAGIC, ...)) goto nvidia_out;
/* ata-raid.c:3046-3048 */
for (checksum = 0, ptr = (u_int32_t*)meta, count = 0;
     count < meta->config_size; count++)
    checksum += *ptr++;

config_size is u_int32_t config_size at ata-raid.h:592. The buffer is 512 bytes (sizeof(struct nvidia_raid_conf) == 512, verified in-guest). The loop reads config_size u32 words = 4 * config_size bytes; a config_size of 0x400 reads 4096 bytes (3584-byte over-read).

Reachability without a valid checksum

Both parsers gate on the magic-string check (Intel:2145, nVidia:3039) before the loop, but verify the checksum (Intel:2156, nVidia:3049) after. An attacker needs only to satisfy the 8/24-byte magic; the loop faults (or over-reads) before the checksum is compared.

Reproducibility on the audit guest

  • nataraid is optional (sys/conf/files:143), not in X86_64_GENERIC. The module ships at /boot/kernel/nataraid.ko.
  • The QEMU guest uses virtio-blk (vtblk0), not ATA, so the parsers never run on guest disks. Live triggering would require rebooting QEMU with an added IDE/SATA disk image containing crafted metadata.

A userspace harness (harness.c) reconstructs both loops with the exact kmalloc sizes (1536 / 512) and matching magics, and drives them with oversized config_size values. Run on the guest:

=== Case 1: Intel parser ===
  meta = kmalloc(1536); magic OK; config_size = 0x10000 (65536)
  loop will run 16384 iterations, reading 65536 bytes (64000-byte OOB read)
  magic check: PASS
  (loop completed -- kernel equivalent: info leak of slab trailing bytes)

=== Case 2: nVidia parser ===
  meta = kmalloc(512); magic OK; config_size = 0x400 (1024)
  loop will run 1024 iterations, reading 4096 bytes (3584-byte OOB read)
  magic check: PASS
  (loop completed -- kernel equivalent: info leak of slab trailing bytes)

(Userspace callocd buffers are fully mapped so no SIGSEGV; in the kernel, a small over-read leaks slab-trailing bytes into the checksum, and a large over-read walks into unmapped pages and panics.)

Module build validation

The fix.diff was applied in-guest to /usr/src and make in /usr/src/sys/dev/disk/nata/nataraid produced a clean nataraid.ko (RC=0, -Werror). The patched source compiles. Source was then reverted.

Exploit chain

none β€” pure OOB read; not a write primitive. Impact ceiling: small info-leak of slab-trailing kernel heap bytes (would require a second primitive to exfiltrate the checksum), plus reliable DoS panic via large config_size.

Fix

fix.diff caps each loop's iteration count to the actual buffer size (1536/sizeof(u32) for Intel, sizeof(struct nvidia_raid_conf)/sizeof(u32) for nVidia). git apply --check passes against the audit tree; patched source compiles cleanly into nataraid.ko on the guest.

Threat model

Same as DF-1174: attacker supplies a disk with crafted RAID metadata; next driver probe over-reads and panics. No privilege beyond disk-write capability.

Severity Medium: requires legacy nata (opt-in); not in GENERIC. High (panic + small info leak) for systems that load nata/nataraid.

Fix verification

not_testable

compile+harness validated

module/object build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source+harness. nata Intel/nVidia parser config_size unbounded checksum loop -> OOB read. Not AMD GPU - nataraid.