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

Before-buffer OOB read and conditional OOB write on CTRL(n) down-arrow at end of history

Summary

Pressing down-arrow when history cursor already at/past newest entry takes else branch clearing first byte of input buffer to NUL then falls through to hist_redraw. index() returns db_lbuf_start itself then db_le[-1] dereference reads one byte before buffer. If that byte happens to be \r or \n *--db_le=\0 writes NUL one byte before buffer 1-byte OOB write. CTRL(n) handler at :232 tests if(db_lhistcur<db_lhistidx-1) on first down-arrow always false takes else at :236-243 executes *db_lbuf_start=\0. No break falls through hist_redraw :245. index(:249) returns db_lbuf_start itself. :250 evaluates db_le[-1] which is db_lbuf_start[-1] OOB read before caller buffer. If byte==\r||\n :251 *--db_le=\0 stores NUL at db_lbuf_start[-1] 1-byte OOB write. Code lacks db_le>db_lbuf_start lower-bound check. Reachable with single keypress no history needed. DDB-only privileged context defense-in-depth. [VERIFIED pass2: value-attributed before-buffer read - pre-byte 0x0a ends 0x0d vs 0x58 unchanged tracking the OOB byte; lower-bound guard fix-validated]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2239 Β· 10 files
FileTypeDescriptionSize
run.log β€” 899 B view raw
run_stock_boot.log β€” 17.4 KB view raw
run_fixed_boot.log β€” 16.3 KB view raw
fix.diff β€” 390 B view raw
dfh.c β€” 24.3 KB view raw
dfarm.c β€” 2.4 KB view raw
harness.diff β€” 2.2 KB view raw
build.sh β€” 66 B view raw
run.sh β€” 168 B view raw
env.txt β€” 234 B view raw

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

Stock: pre-buffer byte mutated 0a->0d on the trigger, untouched for 0x58. Fixed: no pre-buffer access in either mode, control bytes identical.

run.log stock vs fixed DF2239 lines and region hex dumps.
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT #8 DFHARNESS x86_64 (stock-behavior kernels #4/#6, fixed #8; base 6.5-DEVELOPMENT 600519)

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log: DF2239 mode1 pre-set=0a pre-now=0d and mode0 pre-set=58 pre-now=58 on stock; both unchanged on fixed. Hex dumps of region[8..24] in the boot logs.

PoC changes

Built the kernel canary harness + console-input injection (harness.diff) feeding a real CTRL(n)+Enter keystroke stream to db_readline.

Verified recommended fix

Guard the trailing-newline strip with db_le > db_lbuf_start before reading db_le[-1].

Verdict

Proven by behavioral attribution: pressing CTRL(n) as the first key (empty history) makes hist_redraw compute db_le == db_lbuf_start and dereference db_le[-1]. With a pre-buffer 0x0a the NUL write fires and the byte ends as 0x0d (two OOB writes total incl. the later Enter store); with 0x58 no write occurs -- the branch outcome tracks the out-of-bounds byte value, proving the read. Fixed guard (db_le > db_lbuf_start) leaves both cases untouched. DDB console-holder only, value never displayed; Low/defense-in-depth confirmed.