# DF-4047 VERDICT — NULL helper dispatch from BIOS-controlled command revisions (command_table.c)

## Reproduced?

**Source-certain; dispatch model verified on the guest** (userland replica
`null_helper_dispatch`, `build.log`/`run.log`). The kernel manifestation is
**hardware-gated**: the guest has no AMD GPU, so no amdgpu/DC device attaches
and no VBIOS image is parsed. Per the DF-3942 convention (crafted/corrupt
VBIOS → NULL deref at attach) the persisted status is `inconclusive`,
impact `panic`, confidence `certain`.

## Why this is real (path:line chain)

0. Parser selection is itself BIOS-controlled: `dal_bios_parser_create`
   (`bios_parser_interface.c:35-48`) tries `firmware_parser_create`
   (bios_parser2/command_table2.c) first and falls back to the v1
   `bios_parser_create` (this file's parser) whenever the VBIOS lacks an
   atom rom header v2.2+ / display-object-info v1.4
   (`bios_parser2.c:1912-1975`) — so a crafted VBIOS chooses *both* the
   v1 parser and the old command revisions in one image.
1. Helper tables with NULLs: `dce110/command_table_helper_dce110.c`
   (`.assign_control_parameter = NULL`, `.clock_source_id_to_ref_clk_src =
   NULL`, `.transmitter_bp_to_atom = NULL`), same three in
   `dce112/command_table_helper_dce112.c`; dce80's table is fully populated.
   Bound to bp->cmd_helper for DCE 10.0/11.0 (dce110) and 11.2/11.22 (dce112)
   by `command_table_helper.c:38-57`.
2. Revision is BIOS-controlled: `BIOS_CMD_TABLE_PARA_REVISION` /
   `BIOS_CMD_TABLE_REVISION` read frev/crev out of the mapped VBIOS command
   master table (`command_table.c:42-48`, `atom.c:1405-1420`).
3. Dispatch selects old handlers on old revisions:
   `init_dig_encoder_control :120-141` (default → v1 path when DIGx ∉
   {2,4,5}; `init_encoder_control_dig_v1 :153-168` wires dig1/dig2 when
   their crev == 1), `init_transmitter_control :367-396` (crev 2 → v2,
   crev 4 → v4).
4. The selected handlers call the NULL helper unconditionally as part of
   building parameters: `:204`, `:219` (`assign_control_parameter`),
   `:507` (`transmitter_bp_to_atom` — executed before every
   `EXEC_BIOS_CMD_TABLE`), `:678` (`clock_source_id_to_ref_clk_src`,
   before input validation completes).
5. CWE-457 aggravator: `init_transmitter_control :367-375` switches on
   uninitialized stack `crev`/`frev` when the command is absent, because
   `amdgpu_atom_parse_cmd_header` (`atom.c:1412-1413`) returns false
   without writing the out-params.
6. No NULL-check exists anywhere on `bp->cmd_helper->X` in this file
   (verified by grep — every other helper used is non-NULL in all three
   tables; only these three are NULL, and only in dce110/dce112).

Result: crafted/corrupt VBIOS on a DCE10/11/11.2 part → NULL function
pointer call → kernel page fault at the first DIG encoder / transmitter
setup (attach or first modeset). Same threat model and severity family as
DF-3942 (Low, crafted VBIOS).

## Model verification (guest)

`null_helper_dispatch.c` encodes the three helper tables and the
`command_table.c` dispatch logic 1:1; run on the guest it prints, for each
(DCE version, crafted revision) combination, the exact NULL helper that the
kernel would call — plus the two negative controls (honest DCE11 revisions
and any DCE8.0 combination) which select no NULL call. Output in `run.log`.

## Fix

Guard the dispatch: refuse revisions whose handler requires a helper the
selected table does not provide, zero-initialize frev/crev, and fail
`init_transmitter_control` cleanly when the command header is absent.
`fix.diff` implements the minimal defensive form (zero-init + NULL handler
on parse failure + NULL-checks at the four call sites).

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