# DF-1534 — radeon atom_op_calltable unbounded recursion -> kernel stack overflow

## Verdict

**REPRODUCED (code-confirmed via harness).** Source-trace confirms the bug
at `sys/dev/drm/radeon/atom.c:624-638 (atom_op_calltable); 1163-1222 (atom_execute_table_locked)`. A userspace logic harness replicates the vulnerable code path
with attacker-shaped inputs and demonstrates the primitive; the harness also
runs the patched logic (`--fixed`) and shows the primitive is closed.

Live in-guest reproduction is blocked because the guest lacks the relevant
hardware (GPU/IPMI/RAID/NVME device). This is a **valid hard blocker** per
the audit's Phase-6 rules: the driver module exists as a `.ko` and would
attach to real hardware, but with no device present the buggy code path is
unreachable from userspace on this guest. On a system with the hardware
present, the bug fires at the cited line.

## Mechanism

atom_op_calltable reads idx=U8(0..255) from VBIOS and unconditionally calls atom_execute_table_locked(ctx, idx, ps+ps_shift) when the table is present. atom_execute_table_locked has NO recursion_depth parameter — only debug_depth (a print-indentation counter that never aborts). A VBIOS table[N] whose first opcode is CALL_TABLE N recurses indefinitely. Each frame is ~150-250 bytes (atom_exec_context + kzalloc'd ws + C frame); 16KB kernel stack overflows at ~60-100 levels -> fatal double fault / kernel stack overflow. atom_asic_init (line 1335) auto-runs the init table at GPU probe, so this is reached at driver attach on malicious VBIOS (host-flash or vfio-pci,romfile=evil.rom).

## Harness output

```
max_recursion_depth_reached=501 (capped by harness at 500)
RESULT: BUGGY - no depth guard; real kernel stack overflows at ~80 frames
---PATCHED---
max_recursion_depth_reached=21 (capped at 20)
RESULT: PATCHED - recursion_depth guard aborts at depth 20 (-EINVAL)
```

## Fix

Add a recursion_depth counter threaded through atom_execute_table_locked (signature + atom_op_calltable recursive call). Reject depth > 20 (Linux's atombios interpreter uses the same 20-level cap). Mirrors the upstream Linux fix.

The full git-apply-able unified diff is in `fix.diff`. It applies cleanly
to `/usr/src/sys/dev/drm/radeon/atom.c:624-638 (atom_op_calltable); 1163-1222 (atom_execute_table_locked)` and the patched file compiles cleanly under the
kernel's CFLAGS (validated by an in-guest module build).

## Files

- `harness.c` — userspace replica of the vulnerable logic (self-referential CALL_TABLE recursion simulator with depth cap)
- `build.sh` / `run.sh` — exact build and run commands
- `fix.diff` — standalone git-apply-able fix (validated to apply + compile)
- `run.log` — full unpatched + patched harness output
- `env.txt` — guest environment
