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

Off-by-one in btc_copy_vbios_mc_reg_table + post-write bound check in btc_set_mc_special_registers allows VBIOS OOB write

Summary

btc_copy_vbios_mc_reg_table at btc_dpm.c:1992: check table->last>SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE(16) uses > not >=, admits last==16. btc_set_mc_special_registers at :1920-1933: j=table->last=16, first write at mc_reg_address[16]/mc_data[16] BEFORE guard if(j>=SIZE) at :1933 (post-write check). Off-by-one + post-write = OOB write past arrays into vddc_voltage_table. Sibling of ni_dpm.c:2721 which checks BEFORE write. Crafted VBIOS with last==16. Fix: change > to >=, move bound check before write.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1314 Β· 9 files
FileTypeDescriptionSize
VERDICT.md verdict source-trace verdict: off-by-one (> vs >=) admits last==16 -> OOB write 2.4 KB ↓ raw
README.md readme build/run/expected for this hardware-gated finding 2.0 KB ↓ raw
trigger_path.c trigger-source documents the unreachable trigger path + ni_dpm.c sibling 1.3 KB view raw
fix.diff suggested-fix change `>` to `>=` so last==16 is rejected 369 B view raw
build.sh build-log no userspace PoC; documents hardware-gated nature 389 B view raw
run.sh run-log reachability check (module/PCI/CPU) 677 B view raw
env.txt environment guest uname, cc, PCI, CPU, module presence 2.2 KB view 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 build/run/expected for this hardware-gated finding
↓ download raw

DF-1298 / DF-1305 / DF-1314 / DF-1315 β€” hardware-gated driver findings

These four findings are kernel driver/virtualization bugs that are confirmed real by source trace but that cannot run on the QEMU audit guest because the required hardware is absent (see env.txt):

Finding Subsystem Required hardware Present on guest?
DF-1298 amdgpu display VBIOS parser AMD GPU (amdgpu) NO (QEMU std-VGA only)
DF-1305 radeon kv DPM AMD radeon KV APU NO
DF-1314 radeon btc/evergreen DPM AMD radeon NI GPU NO
DF-1315 nvmm AMD-SVM backend AMD-SVM CPU NO (guest CPU has no SVM bit)

Build

./build.sh

There is no userspace PoC binary to compile for these β€” the vulnerable code is inside a kernel driver/VMM module that only executes when the relevant device attaches or the SVM backend runs. build.sh documents this.

Run

./run.sh

run.sh performs a reachability check (kldstat, pciconf, dmesg) and reports that the path is unreachable on this guest. No panic/leak is expected here because the trigger hardware is absent.

Expected (bug present, on a host WITH the hardware)

Each VERDICT.md describes the exact trigger and the kernel-level effect (heap overflow / OOB write / host DR7 persistence). On this guest those are latent.

Reproduce the FIX validation

The fix for each is fix.diff. To compile-validate a module fix: 1. scp fix.diff to the guest; cd /usr/src && patch -p1 < fix.diff 2. Build the relevant module, e.g. cd /usr/src && make -j6 MODULES_OVERRIDE=... or a full make -j6 nativekernel KERNCONF=X86_64_GENERIC (which also builds modules). 3. Confirm the module/object compiles with no errors (see fix_build.log).

Runtime fix-behaviour cannot be compared on this guest because the PoC paths are hardware-gated; the fix is therefore classified not_testable with a compile + source-trace validation.

VERDICT.md verdict source-trace verdict: off-by-one (> vs >=) admits last==16 -> OOB write
↓ download raw

DF-1314 β€” btc_copy_vbios_mc_reg_table off-by-one (radeon BTC DPM)

Verdict

NOT TESTABLE AT RUNTIME on this guest β€” confirmed real latent vulnerability in source.

Mechanism (confirmed by source trace)

sys/dev/drm/radeon/btc_dpm.c initialises the MC register table for Barts/Turks/Caicos (evergreen-family) radeon GPUs.

  1. btc_copy_vbios_mc_reg_table() (line 1987) copies the VBIOS table into the driver struct. Line 1992: c if (table->last > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE) /* SIZE = 16 */ return -EINVAL; uses > instead of >=, so it admits last == 16. It then sets eg_table->last = table->last (= 16) at line 2000.

  2. btc_initialize_mc_reg_table() (line 2014) then calls btc_set_mc_special_registers() (line 2050).

  3. btc_set_mc_special_registers() (line 1913) starts j = table->last = 16 (line 1920) and, in the MC_SEQ_MISC1 >> 2 case, writes table->mc_reg_address[j] and table->mc_reg_table_entry[k].mc_data[j] at index 16 (lines 1924, 1927) β€” which is one past the mc_reg_address[16] / mc_data[16] arrays (indices 0–15) β€” BEFORE the guard if (j >= SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE) return -EINVAL; at line 1933 (a post-write check).

Result: last == 16 β‡’ an OOB write at array index 16, overflowing struct evergreen_mc_reg_table (cypress_dpm.h) into adjacent fields (e.g. vddc_voltage_table).

  1. Sibling bug: ni_dpm.c:2850 has the identical > pattern with SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE. Same off-by-one; same fix. (Noted for maintainers; the included fix.diff targets the cited btc_dpm.c.)

Why it does not reproduce on this guest

  • radeon is not in GENERIC (loadable radeon.ko, not loaded); no AMD GPU present. The MC-reg-table init runs only at radeon evergreen/BTC bring-up, which never happens on this GPU-less guest. (Case d.)

Severity / realistic ceiling

On a host with a Northern-Islands/evergreen radeon GPU whose VBIOS reports last == 16, this is a kernel heap OOB write during DPM init β†’ heap corruption / panic; firmware-data-driven (malformed/malicious VBIOS).

Fix (see fix.diff)

Change > to >= at btc_dpm.c:1992 so last == 16 is rejected before the arrays are populated and before btc_set_mc_special_registers writes past them. Compile-validated (radeon module build). Runtime not exercisable here.

Fix verification

not_testable

compile+boot validated -Werror

nativekernel rc=0, boots #1 clean
↓ fix.diffDragonFly 6.5-DEVELOPMENT #1: Fri Jul 17 11:03:53 UTC 2026

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. btc_copy_vbios_mc_reg_table off-by-one > should be >= -> last==16 -> OOB write. radeon not in GENERIC. Sibling ni_dpm.c:2850.