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

-n ':' / -n '' : strtok() NULL fed to strtol() crashes the vkernel during option parsing

Summary

A -n argument of only delimiters (or empty) makes strtok return NULL, passed unguarded to strtol - the child segfaults during getopt, before any boot output; the monitor masks it (WEXITSTATUS of a signaled child is 0) so the whole vkernel exits 0 silently. ktrace-proven (PSIG SIGSEGV, empty boot log); control boots. NULL-check+usage_err fix validated.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5774 Β· 10 files
FileTypeDescriptionSize
README.md β€” 1.4 KB ↓ raw
VERDICT.md β€” 1.6 KB ↓ raw
run5774.sh β€” 1.0 KB view raw
baseline_run.log β€” 214 B view raw
baseline.kdump.txt β€” 84 B view raw
fixed_run.log β€” 223 B view raw
fix.diff β€” 1.5 KB view raw
env.txt β€” 293 B view raw
verdict.json β€” 2.1 KB view raw
manifest.json β€” 650 B view raw

DF-5774 β€” -n : / -n '' makes strtok() return NULL and strtol(NULL) kills the vkernel before boot

File: sys/platform/vkernel64/platform/init.c Lines: 394-395 Severity: Low (operator-input NULL-deref DoS of the vkernel process at option parsing) Status: reproduced (stock) / fix validated.

Reproduce (guest, root, VKERNEL64 built)

cd /usr/obj/usr/src/sys/VKERNEL64
ktrace -i -f /tmp/vk5774.ktrace ./kernel.debug -m 512m -n : ; echo monitor rc=$?
kdump -f /tmp/vk5774.ktrace | grep PSIG

Expected output

Vulnerable (baseline_run.log / baseline.kdump.txt):

monitor rc=0
kernel.debug PSIG  SIGSEGV SIG_DFL      <- vkernel child dies in strtol(NULL)
(no boot output at all)

Control -n 2 parses fine and the boot proceeds (Using anonymous memory (512 MB)).

Fixed (fixed_run.log, rebuilt kernel with fix.diff hunk 2):

-- kdump signals:
kernel.debug CALL  exit(0x40)           <- EX_USAGE, no signal
-- output was:
Bad -n option

Root cause

init.c:394 tok = strtok(optarg, ":"); returns NULL when the whole -n argument is delimiters or empty (-n :, -n '', -n ::), and init.c:395 passes it straight to strtol(tok, NULL, 0) β€” a NULL nptr dereference in libc. The child segfaults during getopt, the monitor sees a signaled child (WEXITSTATUS of the wait status is 0) and exits 0 with zero diagnostics.

Fix

fix.diff hunk 2: NULL-check tok and usage_err("Bad -n option").

VERDICT.md
↓ download raw

DF-5774 β€” VERDICT

Status: reproduced (stock kernel, deterministic). Fix validated on a rebuilt kernel. Impact: none beyond process death (DoS of the vkernel at startup); classified Low. Confidence: certain.

-n : (or an empty -n argument): strtok(optarg, ":") at init.c:394 consumes the whole delimiter string and returns NULL; init.c:395 optcpus = strtol(tok, NULL, 0) dereferences NULL inside libc β†’ SIGSEGV of the vkernel child during option parsing, before writepid()/boot output. The monitor's WEXITSTATUS(status) (init.c:228) on a signaled child yields 0, so the whole vkernel exits 0 silently β€” no diagnostic, no core by default.

Live: ktrace/kdump on the guest shows kernel.debug PSIG SIGSEGV SIG_DFL (baseline.kdump.txt) with an empty boot log; control -n 2 boots (Using anonymous memory (512 MB)). This is the same operator-input crash class as the known DF-1031 (init_disk NULL deref on -c) but a distinct defect at a different site (option parsing, not device setup).

Fix (fix.diff hunk 2: if (tok == NULL) usage_err("Bad -n option");) validated on the rebuilt kernel: kdump now shows CALL exit(0x40) (EX_USAGE) and the message Bad -n option β€” no signal, no crash (fixed_run.log).

Not uid0-relevant: no memory-corruption primitive (NULL read).

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.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

Baseline: PSIG SIGSEGV, no output. Patched kernel: exit(0x40) with 'Bad -n option', no signal, control -n 2 unchanged.

baseline.kdump.txt vs fixed_run.log
↓ fix.diffper-fix-DF-5774

Confirmed kernel references

Detail

Evidence (decisive lines)

baseline_run.log + baseline.kdump.txt (PSIG SIGSEGV SIG_DFL; control -n 2 boots); fixed_run.log (exit 0x40, 'Bad -n option', no signal)

PoC changes

authored fresh (no seed); run5774.sh wraps the ktrace/kdump evidence and a -n 2 control boot

Verified recommended fix

if (tok == NULL) usage_err("Bad -n option"); after the strtok at init.c:394

Verdict

strtok(optarg, ":") at init.c:394 returns NULL for a -n argument made entirely of delimiters or empty ('-n :', "-n ''"), and init.c:395 feeds it to strtol() unguarded: the vkernel child segfaults during option parsing (ktrace: PSIG SIGSEGV SIG_DFL, zero boot output, monitor exits 0 silently). Same operator-input crash class as DF-1031, distinct site/defect. One-line NULL check fixes it; validated on the rebuilt kernel (clean EX_USAGE exit 0x40, 'Bad -n option').