# DF-3201 — unbounded rule-application recursion via self-matching LINK rules (stack exhaustion)

## Root cause
`devfs_allocp()` applies the rule engine to every newly created node
(`devfs_core.c:291-292`):

    check_apply(node) -> create_link() -> devfs_alias_create()
                      -> devfs_allocp(alias) -> check_apply(alias) -> ...

A LINK rule whose own output matches itself therefore recurses without bound.
Rule `{ NAME "*", LINK, linkname "y" }`: node `foo` gets alias `yfoo`
(strip = strlen("*")-1 = 0), `yfoo` matches `"*"` too -> `yyfoo` -> ...

Each recursion level nests `devfs_rule_check_apply` +
`devfs_rule_checkname` (PATH_MAX stack buffer) + `devfs_rule_create_link`
(TWO PATH_MAX stack buffers) ≈ 3 KB of stack per generation — the kernel
stack is gone after a handful of generations, even though names grow only
one byte at a time.

## Reproduced
`panic: double fault`, rip = 0xffffffff809243cc = `devfs_rule_create_link+0x1c`
(symbolized via nm on the guest kernel) — the crash sits inside the first
PATH_MAX buffer frame of the nested create_link. Trigger: a single
DEVFS_RULE_ADD + DEVFS_RULE_APPLY as root (or jailed root via DF-3197).
Even without the stack blowup the same self-match drives unbounded node
creation under devfs_lock (devfs-wide livelock / memory exhaustion).

## Fix
`fix.diff`: (a) depth cap (8) on rule-driven LINK creation in check_apply,
(b) create_link/checkname PATH_MAX buffers moved from stack to heap.
Validated: post-fix the same rule applies without a panic (`run.fixed.log`).

## Files
`selflink_rec.c`, `build.sh`, `run.sh`, `panic.txt`, `fix.diff`,
`run.fixed.log`, `verdict.json`, `manifest.json`

## 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.
