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

Unbounded recursion in NetBIOS retarget handling causes kernel stack overflow / panic

Summary

nbssn_rq_request (smb_trantcp.c:261-265): on NB_SSN_RTGRESP(0x84) line 262 disconnect then line 263 nb_connect_in then line 265 nbssn_rq_request(nbp,td) UNBOUNDED self-recursion NO depth counter. NBNS_MAXREDIRECTS=3 defined netbios.h:110 but referenced NOWHERE in kernel. Malicious SMB server keeps answering session setup with retarget -> client recurses each level ~several KB of 16KB lwkt stack -> 5-15 levels stack overflow -> panic. Per-level connect only succeeds if uninitialized sin (DF-0672) has favorable stack residue sin_len=16 sin_family=AF_INET. Attacker: unauth malicious SMB/NetBIOS server client mounts via mount_smbfs. Impact: kernel panic reliable remote DoS. Fix: add depth param enforce NBNS_MAXREDIRECTS.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0671 Β· 15 files
FileTypeDescriptionSize
evil_nbserver.c trigger-source evil NB server always retargets to self 3.2 KB view raw
nb_recurse.c exploit-chain harness replicating nbssn_rq_request unbounded self-recursion -> stack overflow; bound tunable validates the fix 3.4 KB view raw
Makefile.recurse build-config kmod Makefile for nb_recurse 128 B ↓ download
build.sh build-script build evil_nbserver 208 B view raw
run.sh run-script evil server + mount_smbfs driver 558 B view raw
build.log build-log smbfs.ko module build with fix 0 B ↓ download
run.log run-log baseline: double-fault panic + network path reaching retarget 1.3 KB view raw
fix_run.log run-log fixed: returned cleanly levels=3 679 B view raw
panic.txt panic-signature panic: double fault (stack guard hit) 455 B view raw
fix.diff suggested-fix depth-bound recursion (NBNS_MAXREDIRECTS) + init retarget sockaddr 1.9 KB view raw
env.txt environment uname / kern.version 209 B view raw
VERDICT.md verdict narrative, sibling-gate analysis, primitive proof, fix validation 5.4 KB ↓ raw
README.md readme build/run/expected 1.3 KB ↓ raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
README.md readme build/run/expected
↓ download raw

DF-0671 PoC β€” NetBIOS retarget unbounded recursion (smbfs)

Build

cd findings/poc/DF-0671
cc -O2 -o evil_nbserver evil_nbserver.c      # evil NB server
cp Makefile.recurse Makefile && make         # nb_recurse.ko recursion harness

Two proofs

A. Network path (evil server + mount_smbfs) β€” reaches the retarget gate

# as root:
./evil_nbserver 139 &
mount_smbfs -N -I 127.0.0.1 '//GUEST@127.0.0.1/SHARE' /mnt

Expected (this guest): evil server logs connection #1, req type=0x81, sends RTGRESP; mount_smbfs fails "Connection reset by peer". This proves the kernel parses the RTGRESP and attempts the retarget. (The recursion itself is masked by the uninitialized sin.sin_family sibling β€” see VERDICT.md.)

B. Recursion-primitive harness (decisive) β€” stack overflow + fix

# baseline (unbounded): expect panic
kldload ./nb_recurse.ko                       # hw.nb_oob.bound defaults to 1
# force baseline:
sysctl -w hw.nb_oob.bound=0   # (set via /boot/loader.conf tunable, then kldload)

Expected baseline (bound=0): panic: double fault after ~36 recursion levels (stack-guard hit). Expected fixed (bound=1): returned cleanly levels=3.

Fix

Apply fix.diff to /usr/src/sys/netproto/smb/smb_trantcp.c and rebuild the smbfs module (cd /usr/src/sys/vfs/smbfs && make).

VERDICT.md verdict narrative, sibling-gate analysis, primitive proof, fix validation
↓ download raw

DF-0671 β€” NetBIOS retarget unbounded recursion (smbfs/netsmb)

Verdict: REPRODUCED (recursion stack-overflow primitive proven; fix validated)

nbssn_rq_request() in sys/netproto/smb/smb_trantcp.c handles the NetBIOS session setup. On receiving NB_SSN_RTGRESP (0x84) it disconnects, reconnects to the retarget address, and recurses into itself with no depth counter:

/* smb_trantcp.c:261-265 */
nbp->nbp_state = NBST_RETARGET;
smb_nbst_disconnect(nbp->nbp_vc, td);
error = nb_connect_in(nbp, &sin, td);
if (!error)
    error = nbssn_rq_request(nbp, td);   /* <-- unbounded self-recursion */

NBNS_MAXREDIRECTS is #defined to 3 in netbios.h:110 but referenced nowhere in the kernel β€” the bound was intended but never enforced. A malicious SMB server that always answers session setup with a retarget drives the client into unbounded recursion; each level's frame (sockaddr_in sin + mbchain/mdchain + mbuf* + scalars + the nbssn_recv/socket_wait/nb_connect_in frames above it, ~272 bytes) eats the 16 KB lwkt stack β†’ overflow.

Primitive proof (decisive)

The harness nb_recurse.c replicates nbssn_rq_request's per-level frame and the unbounded self-call on a 16 KB lwkt stack. Loading it (bound=0, baseline):

DF0671: NB retarget recursion level 8  (sin @0xfffff80118616f68)
DF0671: NB retarget recursion level 16 (sin @0xfffff801186166e8)   (-0x880 / 8 levels)
DF0671: NB retarget recursion level 24 (sin @0xfffff80118615e68)
DF0671: NB retarget recursion level 32 (sin @0xfffff801186155e8)
panic: double fault
Stopped at      Debugger+0x7c:  movb    $0,0xbdaf09(%rip)

The stack-guard page is hit after ~36 levels β†’ double-fault panic. This is the cited line-265 pattern isolated from a sibling gate (below).

Reachability & a sibling gate (important nuance)

The realistic trigger is a malicious SMB server; the victim is any local process that connects through the netsmb transport (mount_smbfs, smbutil). nsmb_dev_open has no privilege check and the clone device is open to whoever devfs permits.

A network PoC (evil_nbserver.c + mount_smbfs) does reach the retarget path: the evil server receives a genuine NB_SSN_REQUEST (type 0x81) and the kernel parses the RTGRESP and attempts the retarget. However, on this guest the recursion did not execute via the live path because of a distinct sibling bug: the retarget sin (smb_trantcp.c:258-260) sets only sin_addr and sin_port, leaving sin_len and sin_family as uninitialized stack garbage. in_pcb.c:655 rejects sin_family != AF_INET with EAFNOSUPPORT, so nb_connect_in() fails before line 265. The harness above removes that gate (initializes sin) to prove the recursion primitive in isolation.

So: the unbounded recursion is a real, confirmed latent bug; its live trigger is masked on this kernel by the uninitialized-sockaddr sibling, but it fires deterministically the moment sin_family residue is AF_INET (or once that sibling is fixed). The fix addresses both.

Escalation ceiling

This is a stack overflow, not a heap write β€” there is no data-only primitive to groom. On a kernel without stack-cookies/stack-protector for the overflow direction, unbounded recursion yields a deterministic DoS (panic). Code-exec from a kernel stack overflow would require a controllable overwrite of a return address with stack residue shaping, which is not derivable from this primitive on its own; the realistic impact is local (or remote-via-evil-SMB-server) kernel panic / DoS, with RCE only via a separate return-address-control chain. Driven by an unprivileged user via smbutil/mount, this is a local DoS; the "unauthenticated remote" framing applies only when the link has no LCP auth.

PoC changes

  • evil_nbserver.c + run.sh: an evil NetBIOS server that always retargets to itself, driven by mount_smbfs. Proves the kernel reaches the retarget path (real NB_SSN_REQUEST observed, RTGRESP parsed).
  • nb_recurse.c + Makefile.recurse: kernel harness replicating nbssn_rq_request's frame + the unbounded self-call, with a bound tunable. bound=0 β†’ double-fault panic (the primitive); bound=1 β†’ clean return after 3 levels (the fix).

Fix (fix.diff)

  1. Add int depth to nbssn_rq_request(), enforced against NBNS_MAXREDIRECTS (if (depth >= NBNS_MAXREDIRECTS) return ECONNREFUSED;); recursive call passes depth + 1, the entry call in smb_nbst_connect passes 0.
  2. Initialize the retarget sockaddr (bzero(&sin,...); sin.sin_len=...; sin.sin_family=AF_INET;) before md_get_mem fills sin_addr β€” closing the sibling uninit that masked the recursion on this guest.

Validated: harness bound=0 panics (double fault) β†’ bound=1 returns cleanly at level 3; the real smbfs.ko module builds with the patch (build.log).

Kernel references (verified)

Fix verification

fixed

validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

REPRODUCED. smb_trantcp nbssn_rq_request unbounded recursion on NB_SSN_RTGRESP -> stack overflow -> double fault panic. Harness-confirmed. Gated by sibling uninit sin_family bug.