# DF-4105 — amdgpu atombios_encoders: fake-EDID record leaves uninitialized kmalloc tail that can be read back by unprivileged users (CWE-457), plus uninit `extensions` byte drives an OOB walk in drm_edid_is_valid

File: `sys/dev/drm/amd/amdgpu/atombios_encoders.c` (pass 2)
Class: uninitialized kernel heap memory disclosure (CWE-457/908) + OOB read
Hardware gate: AMD GPU, LCD encoder with a fake-EDID patch record in VBIOS.
Source-level certainty.
Related: DF-1380 (same record loop — bounds of the *walk* and the OOB
memcpy source; this finding is the *uninitialized tail of the destination*
— different read source, different fix). radeon twin: DF-3744 mentions the
leak conditionally; here it is isolated with the exact gate.

## The defect

atombios_encoders.c:2167-2183:

```c
case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
    fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
    if (fake_edid_record->ucFakeEDIDLength) {          /* u8, 1..255 */
        struct edid *edid;
        int edid_size = max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength);  /* >= 128 */
        edid = kmalloc(edid_size, M_DRM, GFP_KERNEL);  /* NOT zeroed */
        if (edid) {
            memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0],
                   fake_edid_record->ucFakeEDIDLength);   /* only `len` bytes */
            if (drm_edid_is_valid(edid)) {
                adev->mode_info.bios_hardcoded_edid = edid;
                adev->mode_info.bios_hardcoded_edid_size = edid_size;
```

When `1 <= ucFakeEDIDLength < 128`, bytes [len, 128) of the 128-byte
kmalloc chunk are **uninitialized heap**. Two consequences:

1. `drm_edid_is_valid` (drm_edid.c:1484-1497) loops `for (i = 0; i <=
   edid->extensions; i++) drm_edid_block_valid(raw + i*128, ...)`.
   `edid->extensions` is byte 126 — uninitialized when len < 127. A garbage
   non-zero value makes the loop read up to 255 additional 128-byte blocks
   **past the 128-byte allocation** (OOB heap read; each block is fully
   read before its checksum rejects it).
2. If the garbage happens to pass the block-0 checksum (~1/256 per boot
   for a random tail), the EDID is cached with the uninit tail included,
   and `amdgpu_connector_get_edid` (amdgpu_connectors.c:269-274) copies
   the full `bios_hardcoded_edid_size` (128) bytes into the connector's
   EDID, which any unprivileged user can read back with
   `DRM_IOCTL_MODE_GETCONNECTOR` (hw.backlight EDID property) → **kernel
   heap info leak of up to 127-len bytes**.

## Build / Run
Hardware-gated; audit guest has no AMD GPU. See VERDICT.md.

## Fix
Zero the allocation (`kzalloc`) — one line. See fix.diff.
