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

Stack buffer overflow in hptiop_post_req_itl via unbounded SG list (HIGH_MEM_ACESS path)

Summary

hptiop_post_req_itl HIGH_MEM_ACESS branch at hptiop.c:2417-2457: stack struct hpt_iop_request_scsi_command req (64B, sg_list[1]). Loop :2432-2440 psg=req.sg_list; for(idx=0;idx<nsegs;idx++,psg++){psg->pci_address/size/eot=...} overflows stack for nsegs>1. nsegs from bus_dmamap_load up to max_sg_count(HBA-reported, typically 32+). Also bcopy(cdb,req.cdb,cdb_len) at :2442 overflows cdb[16]. Also bus_space_write_region_1 over-reads stack. Triggered when SRB DMA >=32GB (HPT_SRB_FLAG_HIGH_MEM_ACESS). Unprivileged: dd if=/dev/daX bs=128k. Fix: write SG entries directly to MMIO, clamp cdb_len.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1311 Β· 11 files
FileTypeDescriptionSize
VERDICT.md verdict source-trace verdict: stack sg_list[1] overflow in ITL submission path 3.5 KB ↓ raw
README.md readme build/run/expected (HBA-gated) + fix-validation steps 1.3 KB ↓ raw
trigger_path.c trigger-source documents the HBA-only trigger (multi-seg disk I/O) 1.5 KB view raw
fix.diff suggested-fix clamp max_sg_count + size on-stack request buffer for max SG + bound cdb bcopy 2.6 KB view raw
build.sh build-log documents the single-fix nativekernel+installkernel build 770 B view raw
run.sh run-log reachability check (nm/pciconf/dmesg) 717 B view raw
fix_build.log build-log FULL untrimmed nativekernel output, rc=0 (-Werror), all 5 fixes compile 5.6 MB ↓ download
run.log run-log baseline #0 reachability (no HBA, 81 hptiop symbols linked) 209 B view raw
env.txt environment guest uname, cc, PCI, CPU, module presence 2.2 KB view 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 build/run/expected (HBA-gated) + fix-validation steps
↓ download raw

DF-1311 β€” hptiop_post_req_itl stack buffer overflow

Build

No standalone PoC binary β€” the trigger lives inside the kernel driver (sys/dev/raid/hptiop/hptiop.c) and is only reachable on a host with a HighPoint RocketRAID 3xxx HBA attached. The deliverable is the fix:

./build.sh    # applies fix.diff and builds a single-fix GENERIC kernel

Run

./run.sh      # attempts the trigger path; expected: NOT reachable on this guest

Expected (bug present, on a host WITH the HBA)

A multi-segment SCSI transfer to a disk on a HighPoint RocketRAID 3xxx HBA overflows the on-stack struct hpt_iop_request_scsi_command (sg_list[1]) β†’ kernel stack corruption β†’ panic or worse.

On THIS guest (no HBA)

The driver is compiled into GENERIC but never attaches (no HighPoint PCI device). ./run.sh documents the unreachable path and exits. This is not_testable at runtime on the QEMU guest; the fix is compile- and boot-validated instead (see VERDICT.md, fix_build.log).

Reproduce the FIX validation

  1. scp fix.diff to the guest, cd /usr/src && patch -p1 < fix.diff
  2. make -j6 nativekernel KERNCONF=X86_64_GENERIC
  3. Install kernel.stripped β†’ /boot/kernel/kernel, reboot.
  4. Confirm guest boots cleanly (no new hptiop-related issues) and kern.version bumps to the rebuilt build.
VERDICT.md verdict source-trace verdict: stack sg_list[1] overflow in ITL submission path
↓ download raw

DF-1311 β€” hptiop_post_req_itl stack buffer overflow (HighPoint RocketRAID)

Verdict

NOT TESTABLE AT RUNTIME on this guest β€” confirmed real latent vulnerability in source.

The bug is genuine and the analysis is certain, but the vulnerable I/O path can only execute on a machine with a HighPoint RocketRAID 3xxx (ITL/IOP) HBA, which the QEMU audit guest does not have.

Mechanism (confirmed by source trace)

sys/dev/raid/hptiop/hptiop.c:2401 hptiop_post_req_itl() is the ITL-family firmware SCSI-command submission callback. In the HPT_SRB_FLAG_HIGH_MEM_ACESS branch (line 2417) it builds the request in a stack-local struct hpt_iop_request_scsi_command req;.

That struct (sys/dev/raid/hptiop/hptiop.h:301) contains:

u_int8_t cdb[16];
...
struct hpt_iopsg sg_list[1];   /* only ONE scatter/gather slot */
  • Scatter/gather overflow: line 2432-2440 loops idx < nsegs, advancing a psg pointer into req.sg_list and writing pci_address/size/eot per segment. nsegs comes from bus_dmamap_load and is bounded only by hba->max_sg_count (set verbatim from HBA firmware iop_config.max_sg_count at line 1933, with no upper clamp). A typical HBA reports 30+ segments, so any multi-segment transfer writes nsegs-1 16-byte struct hpt_iopsg entries past the 1-entry stack array β†’ kernel stack overflow.
  • CDB overflow: line 2442 bcopy(cdb, req.cdb, ccb->csio.cdb_len) copies cdb_len (up to MAX_CDBLEN=16 via CAM, but controllable through the CDB pointer path) into cdb[16] with no length check β†’ off-by/overflow of cdb.

hptiop is compiled statically into X86_64_GENERIC (device hptiop), but the function is dead code unless the driver actually attaches to a HighPoint PCI device β€” which requires the physical HBA.

Why it does not reproduce on this guest

  • pciconf -l: the only PCI devices are i440FX/PIIX3/virtio and a QEMU std-VGA (1234:1111). No HighPoint RAID controller is present.
  • dmesg shows no hptiop attach. nm /boot/kernel/kernel | grep -c hptiop shows the code is linked (81 symbols) but never executed.
  • No CAM bus for hptiop exists, so no userspace ioctl/pass/da path can deliver a CCB to hptiop_post_req_itl. This is "needs specific HW" (case d).

Severity / realistic ceiling

On a host with a HighPoint RocketRAID 3xxx HBA, this is a kernel stack buffer overflow reachable by ordinary multi-segment disk I/O (no privilege beyond access to a disk on the HBA). Worst case is kernel stack corruption β†’ panic or potential code execution depending on what the overflowed sg_list/cdb overwrite (saved frame pointer / return address are within reach for large nsegs). The CVSS in the finding (AV:L/AC:L/PR:L) is appropriate.

Fix (see fix.diff)

  1. Clamp hba->max_sg_count to a compile-time HPTIOP_MAX_SG_COUNT (64) at attach so an absurd firmware value can't blow the stack buffer.
  2. Replace the fixed 1-entry stack struct with a stack byte-buffer sized for HPTIOP_MAX_SG_COUNT scatter/gather entries, accessed via a pointer.
  3. Bound the cdb bcopy to sizeof(req->cdb).

This is compiled-and-boot-validated on GENERIC (see build.log / fix_build.log); runtime behaviour cannot be exercised without the HBA.

Note on the brief's "mpr SAS" label

The job brief mislabeled DF-1298 as "mpr SAS"; DF-1298 is actually the amdgpu/display bios_parser.c. DF-1311 (this finding) is the HighPoint RAID driver hptiop. mpr is a different finding not in this batch.

Fix verification

not_testable

compile+boot validated -Werror

nativekernel rc=0, boots #1 clean
↓ fix.diffDragonFly 6.5-DEVELOPMENT #1: Fri Jul 17 11:03:53 UTC 2026

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. hptiop_post_req_itl stack sg_list[1] overflow via nsegs + cdb[16] overflow. hptiop in GENERIC, no HighPoint HBA.