# DF-4853 — VERDICT

## Bottom line

**Inconclusive end-to-end** (the radeon driver path is hardware-gated on
this guest: no radeon GPU, no /dev/dri — QEMU std VGA only), **the type
confusion is proven statically with exact lines and machine-verified
offsets, and its memory-corruption primitive is proven LIVE on the guest
kernel** with the exact DragonFly heap geometry (280-byte
`radeon_encoder_lvds` in a 288-byte chunk, zero slack): a KLD replica of
`evergreen_hdmi_enable`'s deref sequence read `dig->afmt` (+288) from the
**adjacent kernel object**, the `!dig || !dig->afmt` guard fell through on
the groomed non-NULL neighbor, `dig->afmt->offset` (0x5678) was collected
as the value the six WREG32 sites would program, and
`dig->afmt->enabled = enable` **wrote through the OOB-read pointer**
(observed 0→1→0 in a controlled fake afmt, both dpms directions).
Confidence: certain (offsets machine-verified by evg_offsets.c: lvds=280,
atom_dig=312, afmt@+288; family precedent DF-4635/DF-4828).

## Why this is a NEW finding (not DF-4635, not DF-4828)

* DF-4635 covers the sinks in **radeon_audio.c:262-480**
  (`radeon_audio_enable`'s walk deref, `radeon_audio_detect`'s dig->pin).
  The sinks here are in **evergreen_hdmi.c** (:431/:438-455/:458 and
  :473/:483-510/:513) — dispatched into by `radeon_audio_dpms`.
* DF-4828 covers the sinks in **r600_hdmi.c** (audio-work walk:
  buffer_status_changed / update_audio_settings), and its verdict
  explicitly dismissed the dpms route: "r600_hdmi_enable … only reachable
  via radeon_audio_dpms … gated on encoder_mode == HDMI || DP — the
  mis-typed LVDS-mode encoders never take it". **That dismissal is wrong
  for eDP**: an eDP connector yields `ATOM_ENCODER_MODE_DP`
  (atombios_encoders.c:824-829) while its encoder carries the lvds-typed
  enc_priv (atombios_encoders.c:2862-2869), so the gate at
  atombios_encoders.c:1848-1851 PASSES, and `radeon_audio_detect`
  (radeon_audio.c:461-472) assigns **hdmi_funcs** (= evergreen sinks on
  DCE4/5/6) to the eDP encoder because DRM_MODE_CONNECTOR_eDP ≠
  DRM_MODE_CONNECTOR_DisplayPort. On a DCE4+ eDP laptop, every dpms
  transition (screen blank/unblank, any modeset, DRM_IOCTL_MODE_DPMS by an
  unprivileged DRM client) hits the mis-typed deref.
* DF-1911 is the missing-mutex race on the shared walk — unrelated root.

## Live primitive proof (run.log)

```
evg_probe: 8192 objs of 280 bytes; usable chunk = 288 (want 288)
evg_probe: adjacent pair A=0xfffff80117c95900 B=0xfffff80117c95a20 (B-A=288)
evg_probe: victim B[0..8) groomed to 0xffffffff82600380 (fake afmt)
evg_probe: OOB READ dig->afmt (+288) == 0xffffffff82600380 (non-NULL -> guard at evergreen_hdmi.c:431 FALLS THROUGH)
evg_probe: fake_afmt before: enabled=0 offset=0x5678
evg_probe: after evergreen_hdmi_enable(true): enabled=1  <- WILD WRITE via OOB-read pointer (evergreen_hdmi.c:458)
evg_probe: collected 2 distinct MMIO sites; dig->afmt->offset == 0x5678 would be added to HDMI_INFOFRAME_CONTROL0/AFMT_AUDIO_PACKET_CONTROL WREG32s (:438-455)
evg_probe: after evergreen_hdmi_enable(false): enabled=0 (write-through both directions)
evg_probe: victim B[0..8) zeroed -> OOB read NULL -> replica touched 0 MMIO site(s), no write (silent; hides the bug)
```

The harness replicates the exact deref sequence of evergreen_hdmi.c
:429-:458 (verbatim comments map each line); WREG32 is factored out (the
offset VALUE it would program is collected), since programming real MMIO
on a GPU-less guest is impossible and meaningless.

## Exploit chain (hardware-gated, not runnable here)

Groom the shared 288-byte slab size class so a chosen victim object follows
the lvds enc_priv allocation → eDP dpms transition →
`evergreen_hdmi_enable` → OOB read `dig->afmt` = victim[0..8) → if
non-NULL: wild read (->offset drives HDMI_INFOFRAME_CONTROL0 /
AFMT_AUDIO_PACKET_CONTROL MMIO offsets — attacker-influenced register
programming), and **wild write** `dig->afmt->enabled = enable` (byte at
victim[0..8)+0) on every dpms on AND off. NULL neighbor silently returns
(hides the bug), garbage neighbor = panic, groomed victim = controlled
write-where (through-pointer, address = victim[0..8)) → crash-to-UAF
escalation path, same analysis as DF-4635/DF-4828 (DF slab 32-byte
granularity makes the cross-object effect DragonFly-specific in severity;
upstream Linux code is byte-identical at the sinks but masked by
kmalloc-512 slack).

## Fix

`fix.diff`: type-gate both sinks — enc_priv is `radeon_encoder_lvds*`
**iff** the encoder was registered `DRM_MODE_ENCODER_LVDS`
(atombios_encoders.c:2824-2836, :2862-2869), so
`if (!dig || encoder->encoder_type == DRM_MODE_ENCODER_LVDS) return;`
in `evergreen_hdmi_enable` and `evergreen_dp_enable`. Compile-validated:
patch applies clean (hunks at 428/485), full radeon.ko rebuild with
-Werror succeeds including the patched evergreen_hdmi.o (fix_build.log,
RC=0). Behavioral validation impossible on this guest (no radeon GPU —
`radeon_audio_dpms` never executes); the KLD primitive harness is
driver-path-independent by construction. Family precedent: the same gate
shape compile-validated for DF-4828.

## PoC fixes vs seed

No seed existed (new pass-2 finding). One -Werror fix during the KLD build
(uninitialized `mmio[0]` in a kprintf).

## 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.
