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

Unguarded enc_priv (NULL) dereferences in all DIG setup paths when get_lcd_info()/get_dig_info() fail β€” NULL-page read at amdgpu attach and NULL-page WRITE on DPMS-ON (DF-3957 amdgpu twin)

Summary

setup_dig_transmitter, setup_dig_encoder, setup_dig and set_crtc_source dereference amdgpu_encoder->enc_priv without a NULL check. enc_priv is NULL whenever get_lcd_info fails (missing/corrupt LVDS_Info VBIOS table) or get_dig_info's kzalloc fails - the dce_v8/10/11 paths assign it verbatim. Crafted/root-flashed VBIOS on an LCD-supporting UNIPHY encoder panics at attach (read) or first modeset (write of panel_mode). DoS only. NULL-guard fix mirroring the guard that exists at :91.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4103 Β· 4 files
FileTypeDescriptionSize
README.md β€” 1.9 KB ↓ raw
VERDICT.md β€” 3.4 KB ↓ raw
verdict.json β€” 2.8 KB view raw
fix.diff β€” 1.8 KB view raw

DF-4103 β€” amdgpu atombios_encoders: unguarded enc_priv (NULL) dereferences in all DIG setup paths

File: sys/dev/drm/amd/amdgpu/atombios_encoders.c (pass 2) Class: NULL-pointer dereference (CWE-476) β†’ kernel panic / NULL-page WRITE Hardware gate: AMD GPU (CIK/VI, DCE8/10/11 non-DC asics) with LCD-supporting UNIPHY encoder. Family: amdgpu twin of DF-3957 (radeon atombios_encoders, same code shape).

Build

Not buildable/runnable on the audit guest: the QEMU guest has no AMD GPU (pciconf -l: only Intel/QEMU devices; vgapci0 = bochs 1234:1111). Source-level certainty only. See VERDICT.md.

Run (would be, on hardware / with an emulated ATI ROM)

  1. Craft a VBIOS image whose encoder table yields an UNIPHY encoder with ATOM_DEVICE_LCD_SUPPORT but with the LVDS_Info master data table absent (or with a master-table index of 0), so amdgpu_atombios_encoder_get_lcd_info() returns NULL (atombios_encoders.c:2081 if (amdgpu_atom_parse_data_header(...)) fails β†’ returns NULL at 2205).
  2. Boot / kldload amdgpu β†’ dce_v10_0_hw_init (dce_v10_0.c:2829) β†’ amdgpu_atombios_encoder_init_dig (atombios_encoders.c:1744) β†’ amdgpu_atombios_encoder_setup_dig_transmitter(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0) (1758) β†’ dig = amdgpu_encoder->enc_priv; (837) β†’ int dig_encoder = dig->dig_encoder; (848) β†’ NULL-page READ β†’ kernel panic.

Expected

Fatal trap 12: page fault while in kernel mode at amdgpu_atombios_encoder_setup_dig_transmitter+0x... during amdgpu hw_init (or later, amdgpu_atombios_encoder_setup_dig NULL WRITE at offset of panel_mode on first DPMS-ON).

Artifacts

  • VERDICT.md β€” full narrative with path:line trace
  • verdict.json β€” machine verdict (status: untested, hardware absent on guest)
  • fix.diff β€” add if (!dig) return; guards (mirrors the guard the file already has in amdgpu_atombios_encoder_set_backlight_level, :91-93)
VERDICT.md
↓ download raw

DF-4103 VERDICT

Status: untested (hardware-gated β€” no AMD GPU on the audit guest; source-level certainty certain) Impact: kernel panic (NULL-page read at boot; NULL-page write on DPMS-ON). Not exploitable beyond DoS.

Root cause

For encoders carrying ATOM_DEVICE_LCD_SUPPORT, enc_priv is produced by amdgpu_atombios_encoder_get_lcd_info():

  • dce_v8_0.c:3408, dce_v10_0.c:3520, dce_v11_0.c:3652: amdgpu_encoder->enc_priv = amdgpu_atombios_encoder_get_lcd_info(amdgpu_encoder);

That function (atombios_encoders.c:2069-2206) returns NULL when: 1. amdgpu_atom_parse_data_header(...LVDS_Info...) fails (atombios_encoders.c:2081) β€” i.e. the VBIOS master data table has no LVDS_Info entry β€” fully VBIOS-controlled; or 2. the kzalloc at 2085-2086 fails (OOM at boot).

For non-LCD digital encoders, enc_priv = amdgpu_atombios_encoder_get_dig_info() (dce_v10_0.c:3524/3528) also returns NULL on kzalloc failure (atombios_encoders.c:2212-2215).

Four sinks in this file dereference enc_priv with no NULL check:

sink deref nature
amdgpu_atombios_encoder_setup_dig_transmitter :837β†’848 dig->dig_encoder NULL read
amdgpu_atombios_encoder_setup_dig_encoder :648β†’668 dig->dig_encoder == -1 NULL read
amdgpu_atombios_encoder_setup_dig :1402β†’1414/1420-1422/1445 dig->panel_mode = ... NULL write
amdgpu_atombios_encoder_set_crtc_source :1617β†’1618, :1686β†’1687 dig->dig_encoder NULL read

(Contrast amdgpu_atombios_encoder_set_backlight_level :91-93, which does guard amdgpu_encoder->enc_priv β€” the guards were simply never added to the setup paths.)

Reachability

  • Boot path (no user action): dce_v10_0_hw_init (dce_v10_0.c:2829) β†’ amdgpu_atombios_encoder_init_dig (:1744) β†’ unconditional setup_dig_transmitter(ATOM_TRANSMITTER_ACTION_INIT) for every UNIPHY encoder (:1754-1759) β†’ :848 NULL read β†’ panic during driver attach.
  • Runtime path (mode set): dce_v10_0_encoder_funcs dpms helpers (dce_v10_0.c:3421/3431) β†’ amdgpu_atombios_encoder_dpms (:1477) β†’ setup_dig (:1397) β†’ :1414 NULL write to the panel_mode offset.

Trigger: crafted/corrupt VBIOS on an LCD (laptop panel) system, or kzalloc failure at the wrong instant. Threat model identical to DF-1380/DF-3744 (root-flashed VBIOS or malicious PCIe device ROM). On DragonFly amd64 the NULL page is unmapped in kernel context β†’ deterministic fatal trap. A NULL-page write at a small fixed offset is not exploitable for code execution on this platform (no mapping at 0).

Why untested

The single-tenant QEMU guest has no AMD GPU (pciconf -l shows only Intel/ QEMU devices; display is bochs 1234:1111 β€” see verdict.json notes/env). The amdgpu driver never probes. Both trigger paths are inside amdgpu attach/ modeset, so no in-guest reproduction is possible without the hardware. Traced the cited path line-by-line instead; conclusion: real defect, certain, panic-only impact.

Fix

Add NULL guards exactly where the backlight path already has one (atombios_encoders.c:91-93). See fix.diff.

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 adds NULL guards to the four sink functions; cannot be kernel-built/tested on the guest because the amdgpu driver has no hardware to attach to.

findings/poc/DF-4103/fix.diff
↓ fix.diffper-fix-DF-4103

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md table of the four unguarded sinks; contrast with the existing guard at atombios_encoders.c:91-93; dce_v10_0.c:3516-3528 enc_priv assignment sites; dce_v10_0.c:2829-2839 boot-path caller.

PoC changes

No PoC possible on guest (hardware absent); evidence pack is a source-level trace instead of a runnable trigger.

Verified recommended fix

Guard every enc_priv dereference with if (!dig) return/break, mirroring atombios_encoders.c:91-93.

Verdict

Source-level certain: amdgpu_atombios_encoder_setup_dig_transmitter (:837/:848), setup_dig_encoder (:648/:668), setup_dig (:1402/:1414 NULL write) and set_crtc_source (:1617/:1686) all dereference amdgpu_encoder->enc_priv unguarded; enc_priv is NULL whenever amdgpu_atombios_encoder_get_lcd_info() fails (missing LVDS_Info VBIOS table, atombios_encoders.c:2081) or get_dig_info()/kzalloc fails. Boot-time sink: dce_v{8,10,11}_0_hw_init -> amdgpu_atombios_encoder_init_dig (:1744/:1758). Result is a NULL-page read/write -> deterministic kernel panic (DoS), not code execution. Not runnable: the QEMU audit guest has no AMD GPU (pciconf: bochs 1234:1111 only), so the driver never attaches.