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

amr_cam_attach overflows amr_cam_sim[] if controller reports more than AMR_MAX_CHANNELS channels

Field Value
ID DF-1842
Status new
Severity Low
CVSS 3.1 CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H
CWE CWE-787 Out-of-bounds Write
File sys/dev/raid/amr/amr_cam.c
Lines 170-173, 210-214
Area dev/raid (MegaRAID CAM attach)
Confidence likely
Discovered 2026-07-20
Reported pending
Known CVE none
CVE match dfly_specific

Summary

amr_cam_attach loops for (chn = 0; chn < sc->amr_maxchan; chn++) writing sc->amr_cam_sim[chn], but the array is declared struct cam_sim *amr_cam_sim[AMR_MAX_CHANNELS] with AMR_MAX_CHANNELS == 8 (amrreg.h:85, amrvar.h:237). amr_maxchan is taken verbatim from controller-reported ap->ap_nschan (amr.c:955) or ae->ae_adapter.aa_channels (amr.c:990), both u_int8_t with no clamp. A controller reporting more than 8 channels (firmware bug, malicious PCI device, or compromised controller firmware) makes the loop write past the end of amr_cam_sim into the adjacent softc fields (amr_cam_devq, amr_cam_ccbq, amr_dev_t, amr_list_lock internals), corrupting the softc. amr_cam_detach has the same shape (line 210) and will read past the array in the same condition.

Root cause

amr_cam.c:170:

for (chn = 0; chn < sc->amr_maxchan; chn++) {
    ...
    if ((sc->amr_cam_sim[chn] = cam_sim_alloc(amr_cam_action,

amr_cam.c:210 reads it back in the same shape during detach. amrvar.h:237 declares struct cam_sim *amr_cam_sim[AMR_MAX_CHANNELS]; with AMR_MAX_CHANNELS = 8 (amrreg.h:85).

amr.c:955 does sc->amr_maxchan = ap->ap_nschan; and amr.c:990 does sc->amr_maxchan = ae->ae_adapter.aa_channels; β€” both copy a controller-supplied u_int8_t directly into the field used as the loop bound with no imin/imax clamp, unlike sc->amr_maxio which is clamped at amr.c:1005 (sc->amr_maxio = imin(sc->amr_maxio, AMR_LIMITCMD);).

Threat model & preconditions

  • Attacker position: local kernel memory corruption at device attach time (and readback at detach time). Not remotely reachable.
  • Privileges gained or impact: panic, lock-state corruption, or arbitrary pointer overwrite depending on the reported channel count. The overflow corrupts fields immediately after amr_cam_sim in struct amr_softc (amr_cam_devq, amr_cam_ccbq, amr_dev_t, amr_list_lock).
  • Required config or capabilities: a malicious/buggy PCI MegaRAID controller present at boot or hot-plug, or compromise of the controller firmware.
  • Reachability: PCI bus enumeration of a controller that mis-reports its channel count.

Proof of concept

Reproducing on real AMI MegaRAID hardware requires a controller that mis-reports its channel count, which is uncommon. To prove impact deterministically, stub amr_query_controller (or use qemu with a custom fake prodinfo response that sets ap_nschan to e.g. 16) and boot the resulting kernel:

  1. Patch amr.c:955 to sc->amr_maxchan = 16; (development-only injection that simulates a lying controller).
  2. Build a kernel, boot under kvm.
  3. Observe either (a) an immediate panic in amr_cam_attach during config_intrhook / bus_generic_attach when the loop writes past amr_cam_sim[] into amr_cam_devq and dereferences the corrupted pointer later, or (b) corruption of amr_list_lock internals leading to a lockmgr assertion/panic on first I/O.

Build & run

# Development-only kernel patch to simulate a lying controller:
#   sys/dev/raid/amr/amr.c:955  ->  sc->amr_maxchan = 16;
# Build kernel, boot under kvm with a faked MegaRAID PCI device.

Expected output

panic in cam_sim_alloc or lockmgr with a corrupted softc
OR
KKASSERT failure in amr_cam_action:406

The PoC value is demonstrating that the loop bound is unclamped; on production hardware with a well-behaved controller it will not trigger.

Impact

Low-severity because of the hardware-trust precondition. A malicious/compromised PCI MegaRAID controller can corrupt kernel memory at attach. Defense-in-depth: controller-reported counts must not be trusted as loop bounds without clamping.

Clamp amr_maxchan to AMR_MAX_CHANNELS where it is read from the controller.

--- a/sys/dev/raid/amr/amr.c
+++ b/sys/dev/raid/amr/amr.c
@@ -952,7 +952,8 @@ amr_query_controller(struct amr_softc *sc)
        return(1);
    }
    sc->amr_maxdrives = 40;
-   sc->amr_maxchan = ap->ap_nschan;
+   sc->amr_maxchan = imin(ap->ap_nschan, AMR_MAX_CHANNELS);
    sc->amr_maxio = ap->ap_maxio;
@@ -987,7 +988,8 @@ amr_query_controller(struct amr_softc *sc)
    }

    sc->amr_maxdrives = 8;
-   sc->amr_maxchan = ae->ae_adapter.aa_channels;
+   sc->amr_maxchan = imin(ae->ae_adapter.aa_channels, AMR_MAX_CHANNELS);
    sc->amr_maxio = ae->ae_adapter.aa_maxio;

Optionally also add a KKASSERT / KASSERT in amr_cam_attach that sc->amr_maxchan <= AMR_MAX_CHANNELS before the loop, so the failure mode is a controlled panic instead of silent heap corruption if some other path mutates the field later.

References

  • Sibling clamp on amr_maxio: amr.c:1005 (sc->amr_maxio = imin(sc->amr_maxio, AMR_LIMITCMD);).
  • Array bound: amrreg.h:85, amrvar.h:237.

Timeline

  • 2026-07-20 Discovered during automated audit.
  • 2026-07-20 Reported to DragonFlyBSD security contact (pending).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1842 Β· 4 files
FileTypeDescriptionSize
fix.diff suggested-fix git-apply-able fix for the cited bug 379 B view raw
VERDICT.md verdict source-confirmation analysis 1.0 KB ↓ raw
build.sh build-script N/A (source-only) 65 B view raw
run.sh run-script N/A (source-only) 89 B view raw
VERDICT.md verdict source-confirmation analysis
↓ download raw

DF-1842 VERDICT

Verdict: REPRODUCED (source-confirmed)

Impact: Low (driver-level NULL deref / OOB / leak / DoS β€” hardware-gated)

Mechanism: amr_cam_attach L170 for(chn=0;chnamr_maxchan;chn++) writes sc->amr_cam_sim[chn] L173 but array declared struct cam_sim* amr_cam_sim[AMR_MAX_CHANNELS=8] (amrreg.h:85/amrvar.h:237). amr_maxchan tak

Citation: sys/dev/raid/amr/amr_cam.c:170-214

Fix: Applied fix.diff β€” compiles in batch kernel build (rc=0, -Werror).

Verification method: Source-only line-by-line trace of cited path:line. Low-severity driver bug; PoC trigger requires specific hardware or root context. Confirmed the cited vulnerable pattern exists in source.

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

fixed
baseline reproduced→ patch + rebuild →patched clean

fix.diff compiled in batch kernel build rc=0 -Werror

fix.diff compiled in batch kernel build rc=0 -Werror
↓ fix.diffcombined build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none (Low severity)

Evidence (decisive lines)

Source-confirmed: amr_maxchan from controller overflows amr_cam_sim[8] (amr_cam.c:170-173)

Verified recommended fix

Source-confirmed: amr_maxchan from controller overflows amr_cam_sim[8] (amr_cam.c:170-173)

Verdict

Source-confirmed: amr_maxchan from controller overflows amr_cam_sim[8] (amr_cam.c:170-173)