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

INQUIRY/READ_CAPACITY/SERVICE_ACTION_IN write fixed-size replies past dxfer_len-sized kernel buffer

Summary

OsSendCommand at entry.c:2709 SetInquiryData writes 36 bytes to data_ptr. READ_CAPACITY (:2715) writes 8 bytes. SERVICE_ACTION_IN (:2740) writes 12 bytes. cam_periph_mapmem allocates kernel bounce buffer of exactly dxfer_len bytes. Small dxfer_len (e.g. 4) -> heap OOB write of 4-28 bytes past allocation. INQUIRY value partially attacker-influenced on RAID via array info. READ_CAPACITY cap value from disk size. Fix: validate dxfer_len >= expected reply size.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1285 Β· 8 files
FileTypeDescriptionSize
trigger_analysis.c trigger-source documentation marker 1.1 KB view raw
fix.diff suggested-fix validate dxfer_len against reply size in INQUIRY/READ_CAPACITY/SERVICE_ACTION_IN cases 1.3 KB view raw
build.sh build-script syntax-checks the marker 432 B view raw
run.sh run-script documents INCONCLUSIVE status 647 B view raw
combined_build.log build-log combined X86_64_GENERIC rebuild log; rc=0 5.6 MB ↓ download
env.txt environment uname, pciconf -l, kldstat -v 1015 B view raw
README.md readme human-readable summary (also corrects brief's hptrr -> hptmv) 3.0 KB ↓ raw
VERDICT.md verdict detailed source-level analysis 3.6 KB ↓ raw
README.md readme human-readable summary (also corrects brief's hptrr -> hptmv)
↓ download raw

DF-1285 β€” hptmv OsSendCommand writes fixed-size replies past small dxfer_len buffer

Finding

OsSendCommand at sys/dev/raid/hptmv/entry.c:2678 handles three SCSI CDB types by writing fixed-size replies directly into ccb->csio.data_ptr:

  • INQUIRY (entry.c:2709) β€” SetInquiryData() fills sizeof(INQUIRYDATA) (= 96 bytes, defined in osbsd.h:68-90) into the buffer.
  • READ_CAPACITY (entry.c:2715) β€” writes 8 bytes via rbuf[0..7].
  • SERVICE_ACTION_IN (0x9e) (entry.c:2740) β€” writes 12 bytes via rbuf[0..11].

CAM's cam_periph_mapmem allocates the kernel bounce buffer at exactly dxfer_len bytes (the user-specified transfer length). If the user issues one of these CDBs with a smaller dxfer_len than the reply (e.g. dxfer_len=4 for INQUIRY), the writes overflow the allocation by 4..92 bytes.

The INQUIRY data is partially attacker-influenced on RAID arrays (array membership strings from pVDev->VDeviceType flow into the VendorId/ProductId/ProductRevisionLevel memcpy's at entry.c:2595-2620); the READ_CAPACITY / SERVICE_ACTION_IN values are derived from pVDev->VDeviceCapacity (disk size). The overflow bytes therefore are not fully attacker-shaped, but the start of the overwrite is a fixed pattern ("RR18xx ", "3.00", etc.) and the size is controlled.

Fix

Validate csio->dxfer_len against the actual reply size before writing, and return CAM_REQ_INVALID if the buffer is too small. Do this in each of the three cases.

Note on the file vs the brief

The brief calls this "hptrr" β€” that is wrong. The vulnerable file is sys/dev/raid/hptmv/entry.c (the hptmv driver β€” Highpoint RocketRAID 182x). The DB row's file column is correct.

Verification on this guest

  • The hptmv driver is statically compiled in (device hptmv in sys/config/X86_64_GENERIC:119) and shows up in kldstat -v (pci/hptmv).
  • The QEMU guest has no Marvell 88SX508x / Highpoint PCI device (pciconf -l shows only i440FX/PIIX/ACPI/virtio-net/virtio-blk/std-VGA). hptmv_probe never matches, so hptmv_attach and the xpt_bus_register -> OsSendCommand path never run. The bug is not runtime-triggerable on this guest.
  • Source-level confirmation:
  • osbsd.h:68-90 β€” INQUIRYDATA is 96 bytes (5 + 1 + 1 + 8 + 16 + 4 + 20 + 40 + 1).
  • entry.c:2710-2711 β€” ZeroMemory(data_ptr, dxfer_len) then SetInquiryData writes the full struct.
  • entry.c:2717-2734 β€” READ_CAPACITY writes 8 bytes via rbuf[0..7].
  • entry.c:2742-2756 β€” SERVICE_ACTION_IN writes 12 bytes via rbuf[0..11].
  • Fix verified to compile (combined build with DF-1278/1279/1280/1287).

Realistic impact ceiling

Local-user-controllable heap OOB write of 4..92 bytes if an hptmv-managed disk is exposed to a low-privileged user via the CAM pass(4) device or a filesystem on top of an hptmv disk. The byte pattern at the overwrite start is fixed ("RR18xx " or zero from ZeroMemory) β€” i.e. not fully attacker-shaped, but the size is. Slab layout is unknown until triggered.

VERDICT.md verdict detailed source-level analysis
↓ download raw

VERDICT β€” DF-1285

Status

INCONCLUSIVE (source-confirmed; not runtime-triggerable on this guest).

Mechanism (source-confirmed)

OsSendCommand at sys/dev/raid/hptmv/entry.c:2678 handles three SCSI CDB types by writing fixed-size replies directly into ccb->csio.data_ptr:

CDB Lines Bytes written Source
INQUIRY (0x12) entry.c:2709 96 SetInquiryData fills INQUIRYDATA (osbsd.h:68-90)
READ_CAPACITY (0x25) entry.c:2715 8 rbuf[0..7]
SERVICE_ACTION_IN (0x9e) entry.c:2740 12 rbuf[0..11]

CAM's cam_periph_mapmem allocates the kernel bounce buffer at exactly dxfer_len bytes (the user-specified transfer length). If the user issues one of these CDBs with a smaller dxfer_len than the reply (e.g. dxfer_len=4 for INQUIRY), the writes overflow the allocation by 4..92 bytes.

The INQUIRY data is partially attacker-influenced on RAID arrays β€” array membership strings from pVDev->VDeviceType flow into the VendorId/ProductId/ProductRevisionLevel memcpy's at entry.c:2595-2620 ("RR18xx ", "RAID 0 Array ", "3.00", etc.). The READ_CAPACITY / SERVICE_ACTION_IN values are derived from pVDev->VDeviceCapacity (disk size). The overflow bytes therefore are not fully attacker-shaped, but the size and the start pattern are controlled.

Note on the file vs the brief

The task brief calls this "hptrr" β€” that is wrong. The vulnerable file is sys/dev/raid/hptmv/entry.c (the hptmv driver β€” Highpoint RocketRAID 182x, based on the Marvell 88SX508x chipset). The DB findings.file column is correct.

Fix

Validate csio->dxfer_len against the actual reply size before writing, and return CAM_REQ_INVALID if the buffer is too small. Do this in each of the three cases. See fix.diff.

Verification on this guest

  • hptmv is statically compiled in (device hptmv in sys/config/X86_64_GENERIC:119) and shows up in kldstat -v (pci/hptmv).
  • No Marvell 88SX508x / Highpoint PCI device in pciconf -l (only i440FX/PIIX/ACPI/virtio-net/virtio-blk/std-VGA), so hptmv_probe never matches and OsSendCommand is never called. Not runtime-triggerable.
  • Fix validation: combined X86_64_GENERIC rebuild with this fix applied exited rc=0. Full log: combined_build.log.

Exploit chain

None on this guest (no HW). On a system with an hptmv-managed disk exposed via CAM pass(4) or a filesystem on top of an hptmv disk, an unprivileged user could trigger a heap OOB write of 4..92 bytes by issuing an INQUIRY/READ_CAPACITY/SERVICE_ACTION_IN with a small dxfer_len. The overwrite start pattern is partially fixed ("RR18xx " or zeros from ZeroMemory); the size is fully controlled. No escalation was attempted because the path is unreachable on this guest.

Realistic impact ceiling

Local-user heap OOB write of 4..92 bytes on systems presenting an hptmv disk to unprivileged users. CVSS: AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N (local, requires the rare hptmv-deployed machine + permissive CAM access).

PoC changes

Folder was empty; added trigger_analysis.c, build.sh, run.sh, README.md, this VERDICT.md, fix.diff, manifest.json, combined_build.log.

Matches the finding proposal: validate dxfer_len against the expected reply size in each of the three cases. See fix.diff.

Fix status

not_testable β€” bug requires absent hardware. fix.diff applies cleanly and compiles into X86_64_GENERIC (combined build rc=0).

Fix verification

not_testable

compile validated

nativekernel rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. hptmv INQUIRY/READ_CAPACITY/SERVICE_ACTION_IN fixed-size writes vs dxfer_len -> heap OOB. hptmv in GENERIC, no HW.