ppc_pc873xx_detect() static probe index never reset: OOB reads past pc873xx_basetab[] used as x86 I/O port numbers (wild inb/outb)
Summary
'static int index = 0' is never reset, so the second and later calls resume past the 5-entry basetable; the reads pick up adjacent kernel .data (and eventually rnametab POINTER values) and each value is used as the idport for inb/outb - semi-arbitrary I/O port writes (0x60/0x64/0x70/0x71/0xcf9 in reach) with the index advancing further on every call. Gated on PPC_PROBE_CHIPSET (LINT64 only) and >=2 parallel ports. One-word fix (drop 'static').
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4138 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | file | 2.3 KB | β raw | |
| manifest.json | file | 366 B | view raw | |
| verdict.json | file | 1.1 KB | view raw |
DF-4138 β ppc_pc873xx_detect() static probe index is never reset:
OOB read past pc873xx_basetab[] used as an I/O port number
Root cause
sys/dev/misc/ppc/ppc.c:432-439:
static int
ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode)
{
static int index = 0; /* <-- static, never reset */
...
while ((idport = pc873xx_basetab[index++])) {
(void)inb(idport); ...
outb(idport, PC873_SID);
val = inb(idport + 1);
pc873xx_basetab[] (ppc.c:415) has 5 entries (4 ports + 0 sentinel).
index is a function-static that is never re-initialized; every call
to ppc_pc873xx_detect resumes where the previous one stopped.
- 1st call (1st parallel port): walks the table from 0.
- 2nd call (2nd port, or a re-probe):
pc873xx_basetab[5],[6], ... β out-of-bounds reads of kernel .data past the table. The values read there (e.g.pc873xx_porttab[]= 0x378/0x3bc/0x278, thenpc873xx_irqtab[], then thepc873xx_regstab[]contents and finally the pointer values ofpc873xx_rnametab[]) are used asidport:inb(idport)/outb(idport, PC873_SID)/inb(idport + 1)are executed on arbitrary port numbers β including writes to semi-arbitrary x86 I/O ports (keyboard 0x60/0x64, POST/reset 0xCF9, CMOS 0x70/0x71 are all in reach depending on adjacent .data), and the loop keeps advancing on every call, reading further and further past the array.
Reachability
Gated on options PPC_PROBE_CHIPSET (ppc.c:406/1274/1295): not in
GENERIC (X86_64_GENERIC does not compile ppc at all); enabled only in
LINT64 or custom kernels, and needs >= 2 ppc attach attempts through the
chipset detect loop (2+ ISA parallel ports, or repeated probes). The
ppc driver itself is not in the shipped GENERIC kernel and the
paravirtual guest has no ISA parallel port, so this is source-level
certainty only.
Fix
--- a/sys/dev/misc/ppc/ppc.c
+++ b/sys/dev/misc/ppc/ppc.c
@@ -433,7 +433,7 @@
static int
ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode)
{
- static int index = 0;
+ int index = 0;
int idport, irq;
int ptr, pcr, val, i;
(the variable was pointlessly static; it must start at 0 per probe).
Verification
Skipped live (hardware-gated: guest has no parallel port; driver not in GENERIC; option not enabled). Analysis-certain: the missing reset is unambiguous from source.
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
README.md analysis (ppc.c:415,435,439-460)
PoC changes
n/a - analysis only
Verified recommended fix
Make the probe index a local (reset per call).
Verdict
ppc_pc873xx_detect uses a function-static index that is never reset (ppc.c:435); on the second and later invocations pc873xx_basetab[index++] reads past the 5-entry table and the garbage value is used as an x86 I/O port for inb/outb (including writes) - unbounded OOB reads of kernel .data turned into semi-arbitrary port I/O. Gated on options PPC_PROBE_CHIPSET (LINT64-only; ppc is not in GENERIC) and multiple probe invocations, so hardware/option-gated: source-level certainty, no live guest (no ISA parallel port).
No comments yet.