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)
PoC verification
Evidence pack
findings/poc/DF-1175 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
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.
Recommended fix
Cap the loop iteration count to the actual buffer size in both parsers. See
fix.diff.
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
nataraidisoptional(sys/conf/files:143), not inX86_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_testablecompile+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.
No comments yet.