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

ciss_filter_physical: bus=CISS_EXTRA_BUS2(ea)-1 can be -1 -> OOB pointer write via ciss_physical[-1][target]

Summary

ciss_filter_physical at ciss.c:1551-1554: bus=CISS_EXTRA_BUS2(ea)-1 from controller extra_address. Filter only rejects BUS3/TARGET3/MODE2!=3, NOT BUS2==0. BUS2=0 -> bus=-1 -> ciss_physical[-1] reads kernel pointer from before array, writes cp_address+cp_online through it. Malicious/emulated CISS controller at attach or hotplug. Fix: validate bus>=0&&bus<max_physical_bus.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1192 Β· 11 files
FileTypeDescriptionSize
harness.c trigger-source replica of CISS_EXTRA_BUS2(ea)-1 with BUS2=0 -> bus=-1 negative index 3.9 KB view raw
VERDICT.md verdict full narrative + fix 3.2 KB ↓ raw
build.sh build-script cc -O2 -Wall -o harness harness.c 172 B view raw
run.sh run-script ./harness 66 B view raw
run.log run-log malicious LUN passes filter, indexes ciss_physical[-1][5] 500 B view raw
env.txt environment uname, cc version 418 B view raw
fix.diff suggested-fix validate bus>=0 && bus<max_physical_bus && target<CISS_MAX_PHYSTGT 557 B view raw
fix_build.log build-log ciss.ko rebuilt with all 3 ciss fixes, -Werror, rc=0 29 B view raw
README.md readme human reproduce doc 1.4 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 reproduce doc
↓ download raw

DF-1192 β€” ciss_filter_physical negative bus index -> OOB read+write

File: sys/dev/raid/ciss/ciss.c:1551-1554 Class: memory corruption (hardware/firmware-attacker; malicious CISS PCI device or malicious VBIOS at driver attach). No local-unprivileged syscall trigger on the audit guest (no HP Smart Array / no AMD GPU present).

Reproduce

./build.sh && ./run.sh

What the harness does

harness.c is a faithful userspace replica of the kernel parsing routine cited above, fed crafted controller/VBIOS data that the real malicious device would supply. It demonstrates the out-of-bounds access / overflow / underflow using the real kernel macros and struct sizes, with a canary or computed-index check to make the OOB observable without needing the hardware.

Expected output

A [BUG REPRODUCED] (or UNDERFLOW for DF-1199) marker plus the computed out-of-range index / overflow byte count / underflowed loop count. See run.log for the captured decisive run.

Fix

See fix.diff (git-apply-able) and VERDICT.md. The fix was validated to compile (module rebuilt with -Werror) β€” see fix_build.log. No live-kernel trigger exists on the guest, so the fix is validated at the applies + compiles + closes-the-code-path level.

Artifacts

VERDICT.md (full narrative), harness.c, build.sh, run.sh, run.log, env.txt, fix.diff, fix_build.log, manifest.json.

VERDICT.md verdict full narrative + fix
↓ download raw

DF-1192 β€” ciss_filter_physical negative bus index (OOB read+write)

Verdict

REPRODUCED (harness) β€” real bug confirmed by source trace + userspace replica. Impact class: negative array index β†’ OOB kernel-pointer read then controlled OOB write. No local-unprivileged trigger on the audit guest; trigger requires a malicious/emulated CISS controller. uid=0 chain N/A β€” hardware/firmware-attacker.

Mechanism (confirmed path:line)

ciss_filter_physical() (called from ciss_init_physical) maps each physical LUN's extra_address into the ciss_physical[][] array:

CISS_EXTRA_BUS2 (cissreg.h:63) extracts bits 24..29 β†’ 0..63, then the code subtracts 1 (CISS firmware numbers physical buses from 1). The preceding filter (ciss.c:1539-1541) rejects only BUS3 != 0, TARGET3 != 0, and MODE2 == 3 β€” it does not reject BUS2 == 0. When BUS2 == 0: bus = 0 - 1 = -1 (the bus local is int, ciss.c:1420), and sc->ciss_physical[-1][target]: 1. reads the pointer one slot before the ciss_physical[] row array (an OOB kernel-pointer read), and 2. writes cp_address / cp_online through that pointer β€” a controlled write to whatever it references.

ciss_physical is sized ciss_max_physical_bus rows Γ— CISS_MAX_PHYSTGT(256) cols (cissvar.h:171, ciss.c:1495-1503). target (0..255) is always in range, but bus is never validated against [0, ciss_max_physical_bus).

Harness proof (run.log)

harness.c replicates the filter + index with the real macros, a benign BUS2=2 (β†’ bus=1, in-range) and a malicious BUS2=0 (β†’ bus=-1). The malicious LUN passes the filter and computes a negative index:

[malicious] BUS2= 0 target= 5 -> index bus=-1 (valid 0..3) target=5
[benign   ] BUS2= 2 target= 5 -> index bus=1 (valid 0..3) target=5
[BUG REPRODUCED] malicious LUN PASSES the filter and indexes ciss_physical[-1][5]

(The first harness revision had a return-value sentinel collision: bus=-1 was mistaken for the "filtered" sentinel -1. Fixed by using a distinct status code; the bug itself was correctly computed in both revisions.)

Why not a live-kernel trigger / no uid0 chain

ciss attaches only to HP Smart Array PCI devices (none on the guest). The extra_address comes from the controller's REPORT_PHYSICAL_LUNS DMA reply at probe time β€” not reachable from any unprivileged syscall. Hardware/firmware- attacker class (note AC:H in the CVSS reflects this); no local-privesc chain.

Fix (fix.diff)

Validate bus >= 0 && bus < ciss_max_physical_bus && target < CISS_MAX_PHYSTGT before indexing, at ciss.c:1557. One logical change; compiles cleanly.

Fix validation

ciss.ko rebuilt from patched source (DF-1190/1191/1192 applied) compiled with -Werror and linked; new "physical device %d has out-of-range address" string present. fix_status: not_testable (no CISS HW for a live trigger).

Fix verification

not_testable

compile+harness validated

module build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

REPRODUCED (harness). ciss_filter_physical bus=CISS_EXTRA_BUS2-1 underflow when BUS2=0 -> negative index OOB. No HP controller.