# DF-5364 — Unchecked kmalloc(M_NOWAIT) in FUNCID/CONFIG handlers: NULL-page write

## Verdict in one line
Statically certain (model-demonstrated address computation): both
`kmalloc(sizeof(*state->pf), M_DEVBUF, M_NOWAIT | M_ZERO)` calls in the
tuple parser are immediately dereferenced with no NULL check — on
allocation failure the very next statement writes through NULL.

## Root cause (path:line)
CISTPL_FUNCID handler:
```c
if ((state->pf == NULL) || (state->gotmfc == 2)) {
        state->pf = kmalloc(sizeof(*state->pf), M_DEVBUF,
            M_NOWAIT | M_ZERO);                    /* :790-791  unchecked */
        state->pf->number = state->count++;         /* :792  NULL+0 write */
        ...
```
CISTPL_CONFIG handler:
```c
if (state->pf == NULL) {
        state->pf = kmalloc(sizeof(*state->pf),
            M_DEVBUF, M_NOWAIT | M_ZERO);           /* :837-838  unchecked */
        state->pf->number = state->count++;         /* :839  NULL+0 write */
```
The CFTABLE handler in the same function does it correctly
(`if (cfe == NULL) { DPRINTF(...); goto abort_cfe; }` at :910-913), which
makes the omission plain.

`offsetof(struct pccard_function, number) == 0`, so the write is to virtual
address 0 — an immediate kernel page fault / panic on amd64 and i386.

## Trigger / preconditions
`pccard_parse_cis_tuple` runs at every card insertion (pccard.c:195). The
allocation is small (~150 B), so failure requires kernel memory pressure
(kmalloc M_NOWAIT failing) — e.g. an already-memory-starved system at card
insert, or an attacker combining it with the DF-5362+DF-5361 unbounded
leak-loop to *manufacture* the exhaustion, then re-inserting a card whose
CIS leads with FUNCID or CONFIG. Low severity (DoS on top of memory
exhaustion), certain as a code defect.

## Model evidence (run.log, scenario `kmallocfail`)
```
=== S6 kmallocfail ===
RESULT: DF-5364 FUNCID kmalloc(M_NOWAIT) returned NULL; next kernel
  statement writes *(int*)(NULL+0) = 0  -> NULL-page write, panic
```
(The model injects a single allocation failure at the FUNCID pf alloc and
reports the address the kernel write would target; offsetof(number)=0.)

## Fix
Check for NULL and bail out of the tuple (fix.diff, also adds the
top-of-case guard in CFTABLE that hardens the DF-2319 default_cfe/pf
NULLs so the new break-outs cannot re-expose them).

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
