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

hptv2 metadata writeback: 2048-byte write from a 512-byte heap buffer persists ~1.5KB of kernel heap to disk (OOB read -> durable info leak)

Summary

ata_raid_hptv2_write_meta kmallocs sizeof(struct hptv2_raid_conf)=512B but writes sizeof(struct promise_raid_conf)=2048B to every member disk - ata_raid_rw DMAs bcount bytes from the buffer, persisting 1536 bytes of adjacent kernel heap into fixed sectors (LBA 9..12) on every writeback. write_metadata routes BOTH HPTv2 and HPTv3 formats here; writeback fires on every status change (boot 0->READY, mirror loss, subdisk detach, spare ops). Vendor-gated to HighPoint controllers so not runnable on this Intel-only guest: inconclusive, source certain (compile-time-constant size mismatch proven by compiling the packed struct from the real header).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3693 Β· 6 files
FileTypeDescriptionSize
README.md β€” 2.4 KB ↓ raw
VERDICT.md β€” 2.1 KB ↓ raw
analysis.txt β€” 1.9 KB view raw
fix.diff β€” 3.6 KB view raw
verdict.json β€” 2.0 KB view raw
manifest.json β€” 2.4 KB view raw

DF-3693 β€” hptv2 metadata writeback reads 2048 bytes out of a 512-byte heap buffer and persists them to disk (kernel heap disclosure)

Root cause (source)

ata_raid_hptv2_write_meta (sys/dev/disk/nata/ata-raid.c:1897-1983) allocates sizeof(struct hptv2_raid_conf) = 512 bytes (:1903-1904) but issues the write with sizeof(struct promise_raid_conf) = 2048 bytes:

1903:  meta = (struct hptv2_raid_conf *)kmalloc(sizeof(struct hptv2_raid_conf), M_AR, M_WAITOK | M_ZERO);
...
1972:       if (ata_raid_rw(rdp->disks[disk].dev,
1973:               HPTV2_LBA(rdp->disks[disk].dev), meta,
1974:               sizeof(struct promise_raid_conf),      /* 2048 != 512 */
1975:               ATA_R_WRITE | ATA_R_DIRECT)) {

ata_raid_rw DMAs bcount bytes from meta to the disk (request->data = data; request->bytecount = bcount;), so 1536 bytes of kernel heap past the allocation are written into the member disks' metadata sectors (LBA 9..12). Sizes verified by compiling the packed structs from the real header on the guest (sizeof hptv2=512, sizeof promise=2048).

write_metadata routes both AR_F_HPTV2_RAID and AR_F_HPTV3_RAID arrays here (:1492-1498). The writeback fires on every array-state change (ata_raid_config_changed:977-998 forces writeback when status changes β€” e.g. 0β†’READY at boot, mirror loss, disk detach :4179, spare insertion).

Impact

Kernel heap contents (adjacent allocation data β€” potentially pointers, file fragments, keys) are persisted to fixed disk sectors readable by anyone with raw access to the member disk (root/operator/physical/cloud-image inspection). CWE-125/CWE-200 (OOB read β†’ information exposure), plus corruption of the (unwritten-by-us) HPTv2 image area semantics.

Guest testability

The HPTv2/HPTv3 read parsers are only reached when pci_get_vendor(GRANDPARENT(...)) == ATA_HIGHPOINT_ID (ata_raid_read_metadata:1416-1420), i.e. on HighPoint controllers. This QEMU guest has only an Intel PIIX3 IDE controller, so the format can never be instantiated here β†’ verdict inconclusive (not testable on this hardware), confidence in the source analysis remains certain (buffer-size mismatch is compile-time constant; sizes confirmed on the guest toolchain).

Fix

fix.diff hunk: use sizeof(struct hptv2_raid_conf) for the write length.

Files

analysis.txt (struct size transcript from the guest), fix.diff, verdict.json

VERDICT.md
↓ download raw

DF-3693 VERDICT

Status: inconclusive (runtime) / certain (source). impact: leak (not demonstrated at runtime on this hardware).

Why inconclusive at runtime

The HPTv2/HPTv3 parsers are vendor-gated on ATA_HIGHPOINT_ID (ata-raid.c:1416-1420). The audit guest exposes only an Intel PIIX3 IDE controller (QEMU default), so AR_F_HPTV2_RAID/AR_F_HPTV3_RAID can never be instantiated and ata_raid_hptv2_write_meta cannot be reached. No other reachable route exists (write_metadata dispatches purely on rdp->format).

Why the source claim is certain

  • kmalloc(sizeof(struct hptv2_raid_conf)) = 512 bytes (verified by compiling the packed struct from the real header with the guest's cc β€” see analysis.txt).
  • The write passes sizeof(struct promise_raid_conf) = 2048 bytes to ata_raid_rw, which sets request->data = data; request->bytecount = bcount and DMAs that many bytes from the buffer to disk (ata-raid.c:4087-4131, 1972-1975).
  • 1536 bytes beyond the allocation are therefore persisted into LBA 9..12 of every member disk, on every forced writeback (status change at boot, subdisk detach :4179, spare add, generation bumps).
  • The overflow is compile-time-constant; there is no path-sensitive condition to dispute.

Impact ceiling

Kernel-heap-content disclosure to persistent storage. The metadata sectors are world-position-stable (HPTV2_LBA = 9) and re-readable by whoever controls the disk later (operator/physical/cloud-image). Adjacent M_AR / kmem allocations can contain pointers and file data. No write primitive, no direct kernel-execution path β†’ Medium.

Fix

One-line: use sizeof(struct hptv2_raid_conf) as the write length (included in fix.diff; not behaviorally validated on this guest for the hardware reason above β€” fix_status = not_testable with this stated reason).

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

not_testable
baseline no→ patch + rebuild →patched clean

one-line constant change included in fix.diff; cannot be behaviorally validated on this guest (no HighPoint controller)

fix.diff hunk '@@ -1971,7 +1998,7 @@'
↓ fix.diffper-fix-DF-3693

Confirmed kernel references

Detail

Evidence (decisive lines)

analysis.txt (guest-compiled sizeof transcript: hptv2=512, promise=2048; vendor gating trace; writeback trigger trace)

PoC changes

no PoC possible on this hardware; layout verification tooling only

Verified recommended fix

write sizeof(struct hptv2_raid_conf) instead of sizeof(struct promise_raid_conf) (fix.diff hunk 7)

Verdict

ata_raid_hptv2_write_meta kmallocs 512 bytes (sizeof hptv2_raid_conf, verified by compiling the packed struct from the real header on the guest) but writes sizeof(promise_raid_conf)=2048 bytes to each member disk, persisting 1536 bytes of adjacent kernel heap into fixed metadata sectors (LBA 9..12) on every writeback (boot status change, subdisk detach, spare ops). Runtime test impossible on this guest: HPTv2/HPTv3 formats are PCI-vendor-gated to HighPoint controllers and the guest has only Intel PIIX3 IDE. Buffer-size mismatch is compile-time constant - source analysis certain.