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

DDB 'watch addr[,size]' β€” the syntax documented in ddb(4) β€” silently drops the size argument and always watches 4 bytes

Summary

The standard-syntax size lands in the unused count parameter while the re-parse at EOL fails and size defaults to 4: 'watch ticks,8' arms a 4-byte watch with no diagnostic (only the undocumented space form honors size). A mis-sized tripwire compounding DF-5721's inert software watchpoints with a distinct argument-handling root cause - live on any future arch where the machinery works. Live-proven (comma form shows 4 on stock); honor-count fix validated.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5727 Β· 13 files
FileTypeDescriptionSize
README.md β€” 1.7 KB ↓ raw
VERDICT.md β€” 2.2 KB ↓ raw
serial_vm1.sh β€” 1.8 KB view raw
drive_ddb.py β€” 2.2 KB view raw
enter_ddb.sh β€” 867 B view raw
run.sh β€” 246 B view raw
session1-smp.serial.log β€” 14.5 KB view raw
baseline-up.serial.log β€” 36.0 KB view raw
env.txt β€” 350 B view raw
fix.diff β€” 572 B view raw
fix_build.log β€” 5.7 MB ↓ download
fix_run.log β€” 15.2 KB view raw
verdict.json β€” 2.6 KB view raw

DF-5727 β€” DDB watch addr,size (documented syntax) silently drops the size β€” always watches 4 bytes

Severity: Low (DDB console is root-gated; mis-sized tripwire, compounds the DF-5721 dead-instrument problem with a distinct argument-parsing root cause).

What breaks

ddb(4) documents watch addr[,size] ("The size argument defaults to 4"), but db_command() (db_command.c:386-396) parses ,size into the command's count parameter, and db_watchpoint_cmd() (db_watch.c:198-201) ignores count entirely and instead re-parses the token stream β€” which is already at end-of-line, so db_expression() returns FALSE and the size silently defaults to 4. (Only the undocumented space form watch addr size reaches the size.)

db_set_watchpoint() then arms loaddr..loaddr+4 instead of the requested region β€” an operator watching an 8-byte field with the documented syntax watches half of it, with no error.

Live proof (stock kernel)

baseline-up.serial.log / session1-smp.serial.log:

db> watch ticks,8
db> show watches
 Map        Address  Size
*ffffffff8159eea0  ffffffff810529c8  4      <-- requested 8, got 4
db> dwatch ticks
db> watch ticks 8
db> show watches
 Map        Address  Size
*ffffffff8159eea0  ffffffff810529c8  8      <-- undocumented syntax works

Fix

Honor the parser-provided count (db_watch.c), keep the legacy space form β€” see fix.diff. Validated on the patched kernel: watch ticks,8 now shows Size 8; watch ticks still defaults to 4.

Reproduce

./serial_vm1.sh up && ./enter_ddb.sh
DF5725_SOCK=/tmp/opencode/df-5725-ser-up.sock ./drive_ddb.py \
   "watch ticks,8" 2 "show watches" 3 "dwatch ticks" 2 \
   "watch ticks 8" 2 "show watches" 3 "dwatch ticks" 2 "c" 8
VERDICT.md
↓ download raw

DF-5727 β€” VERDICT

reproduced β€” impact: none (mis-sized tripwire correctness defect; no memory unsafety). The man-page-documented watch addr[,size] syntax silently drops the size and always watches 4 bytes.

Environment

Same rig as DF-5725 (stock X86_64_GENERIC, UP + SMP instances).

Observation (exact)

db> watch ticks,8
db> show watches
 Map        Address  Size
*ffffffff8159eea0  ffffffff810529c8  4      <- requested 8, got 4
db> dwatch ticks
db> watch ticks 8
db> show watches
 Map        Address  Size
*ffffffff8159eea0  ffffffff810529c8  8      <- undocumented space form works

Root cause (line-accurate)

share/man/man4/ddb.4 (~line 495) documents watch addr[,size] ("The size argument defaults to 4"). db_command() (sys/ddb/db_command.c:385-396) parses ,size into the command callback's count parameter; db_watchpoint_cmd() (sys/ddb/db_watch.c:192-205) ignores count and calls db_expression(&value) again β€” the token stream is at end-of-line, db_term() returns FALSE (sys/ddb/db_expr.c), so size = 4 unconditionally. Only the undocumented space-separated form reaches a size. db_set_watchpoint() (db_watch.c:101-138) then arms [addr, addr+4) instead of the requested region, with no error.

Given DF-5721 (software watchpoints are inert on x86_64), this compounds the dead-instrument problem with a distinct argument-handling root cause; it also applies to any future arch where software watchpoints work.

Fix validation

fix.diff (db_watch.c): honor the parser-provided count first, keep the legacy space form, keep the 4 default. On the combined-fix kernel (fix_run.log):

db> watch ticks,8
db> show watches
 ... 8          <- comma syntax now honored
db> dwatch ticks
db> watch ticks
 ... 4          <- default preserved

Baseline reproduced / patched behavior corrected β†’ fixed.

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

Stock kernel: comma size silently dropped (Size 4 for ',8'). Patched kernel: 'watch ticks,8' -> Size 8, 'watch ticks' -> Size 4. Documented syntax now honored.

findings/poc/DF-5727/fix.diff; fix_run.log (Size 8 for comma syntax on patched kernel); baseline-up.serial.log (Size 4 on stock)
↓ fix.diffDragonFly 6.5-DEVELOPMENT #1: Sat Oct 10 18:42:38 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC

Confirmed kernel references

Detail

Evidence (decisive lines)

baseline-up.serial.log / session1-smp.serial.log: 'watch ticks,8' -> show watches prints Size 4; 'watch ticks 8' -> Size 8. fix_run.log (patched): 'watch ticks,8' -> Size 8; 'watch ticks' -> Size 4 (default preserved).

PoC changes

No seed PoC; uses the DF-5725 pack's serial rig.

Verified recommended fix

Honor the parser-provided count in db_watchpoint_cmd() (comma syntax) while keeping the legacy space form and 4-byte default (fix.diff).

Verdict

watch addr[,size] - the syntax documented in ddb(4) - silently drops the size: db_command.c:386-396 parses ',size' into the count parameter, db_watch.c:198-201 ignores count and re-parses at end-of-line (FALSE) so size defaults to 4 unconditionally; live-proven 'watch ticks,8' shows Size 4 while the undocumented 'watch ticks 8' shows Size 8. Mis-sized tripwire on a root-gated console -> Low; compounds DF-5721's inert software watchpoints with a distinct argument-handling root cause; no memory unsafety.