# DF-5336 — db_disasm Grp7_11 sub-table inner-index OOB read

## What

`sys/cpu/x86_64/misc/db_disasm.c:1275`:

```c
i_name = db_Grp7_11[f_reg(rex, regmodrm)][regmodrm &0x7];
```

When disassembling `0f 01 /r` with mod==3 (`regmodrm >= 0xC0`), the **inner**
index (`regmodrm & 0x7`, the rm field, 0..7) selects from the sub-tables
`db_Grp7_11_{000,001,010,111}` which have only **5, 4, 7 and 2 entries**
(db_disasm.c:174-211). rm values beyond each table's length read a
`const char *` from **adjacent kernel .rodata**, which is then printed by
`db_printf("%s", i_name)` at db_disasm.c:1303.

**No REX prefix is required** — unlike the known DF-1033 — and the defect is
on a *different index* than DF-1032 (outer `f_reg` into the 6-entry
`db_Grp7_11` array) and DF-2360 (NULL `db_Grp7_11[3]/[4]` + REX wild derefs).
A fix that only bounds `f_reg` and NULL-checks (the known findings) leaves
this bug fully reachable.

## Trigger encodings (mod=3)

| bytes            | reg | rm | table hit        | len | result on stock kernel |
|------------------|-----|----|------------------|-----|------------------------|
| `0f 01 c5`/`c7`  | 0   | 5/7| `_000[5]`,`_000[7]` | 5 | `(null)` — reads 0 alignment padding past the array |
| `0f 01 cc`       | 1   | 4  | `_001[4]`        | 4   | `""` — reads `_000[0]` (pointer to `""`) |
| `0f 01 d7`       | 2   | 7  | `_010[7]`        | 7   | `(null)` — reads padding |
| `0f 01 ea`       | 5   | 2  | `_111[2]`        | 2   | **`xgetbv`** — reads `db_Grp7_11_010[0]`, a *different table* |
| `0f 01 ef`       | 5   | 7  | `_111[7]`        | 2   | **`xend`** — reads `db_Grp7_11_010[5]` |

Adjacency proof (guest `nm -n /boot/kernel/kernel`):

```
ffffffff80d9d330 r db_Grp7_11_111   (+16 = 0x...d340)
ffffffff80d9d340 r db_Grp7_11_010   <- _111[2] lands exactly here
```

`db_Grp7_11_111[2]` == the qword at `0xffffffff80d9d340` == `db_Grp7_11_010[0]`
== pointer to `"xgetbv"` — byte-for-byte what the disassembler printed.

## Reachability / threat model

DDB disassembles kernel-memory content: `x/i` at the `db>` prompt
(db_examine.c:178) and automatic instruction printing in panic backtraces
(`db_print_loc_and_inst`, db_examine.c:259). Any path that disassembles
attacker-influenced kernel memory (corrupted buffers, injected bytes, a
jump into data) with the encodings above performs the OOB read. Impact:
deterministic disclosure of adjacent kernel .rodata content on the DDB
console (cross-table reads; with pointer-valued adjacency this discloses
.rodata addresses — pointer-KASLR-relevant), and layout-dependent potential
for `db_printf("%s")` to dereference a non-pointer qword (wild deref,
debuger DoS). DDB access requires console/serial or an in-kernel
`Debugger()` event, hence Low severity — consistent with DF-1032/DF-2360.

## Build / run (on the DragonFly guest as root)

```
cd /root/df5336
export SYSDIR=/usr/src/sys
make            # builds df5336_oob.ko via bsd.kmod.mk
kldload ./df5336_oob.ko     # prints the test matrix to the console
kldunload df5336_oob
```

Expected (stock kernel): the 5 CTRL lines print real mnemonics
(vmxoff/monitor/xtest/swapgs/rdtscp); the 6 OOB lines print `(null)`,
empty, `xgetbv`, `xend` — content that provably is not in the indexed
sub-table.

## Fix validation

`fix.diff` pads all four sub-tables to 8 entries and bounds the outer
index (`reg > 5` / NULL → `""`). After `quickkernel` + `installkernel` +
reboot, the same PoC prints: controls unchanged, **all 6 OOB lines empty**
(`run.patched.log`). The fix also incidentally hardens the outer-index
cases of DF-1032/DF-2360 on this line.

## Files

* `df5336_oob.c` / `Makefile` / `build.sh` / `run.sh` — the PoC
* `run.log`, `run.2.log`, `run.3.log` — stock kernel, 3 identical runs
* `run.patched.log` — fixed kernel
* `fix.diff` — git-apply-able fix (validated in-guest)
* `fix_build.log`, `build.log` — kernel + KLD build output
* `env.txt` — guest uname, cc, osreldate, symbol-table excerpt
* `VERDICT.md`, `manifest.json`, `verdict.json`
