β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2289

Off-by-one stack buffer overflow in crom_next depth guard allows kernel stack corruption

Summary

crom_next() checks cc->depth >= CROM_MAX_DEPTH before incrementing depth but CROM_MAX_DEPTH is 10 and stack[] has exactly 10 elements (indices 0-9). At depth==9 the guard 9>=10 is false so execution continues to depth++ (now 10) then ptr=&cc->stack[10] which is one past end. Writes ptr->dir (8 bytes attacker-controlled pointer) and ptr->index (4 bytes). Total 16 bytes written past stack array. Correct guard should be >= CROM_MAX_DEPTH-1. After overflow goto check dereferences ptr->dir->crc_len - attacker-controlled pointer read causing info leak or kernel panic. Trigger: malicious FireWire device with Config ROM containing chain of 10 nested CSRTYPE_D directory entries. Stack[10] writes at offset 168 of crom_context struct into saved registers/adjacent locals.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2289 Β· 6 files
FileTypeDescriptionSize
VERDICT.md verdict gate analysis + off-by-one depth-guard trace 3.5 KB ↓ raw
fix.diff suggested-fix guard depth >= CROM_MAX_DEPTH-1 371 B view raw
build.sh build-script documents HW gate 145 B view raw
run.sh run-script prints gate proof 257 B view raw
env.txt environment guest env 1.1 KB view raw
gate_proof.txt gate-proof no fwohci, no /dev/fw* 61 B view raw
VERDICT.md verdict gate analysis + off-by-one depth-guard trace
↓ download raw

DF-2289 β€” Off-by-one stack overflow in crom_next depth guard (fwcrom.c)

Verdict: NOT REPRODUCED (HW-gated); REAL BUG IN SOURCE (defense-in-depth fix warranted)

Hardware gate (why the PoC cannot run on this guest)

crom_next() parses IEEE 1394 Configuration ROM and is reached via the FireWire stack (e.g. crom_init_context / crom_search_key invoked while enumerating remote nodes). The audit QEMU/KVM guest has no FireWire controller and no /dev/fw* device:

$ pciconf -l | grep -iE "fwohci|firewire"   # (no output)
$ ls /dev/fw*                                # /dev/fw*: No such file or directory
$ ifconfig -l                                # vtnet0 lo0

Without an fwohci controller and a live 1394 peer there is no path to feed a crafted Config-ROM into crom_next. The unprivileged maxx user cannot open /dev/fw* (it does not exist), so no ioctl or userspace path reaches the parser on this guest.

Source trace β€” the bug is REAL (sys/bus/firewire/fwcrom.c)

Layout (iec13213.h:200-209):

#define CROM_MAX_DEPTH  10
struct crom_ptr   { struct csrdirectory *dir; int index; };
struct crom_context { int depth; struct crom_ptr stack[CROM_MAX_DEPTH]; };
                                       /* stack[0..9], 10 elements */

crom_next() (fwcrom.c:106-143):

reg = crom_get(cc);                          /* cc->stack[cc->depth] */
if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) {
    if (cc->depth >= CROM_MAX_DEPTH) {       /* line 115: checks BEFORE incr */
        kprintf("crom_next: too deep\n");
        goto again;
    }
    cc->depth ++;                            /* line 119: now depth == 10 */
    ptr = &cc->stack[cc->depth];             /* line 121: &stack[10] = ONE PAST END */
    ptr->dir  = (struct csrdirectory *)(reg + reg->val);  /* 8-byte attacker ptr */
    ptr->index = 0;                          /* + 4 bytes */
    goto check;
}

The guard at line 115 fires only when depth >= 10, but the array's last legal index is 9. So when the parser enters crom_next at depth == 9 (10th level of nesting already reached) and the current entry is a directory (CSRTYPE_D), the guard 9 >= 10 is false, execution proceeds to cc->depth++ (now 10) and ptr = &cc->stack[10] β€” one past the end of the 10-element array. ptr->dir (an 8-byte attacker-controlled pointer derived from reg->val) and ptr->index (4 bytes) are then written, a 16-byte stack overflow into whatever follows crom_context.stack[] (saved registers / adjacent locals). The correct guard is cc->depth >= CROM_MAX_DEPTH - 1 (i.e. >= 9), or move the increment-before-check.

After the overflow, goto check dereferences ptr->dir->crc_len (fwcrom.c:130) β€” an attacker-controlled pointer read β†’ kernel info-leak or panic.

Trigger: a malicious FireWire device whose Config ROM contains a chain of 10 nested CSRTYPE_D directory entries. No authentication; physical bus access.

Exploit chain status

Not pursuable β€” primitive is behind absent FireWire hardware (valid Phase-6 hard blocker: dead path at runtime + no harness can drive it on this guest without a live 1394 peer). The bug is a real 16-byte controlled stack overflow on FireWire-equipped hardware.

PoC changes

None. No PoC runnable: /dev/fw* absent, fwohci controller absent. Verified by source trace only.

Tighten the depth guard so the increment never reaches the sentinel index. See fix.diff (matches the finding proposal's intent β€” guard against depth >= CROM_MAX_DEPTH - 1).

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

not_testable: PoC cannot run on this guest (HW-gated, no target device). fix.diff validated by git apply --check (clean) + line-accurate source trace confirming it closes the cited path.

git apply --check findings/poc/DF-2289/fix.diff -> OK (clean apply). No runtime test possible (HW-gated).
↓ fix.diffn/a (no target HW/device on this guest)

Confirmed kernel references

Detail

Exploit chain

none β€” valid hard blocker (driver/device path dead at runtime on this guest: no target HW / no attached device). No unprivileged->root path.

Evidence (decisive lines)

usbconfig list -> No device match or lack of permissions.; pciconf -l -> no target controller HW; ifconfig -l -> vtnet0 lo0; kldstat -> kernel/ehci/xhci only; ls /dev/<target> -> No such file or directory; id maxx -> uid=1001 groups=1001 (not operator). Source confirmed at cited lines.

PoC changes

Created findings/poc/DF-2289/{VERDICT.md,fix.diff,build.sh,run.sh,env.txt,gate_proof.txt,manifest.json}. No PoC source (HW-gated).

Verified recommended fix

change guard to cc->depth >= CROM_MAX_DEPTH-1. Full git-apply-able diff in findings/poc/DF-2289/fix.diff (git apply --check OK).

Verdict

NOT REPRODUCED (HW-gated). The bug is REAL in source (traced line-by-line). fwcrom crom_next off-by-one stack overflow (depth>=10 guard is one late); no FireWire. Gate confirmed via usbconfig list (No device match / no /dev/ugen*), pciconf -l (no target controller HW), ifconfig (vtnet0 lo0 only), kldstat (no target module), and ls /dev (no target nodes). maxx (uid 1001, not in operator) cannot reach any /dev/usbctl write path.