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

radeon_connector_get_edid dereferences ddc_bus->has_aux with ddc_bus==NULL (unprivileged GETCONNECTOR DoS)

Summary

get_edid tests the DP-bridge encoder condition first and then dereferences ddc_bus->has_aux unconditionally. radeon_add_atom_connector continues with ddc_bus==NULL after a failed i2c lookup (error only printed), and a TRAVIS/NUTMEG possible-encoder satisfies the condition from static BIOS data - so the first detect on such a connector panics. The 'else if (ddc_bus)' later shows the NULL check was simply forgotten for the aux paths. GETCONNECTOR has no master/auth gate - unprivileged. Guard fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4034 Β· 11 files
FileTypeDescriptionSize
README.md β€” 553 B ↓ raw
VERDICT.md β€” 2.5 KB ↓ raw
build.log β€” 1.1 KB view raw
build.sh β€” 65 B view raw
conn_probe.c β€” 5.0 KB view raw
env.txt β€” 586 B view raw
fix.diff β€” 931 B view raw
run.2.log β€” 881 B view raw
run.log β€” 117 B view raw
run.sh β€” 89 B view raw
verdict.json β€” 2.7 KB view raw

DF-4034 evidence pack

radeon_connector_get_edid dereferences radeon_connector->ddc_bus->has_aux (radeon_connectors.c:311, and :320 in the DP/eDP branch) without checking ddc_bus. radeon_add_atom_connector continues with dd

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-4034 β€” radeon_connector_get_edid() dereferences ddc_bus->has_aux with ddc_bus == NULL

File: sys/dev/drm/radeon/radeon_connectors.c Severity: Low (unprivileged local DoS panic; hardware/BIOS-gated) Class: CWE-476 NULL pointer dereference.

Root cause (path:line)

309:    if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
310:         ENCODER_OBJECT_ID_NONE) &&
311:        radeon_connector->ddc_bus->has_aux) {

The DP-bridge test (possible encoders contain TRAVIS/NUTMEG β€” static BIOS data) is evaluated first; ddc_bus->has_aux is then dereferenced unconditionally. A DP-bridge connector whose i2c bus lookup failed is still created with ddc_bus == NULL (radeon_add_atom_connector, radeon_connectors.c:1961-1966: lookup failure only prints "DP: Failed to assign ddc bus!" and continues). Every later radeon_connector_get_edid() β€” i.e. every detect/get_modes β€” then panics at :311.

A second, narrower variant sits in the DP/eDP branch at :318-320 (radeon_connector->ddc_bus->has_aux evaluated after dig->dp_sink_type is set to DISPLAYPORT by radeon_dp_detect, radeon_connectors.c:1709/1721) β€” the else if at :323 shows the author did remember the NULL check for the non-aux path, proving the :311/:320 dereferences are oversights.

Reachability: unprivileged β€” DRM_IOCTL_MODE_GETCONNECTOR has no master/auth gate (sys/dev/drm/drm_ioctl.c:663, DRM_UNLOCKED only) and drives fill_modes β†’ radeon_*_get_modes β†’ radeon_connector_get_edid. Preconditions: radeon KMS + a DP-bridge (Travis/Nutmeg) connector + failed i2c-bus assignment (error is visible in dmesg at boot: "Failed to assign ddc bus!").

Upstream status

Identical dereference in current Linux master (upstream radeon_connectors.c:271-273). Unfixed upstream.

Verification (this pack)

  • conn_probe.c mode getconnector β€” raw unauthenticated GETCONNECTOR loop over all connectors (builds clean on the guest; run.log).
  • Runtime hardware-gated (no radeon GPU on the audit guest β€” env.txt); the dereference is source-certain given the boot-time misconfiguration.

Suggested fix

fix.diff: add radeon_connector->ddc_bus && before both has_aux tests.

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-4034

Confirmed kernel references

Detail

Exploit chain

Unpriv user opens /dev/dri/card0, GETCONNECTOR on the DP-bridge connector whose ddc bus lookup failed at boot -> NULL-deref panic.

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

Add ddc_bus NULL guards before both has_aux tests (see fix.diff).

Verdict

radeon_connector_get_edid dereferences radeon_connector->ddc_bus->has_aux (radeon_connectors.c:311, and :320 in the DP/eDP branch) without checking ddc_bus. radeon_add_atom_connector continues with ddc_bus==NULL after a failed i2c lookup (:1961-1966), and a DP-bridge (TRAVIS/NUTMEG) connector satisfies the :309 condition from static BIOS data, so the first detect/get_modes panics. Unauthenticated reachability via DRM_IOCTL_MODE_GETCONNECTOR (drm_ioctl.c:663, DRM_UNLOCKED only). Upstream master has the same dereference. Hardware/BIOS-gated: no radeon GPU on the audit guest.