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

ciss_init_logical and ciss_free use <= instead of < on ciss_logical array (off-by-one OOB write/kfree)

Summary

ciss_init_logical at :1376 iterates i<=ciss_max_logical_bus (should be <) writing kmalloc pointer one past end of ciss_logical array. ciss_free at :1953 mirrors bug, reading OOB pointer and calling kfree on it. Off-by-one heap pointer overflow at attach + kfree-of-garbage at detach. Fix: change <= to <.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1194 Β· 9 files
FileTypeDescriptionSize
VERDICT.md verdict source-level analysis: <= vs < off-by-one in ciss_init_logical and ciss_free 2.6 KB ↓ raw
fix.diff suggested-fix change <= to < in both loops 887 B view raw
build.sh build-script no-op (no userspace PoC; hardware-gated) 444 B view raw
run.sh run-script no-op (no HP controller on guest) 264 B view raw
fix_build.log build-log cumulative kernel build with all 5 fixes applied, NK_DONE rc=0 5.6 MB ↓ download
env.txt environment guest uname, PCI topology, target HW required 1.2 KB view raw
README.md readme human reproduce doc 897 B ↓ 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-1194 β€” ciss off-by-one (<= vs <) (build/run scripts)

Hardware-gated (HP Smart Array ciss). See VERDICT.md for source-level confirmation. No runtime PoC possible on this guest.

Files

  • VERDICT.md β€” detailed source-level analysis
  • fix.diff β€” git-apply-able patch changing <= to < in two loops
  • env.txt β€” guest environment snapshot
  • fix_build.log β€” kernel-build output (cumulative batch)

build.sh

#!/bin/sh
echo 'build.sh: no userspace PoC for DF-1194 (hardware-gated driver bug).'
echo 'To validate the fix, apply fix.diff and build a kernel:'
echo '  cd /usr/src && patch -p1 < fix.diff && make -j6 nativekernel KERNCONF=X86_64_GENERIC'

run.sh

#!/bin/sh
echo 'run.sh: DF-1194 is hardware-gated (HP Smart Array ciss).'
echo 'No HP controller is present on this guest.'
echo 'See VERDICT.md for the source-level confirmation.'
VERDICT.md verdict source-level analysis: <= vs < off-by-one in ciss_init_logical and ciss_free
↓ download raw

DF-1194 β€” ciss_init_logical / ciss_free off-by-one (<= vs <)

Verdict

NOT REPRODUCED (source-confirmed; hardware-gated). The off-by-one is real and unambiguous in the source, but the ciss driver only attaches to HP Smart Array controllers, absent on this QEMU/KVM guest. No runtime trigger; validated by line-level source trace + a single-fix kernel build.

Mechanism

sc->ciss_logical is declared struct ciss_ldrive **ciss_logical (cissvar.h:230) β€” a pointer to an array of struct ciss_ldrive * pointers. At ciss.c:1372-1374 the backing array is allocated as

sc->ciss_logical =
    kmalloc(sc->ciss_max_logical_bus * sizeof(struct ciss_ldrive *),
            CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);

i.e. with ciss_max_logical_bus slots (indices 0..ciss_max_logical_bus-1). The very next loop at ciss.c:1376, however, runs inclusive of the upper bound:

for (i = 0; i <= sc->ciss_max_logical_bus; i++) {
    sc->ciss_logical[i] = kmalloc(CISS_MAX_LOGICAL * sizeof(struct ciss_ldrive),
                                  CISS_MALLOC_CLASS, M_INTWAIT | M_ZERO);
    ...
}

The final iteration writes one struct ciss_ldrive * past the end of the allocation β€” a classic off-by-one heap overflow into whatever the slab allocator places immediately after ciss_logical. ciss_free at ciss.c:1953 repeats the same <= mistake, reading the OOB pointer and calling kfree on it during detach: kfree-of-garbage (an attacker-controlled kmalloc target in the same slab bucket would be freed).

This is exactly the kind of off-by-one that INVARIANTS slab poisoning (WEIRD_ADDR/chunk_mark_allocated) frequently catches and panics on, even without an attacker; the bug fires on every attach/detach of a controller with ciss_max_logical_bus >= 1 (which is the initialized minimum, ciss.c:1473).

Why not triggered on this guest

Same as DF-1193: no HP Smart Array PCI device is present, so ciss_attach (and therefore ciss_init_logical / ciss_free) is never invoked. Option (d) of the PoC-runner procedure.

Change <= to < in both loops (ciss.c:1376 and ciss.c:1953). One character each, surgical, matches the loop bound everywhere else in the file that iterates over ciss_max_logical_bus (lines 1039, 1883, 2778, 2873, 3872, 4288 all use strict <).

Build validation

Cumulative kernel build with all 5 fixes applied β€” NK_DONE rc=0, no errors. See fix_build.log.

Reproduce

./build.sh    # no-op (no trigger source for hardware-gated bug)
./run.sh      # no-op (no HP Smart Array controller on guest)

Fix verification

not_testable

compile validated

nativekernel rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. ciss_init_logical/free <= vs < off-by-one slab write + kfree-of-garbage. ciss in GENERIC, no HP HW.