init_transmitter_control steers handler selection with uninitialized stack byte crev when the VBIOS master command table lacks dig1transmittercontrol (v2 twin of DF-4047's sub-issue)
Summary
A failed parse leaves crev unwritten (the atom parse returns false without touching it when the master table entry is 0) and BREAK_TO_DEBUGGER is WARN-only in release, so the switch runs on an uninitialized kernel-stack byte selecting the v1_6 handler (garbage 6) or NULL (bounded outcomes: EXEC fails cleanly or the NULL is guarded). Hardening-grade like the DF-4047 v1 twin. Initialize-crev fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4612 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.2 KB | β raw | |
| VERDICT.md | β | 2.9 KB | β raw | |
| env.txt | β | 273 B | view raw | |
| fix.diff | β | 726 B | view raw | |
| manifest.json | β | 734 B | view raw | |
| verdict.json | β | 2.9 KB | view raw |
DF-4612 β init_transmitter_control steers handler selection with uninitialized crev (command_table2.c)
What
sys/dev/drm/amd/display/dc/bios/command_table2.c:176-192
static void init_transmitter_control(struct bios_parser *bp)
{
uint8_t frev;
uint8_t crev;
if (BIOS_CMD_TABLE_REVISION(dig1transmittercontrol, frev, crev) == false)
BREAK_TO_DEBUGGER();
switch (crev) { /* <-- crev uninitialized when the parse failed */
BIOS_CMD_TABLE_REVISION β amdgpu_atom_parse_cmd_header() (sys/dev/drm/amd/amdgpu/atom.c:1405-1420)
returns false without writing *crev when the master command table has no
dig1transmittercontrol entry (if (!mct[index]) return false;, atom.c:1412-1413).
BREAK_TO_DEBUGGER() is WARN_ON(1) in release builds (os_types.h:76-79) β it
warns and falls through into switch (crev) on an uninitialized stack byte.
Twin of the uninit crev steering in init_transmitter_control sub-issue of
DF-4047 (which covered the v1 file command_table.c). This is the v2
(firmware-parser, command_table2.c) instance.
Build / run
Not runnable on the audit QEMU guest: the path requires an AMD GPU whose VBIOS
is parsed by the DC firmware parser (amdgpu driver attach). The guest has a
virtio-vga adapter only (env.txt β no drm/amd, no AMD PCI device).
Expected behavior (if hardware were present)
With a VBIOS whose master command table lacks the dig1transmittercontrol
pointer, crev is an uninitialized kernel-stack byte:
* garbage == 6 β binds transmitter_control_v1_6 for a table that does not
exist; the later EXEC fails cleanly at atom.c:1206-1207 (base == 0 β
-EINVAL).
* garbage != 6 β bp->cmd_tbl.transmitter_control = NULL, which the caller
checks (bios_parser2.c:1004) and returns BP_RESULT_FAILURE.
So the worst observable effect is an uninitialized-stack read steering
control flow (info leak into handler selection / MSan-class defect), not an
OOB. Defense-in-depth fix: initialize crev and return early on parse
failure.
Contents
VERDICT.mdβ full analysis and verdictenv.txtβ guest evidence (no AMD GPU present)fix.diffβ git-apply-able fixmanifest.json,verdict.json
VERDICT β DF-4612
Status: not_reproduced (target hardware absent from the audit guest β no AMD GPU / amdgpu driver instance; VBIOS command-table parsing never executes there). The defect is proven statically, line-accurate, with certain confidence.
Narrative
init_transmitter_control() (command_table2.c:176-192) asks the ATOM master
command table for the dig1transmittercontrol entry's revision:
uint8_t frev; uint8_t crev;
if (BIOS_CMD_TABLE_REVISION(dig1transmittercontrol, frev, crev) == false)
BREAK_TO_DEBUGGER();
switch (crev) {
case 6: bp->cmd_tbl.transmitter_control = transmitter_control_v1_6; break;
default: bp->cmd_tbl.transmitter_control = NULL; break;
}
amdgpu_atom_parse_cmd_header() (amdgpu/atom.c:1405-1420):
int idx = CU16(ctx->cmd_table + offset);
u16 *mct = (u16 *)(ctx->bios + ctx->cmd_table + 4);
if (!mct[index])
return false; /* <-- *frev/*crev NEVER written */
*frev = CU8(idx + 2);
*crev = CU8(idx + 3);
So on a VBIOS image whose master command table has a zero pointer for the
dig1transmittercontrol slot (malformed / attacker-reflashed / truncated
image β the image is otherwise barely validated at this point per DF-4345),
crev keeps its uninitialized stack value and steers the switch.
BREAK_TO_DEBUGGER() is ASSERT(0) β WARN_ON(1) in release
(dc/os_types.h:72-79): warns, does not stop execution.
Impact assessment (honest ceiling)
- uninitialized stack byte read that influences control flow;
- garbage
6β binds v1_6 handler; its laterEXEC_BIOS_CMD_TABLEresolves the master-table entry tobase == 0andamdgpu_atom_execute_table_lockedreturns-EINVAL(atom.c:1206-1207) β cleanBP_RESULT_FAILURE; - garbage
!= 6β NULL pointer stored; all call sites NULL-check (bios_parser2.c:1004) β clean failure.
No OOB, no info leak out of the kernel. Severity Low (hardening class), consistent with the DF-4047 v1 twin. The realistic attack prerequisite (a VBIOS image you control on the card) already implies greater power, which is why this stays Low.
Why not reproduced on the guest
env.txt: the audit guest is QEMU with a virtio-vga GPU (vgapci0
chip=0x11111234), no AMD display PCI device, no amdgpu/drm-amd module
loaded. command_table2.c is only reachable during amdgpu DC construction.
No PoC can exercise it there. Static trace is complete and cited.
Fix
Initialize crev = 0 and bail out of init_transmitter_control() when
BIOS_CMD_TABLE_REVISION fails (setting the handler to NULL, which callers
already handle). 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_testableBaseline never manifests on this guest (no AMD GPU); fix is a one-line initialization with no behavioral risk. Cannot build an amdgpu DC kernel test on the QEMU std-vga guest.
fix.diff initializes crev=0 at declaration; parse failure then takes the default NULL-handler path which bios_parser2.c:1004 already guards.
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (line-accurate trace: command_table2.c:176-192, amdgpu/atom.c:1405-1420, dc/os_types.h:72-79 WARN_ON release semantics, bios_parser2.c:1004 NULL check); env.txt (no AMD display device / driver on guest)
PoC changes
none - no PoC possible without AMD hardware; static trace only
Verified recommended fix
Initialize crev=0 in init_transmitter_control so a failed BIOS_CMD_TABLE_REVISION cannot steer handler selection with an uninitialized stack byte.
Verdict
init_transmitter_control (command_table2.c:181-183) switches on an uninitialized stack byte crev whenever amdgpu_atom_parse_cmd_header fails (returns false at amdgpu/atom.c:1412-1413 without writing *crev, i.e. the VBIOS master command table lacks the dig1transmittercontrol entry). BREAK_TO_DEBUGGER() is WARN_ON(1) in release, so execution falls through into switch(crev). Outcome is bounded: crev!=6 stores NULL (callers NULL-check, bios_parser2.c:1004) and crev==6 binds a handler whose EXEC then fails cleanly with -EINVAL (atom.c:1206-1207). No OOB, no leak - Low/hardening, the command_table2.c twin of DF-4047's v1 sub-issue. Not reproducible on the audit guest: no AMD GPU (virtio-vga only, see env.txt), so the DC firmware parser never runs.
No comments yet.