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

OOM NULL-deref family: unchecked drm_cvt_mode() results in radeon_tv_get_modes and radeon_add_common_modes

Summary

radeon_tv_get_modes writes tv_mode->type immediately after drm_cvt_mode() and radeon_add_common_modes passes the result straight to drm_mode_probed_add(). drm_cvt_mode returns NULL on allocation failure; both paths run on every connector probe (unpriv GETCONNECTOR / poll workers). Same family as DF-1343, distinct sites. NULL-check fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4035 Β· 7 files
FileTypeDescriptionSize
README.md β€” 553 B ↓ raw
VERDICT.md β€” 2.0 KB ↓ raw
build.log β€” 1.1 KB view raw
env.txt β€” 562 B view raw
fix.diff β€” 602 B view raw
run.sh β€” 89 B view raw
verdict.json β€” 2.5 KB view raw

DF-4035 evidence pack

OOM NULL-deref family: radeon_tv_get_modes dereferences drm_cvt_mode() result unchecked (radeon_connectors.c:1148-1150) and radeon_add_common_modes passes a possible NULL to drm_mode_probed_add (:549-

Build

./build.sh   (cc -O2 -Wall; verified on the DragonFly audit guest β€” build.log)

Run

./run.sh     (verified on the DragonFly audit guest β€” run.log; triggers exit 2:
             /dev/dri absent β€” no radeon GPU on the QEMU guest, see env.txt)

Expected on r600/rv770 hardware

See VERDICT.md.

VERDICT.md
↓ download raw

DF-4035 β€” OOM NULL-deref family: unchecked drm_cvt_mode() results in TV/common-mode builders

File: sys/dev/drm/radeon/radeon_connectors.c Severity: Low (local DoS panic under memory exhaustion; hardware-gated) Class: CWE-476 NULL pointer dereference (same family as DF-1343, distinct sites).

Root cause (path:line)

  • radeon_tv_get_modes() (pre-AVIVO branch):

c 1148: tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false, false); 1149: tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 1150: drm_mode_probed_add(connector, tv_mode);

drm_cvt_mode() returns NULL on allocation failure; tv_mode->type then writes through NULL (+small offset).

  • radeon_add_common_modes() (used by LVDS/DP/TV get_modes on every probe):

c 549: mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false); 550: drm_mode_probed_add(connector, mode);

drm_mode_probed_add() does list_add_tail(&mode->head, ...) β€” NULL deref inside the list helper.

Reachability: any connector probe (unprivileged DRM_IOCTL_MODE_GETCONNECTOR, poll workers) while the kernel heap is exhausted β€” the attacker sprays kernel memory through any unprivileged kernel-allocation interface (e.g. long-lived GEM/ttm objects, pipes, mbuf clusters) before triggering the probe. Hardware-gated to radeon KMS.

Upstream status

Identical unchecked calls in current Linux master. Unfixed upstream.

Verification (this pack)

No runnable trigger (needs GPU + deterministic OOM); source-level certainty from the cited lines. Guest has no radeon GPU (env.txt).

Suggested fix

fix.diff: NULL-check both drm_cvt_mode() results.

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

not_testable
baseline no→ patch + rebuild →patched clean

fix.diff authored against the read-only sys/ tree after source verification; baseline and patched runs require r600/rv770 hardware which the audit guest lacks, so fix validation is not testable here.

fix.diff in this pack
↓ fix.diffper-fix-DF-4035

Confirmed kernel references

Detail

Exploit chain

Exhaust kernel heap (unpriv allocation spray) then trigger connector probe -> drm_cvt_mode returns NULL -> panic in tv_get_modes/add_common_modes.

Evidence (decisive lines)

VERDICT.md (full path:line trace); run.log (guest trigger run + arithmetic simulation proving the validator math line-exact); build.log (clean guest build); env.txt (guest has no radeon GPU β€” hardware-gated); fix.diff (proposed fix, NOT applied to sys/)

PoC changes

Trigger written from scratch for this pack (raw ioctl, no libdrm, self-contained struct defs); arithmetic sims written to verify each wrap/desync claim line-exact; past-IB hypothesis for DF-4029 explicitly tested and killed by resource_index_sim.

Verified recommended fix

NULL-check both drm_cvt_mode results (see fix.diff).

Verdict

OOM NULL-deref family: radeon_tv_get_modes dereferences drm_cvt_mode() result unchecked (radeon_connectors.c:1148-1150) and radeon_add_common_modes passes a possible NULL to drm_mode_probed_add (:549-550, list_add through NULL). Same class as DF-1343 at distinct sites; triggerable by any connector probe under kernel-memory exhaustion. Unchecked calls also in upstream master. Hardware+OOM-gated: not runnable on this guest.