# DF-4201 — NULL `amdgpu_encoder` dereference family after best_encoder() (radeon DF-4033 twin)

**File:** `sys/dev/drm/amd/amdgpu/amdgpu_connectors.c:139-141, 583-594, 792-803` (pass 2)
**Severity:** Low (VBIOS-misconfig-gated NULL deref panic; DRM_MASTER-gated ioctls / modeset path)
**Status:** not reproduced at runtime — hardware-gated; source-level certainty.

## Sites

1. `amdgpu_connector_get_monitor_bpc()` — eDP/LVDS branch when
   `display_info.bpc == 0` (no EDID / EDID without bpc):
   ```c
   struct drm_encoder *encoder = connector_funcs->best_encoder(connector);  /* :139 may be NULL */
   struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);      /* :140 NULL->container */
   struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;           /* :141 */
   if (dig->lcd_misc & ...)                                                 /* :143 deref */
   ```
   Two NULLs in the chain: `best_encoder()` (NULL on an empty
   possible-encoder list — `amdgpu_connector_best_single_encoder`
   :346-357, `amdgpu_connector_dvi_encoder` :1122-1148 both return NULL),
   and `enc_priv` itself, which `dce_v*_0_encoder_add` initializes to NULL
   (dce_v10_0.c:3494) and only replaces if
   `amdgpu_atombios_encoder_get_lcd_info()`/`get_dig_info()` kzallocs
   succeed (dce_v10_0.c:3520/3524/3528). The same file knows to guard
   `enc_priv` — see the coherent-mode handler at :484 — but not here.
   Reached from every modeset (`atombios_crtc.c:773`,
   `atombios_dp.c:261`, `dce_v{8,10,11}_0.c`).

2. `amdgpu_connector_set_property()` — scaling-mode branch:
   ```c
   } else {
       amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector));  /* :584 */
   }
   ...
   if (amdgpu_encoder->rmx_type == rmx_type)      /* :594 NULL deref */
   ```
   Reached via `DRM_IOCTL_MODE_SETPROPERTY` /
   `DRM_IOCTL_MODE_OBJ_SETPROPERTY` (both `DRM_MASTER`-gated —
   drm_ioctl.c:667/679): the display session owner.

3. `amdgpu_connector_set_lcd_property()` — identical pattern, deref at
   :803. Same ioctls (this is the eDP/LVDS `.set_property`).

## Reach

An empty (or NULL-producing) possible-encoder list requires the VBIOS to
describe a connector whose device bits no encoder claims —
`amdgpu_link_encoder_connector()` (amdgpu_encoders.c:45-56) then attaches
nothing. Atom-table parser quirk territory; upstream Linux carries the
identical unguarded code.

## Evidence

- `trigger_df4201.c` — raw-ioctl scaling-mode write over every connector
  property (becomes DRM master, enumerates connectors, writes
  DRM_MODE_SCALE_CENTER). Builds and runs on the guest; guest has no AMD
  GPU (`env.txt`), so the amdgpu handlers are unreachable there.
- `fix.diff` — NULL guards at all three sites (applies cleanly to a copy
  of the real file; cumulative with DF-4200/4202 diffs).

## Fix

See `fix.diff` (guard `best_encoder()` result at :584/:793; guard both
`encoder` and `enc_priv` in the monitor-bpc branch).
