β¬’ 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 706 B ↓ raw
build.sh build-script N/A (source-only) 61 B view raw
run.sh run-script N/A (source-only) 87 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 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)