dmcub/ — the DCN display microcontroller (DMCUB / DMUB)
New target, opened 2026-09. Read in this order:
AUDIT-DMCUB-03-COMMANDS.md— the per-command audit of all 24 implementedDMUB_CMD__*types, three candidate findings, and the coverage limits.AUDIT-DMCUB-07-DPAUX.md— the newer images (3.5/3.6/4.0.1): a taint-root bug that had made the whole 4.0.1 run a false negative, the retraction of the "DP_AUX_ACCESSis a stub everywhere" claim, and FINDING-11.AUDIT-DMCUB-02.md— dispatcher/register-map infrastructure, the address base, and the first finding.AUDIT-DMCUB-01.md— provenance, container format, ISA determination (partially superseded; carries a banner).
Short version: the DMCUB is a Tensilica Xtensa (windowed ABI) microcontroller
inside AMD's DCN display IP, PSP-loaded, body mapped at 0x60000000
(VA = 0x60000000 + file_off - 0x200), driven by the host over a 64-byte-frame
inbox ring plus a GPINT doorbell. For Navi 31 the image is
fw/dcn_3_2_0_dmcub.bin, 1036 functions, 24 implemented command types.
Three candidate findings so far, all static only, all host→DMCUB (the inbox is
driven by amdgpu, so none is a privilege escalation for the host — see the threat
model note in AUDIT-DMCUB-02.md):
| # | command | primitive |
|---|---|---|
| 1 [HW] | ABM_INIT_CONFIG (66) |
unchecked 16-bit bytes → confirmed on hardware: ~32 KB of attacker-supplied data written past a 712-byte slot (bytes=0x8000, 32492 bytes changed, processed cleanly); bytes ≥ 0x9c00 also wedges the command loop |
| 8 [HW] | (firmware loading) | DMUB rollback works — 7.0.38 / 7.0.42 load and run on a card shipping 7.0.51, and a DCN 3.5 image is accepted and starts executing on DCN 3.2 silicon. Signature enforced, version/ASIC binding absent. Dates findings 1/2/3 to ≥ 7.0.38 (2024-02) |
| 6 [HW] | ABM_INIT_CONFIG (66) |
one command with bytes ≥ 0x9c00 wedges the inbox command loop (display DoS); SCRATCH0/timer still look healthy, so liveness must be judged by ring consumption |
| 2 [HW] | GET_VISUAL_CONFIRM_COLOR (8) |
unbounded 16-bit panel_inst → 8-byte OOB read returned to the host. Confirmed on hardware: indices 2..227 return memory past the 2-entry array. The DoS leg is retracted (out-of-window reads return zeros) |
| 3 [HW partial] | HW_LOCK (69) |
unbounded 8-bit dig_inst → register pointer fetched past a 7-entry table, then read-modify-written. Hardware: reachable and dig_inst provably selects the register (1/2/3 → OTG1/2/3), but no OOB write achieved — the table lives in PSP-owned CW0, so the pointer value is never attacker-controlled. Latent, not a primitive |
| 4 [HW not demonstrated] | REPLAY (83), CACP (87), VBIOS (128) |
handlers run and write state, but the offsets are index-independent for idx 0..255; Replay is additionally caller-bounded (bgeui idx, 2). Same class: an unchecked panel_inst/instance byte scaled by 0x130 / 0x30c / 0xd4 into per-instance state or into the register-address table (Replay's is a plain s8i write; AMD's own ABI says that field "is only 0 or 1") |
| 11 [ST+EMU] | DP_AUX_ACCESS (70), in yellow_carp, dcn_3_1_4, dcn_3_5, dcn_3_6 |
unchecked 8-bit instance on the DPIA path → host-controlled 1-byte write at base + <off> + instance, stride 1, up to 252 bytes past a 4-entry array, repeatable. The sibling function on the same path applies the intended instance < 4 bound (3×) one call too late. Reaches a multiply-referenced adjacent structure at instance 8–12. Stays inside the mapped data region (adjacent-global corruption, not a wild write). Stubbed in 3.2.x/4.0.1, which is why a 3.2.0-anchored audit missed it. See AUDIT-DMCUB-07-DPAUX.md |
Newer images (dcn_3_5, dcn_4_0_1) implement 31 command types including
DMUB_CMD__PSP, LSDMA (host-supplied DMA src/dst/count) and FUSED_IO; those are
static-only leads because the 4.0.1 image is refused by this card's PSP and the 3.5
image will not finish booting on DCN 3.2. DP_AUX_ACCESS (70) is a stub in
3.2.0 and 4.0.1 — but not in 3.5/3.6, where it is fully implemented and
carries FINDING-11; the earlier generalisation that "there is no AUX sink path via
that command in any image we hold" was retracted in
AUDIT-DMCUB-07-DPAUX.md. Only the two stub images had been checked.
Also recorded [HW]: the host cannot program DMCUB_REGION3_CW0/CW1 or
DMCUB_SEC_CNTL (writes dropped, reads 0), so backdoor_load is blocked on Navi
31 and DMCUB code execution requires a PSP-signed image — a security-positive
result, and the reason bring-up goes through GFX_FW_TYPE_DMUB.
Also recorded: types 1/3/4 are the legacy REG_SEQ_* / REG_REG_WAIT commands and
are an intentional arbitrary register read/write/poll interface. They are
documented ABI, not "unpublished" as this tree said until corrected — present in
enum dmub_cmd_type from v5.6 through v6.18-rc1 and deleted from the header only by
upstream commit 9a591ae691b5 (2026-06-05, "command IDs 1-4 have been deprecated").
fetch_ref.sh pulls master, which is why they looked undocumented. The firmware
still dispatches them in every image in fw/, including DCN 4.0.1 — the
deprecation is header-only. Name IDs from the pinned ref/dmub_cmd_v6.17.h;
DP_AUX_ACCESS (70) is a stub in this build (3.2.0 only — see FINDING-11 for
3.5/3.6). Bounded and closed: EDID/CEA
reassembly and its VSDB parse, all 23 jx dispatches, 27/28 callx8 sites (the
one indexed site is double-guarded), and 55 of 57 memcpy sites.
Tooling
Xtensa needs capstone 6; the system capstone (5.0.9) has no CS_ARCH_XTENSA:
python3 -m venv /home/user/.venvs/cs6 && /home/user/.venvs/cs6/bin/pip install --pre capstone
dmcub_cfg.py and dmcub_regmap.py must run under that interpreter; the other
scripts work with the system python. IDA 9.3/9.4 also ship procs/xtensa.so
(this corrects the note in psp_out/FIRMWARE-INVENTORY.md).
./fetch_ref.sh # kernel reference sources -> ref/
python3 dmcub_parse.py fw/*.bin # container + dmub_fw_meta_info
python3 dmcub_isa_evidence.py fw/dcn_3_2_0_dmcub.bin 0x1c100 0x44000 # ISA + controls
V=/home/user/.venvs/cs6/bin/python
$V dmcub_dis.py fw/dcn_3_2_0_dmcub.bin hot 12 # hottest call targets
$V dmcub_dis.py fw/dcn_3_2_0_dmcub.bin dis 0x6001c780 # the inbox1 dispatcher
$V dmcub_regs.py fw/dcn_3_2_0_dmcub.bin ref/dcn_3_2_0_offset.h access --grep INBOX
$V dmcub_regs.py fw/dcn_3_2_0_dmcub.bin ref/dcn_3_2_0_offset.h vote # aperture evidence
$V dmcub_jxaudit.py fw/dcn_3_2_0_dmcub.bin # jump-table bounds audit
$V dmcub_copyaudit.py fw/dcn_3_2_0_dmcub.bin # memcpy length audit
$V dmcub_dpaux_audit.py fw/*.bin fw/old/*.bin # FINDING-11 cross-version sweep
$V dmcub_emu_dpaux.py --selftest # FINDING-11 in emulation (7 controls x2 images)
dmcub_cmdaudit.py auto-detects which register holds the command-frame pointer
(a3 on 3.2.x/3.5/3.6, a4 on 4.0.1/renoir) and prints a WARNING: ... Treat
every "0 sinks" result in this run as UNVERIFIED line if taint never entered a
case's handlers. Do not trust a run that prints it — that warning exists because a
hardcoded a3 silently produced a clean audit of 30 unexamined command types.
Hardware PoC (Option A)
hw/ brought the DMCUB up on the rig and reproduced FINDING-2 on silicon
(2026-09). The tinygrad-AM stack initialises no display IP, so the core is loaded
via the PSP (GFX_FW_TYPE_DMUB, stock signed image) and then driven over inbox1.
Read hw/README.md; transcript in hw/EVIDENCE-type8-poc.txt.
Contents
fw/— 10linux-firmwareimages, Renoir .. DCN 4.0.1 (hashed indata/MANIFEST.sha256).ref/— untracked upstream kernel sources (register offsets,dmub_cmd.hABI, loader); re-fetch withfetch_ref.sh.AUDIT-DMCUB-01.md— the audit.dmcub_*.py— analysis tools, described at the bottom of the audit.hw/— hardware bring-up + PoC scripts (probe, bring-up, type-8 PoC), dry-run by default, plus offline selftests.
