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

Unthrottled kprintf log-flood DoS via umtx_sleep/wakeup on unmapped address

Summary

umtx_sleep(:150-156)/wakeup(:289-295) kprintf(WARNING cant translate) on unmapped in-range address with NO rate limit. Any unpriv user loops syscall(469,0x1000,...) -> one kernel msg per call. Floods msgbuf/dmesg/syslog. Serial console: synchronous blocking -> system-wide slowdown.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0202 Β· 10 files
FileTypeDescriptionSize
umtx_flood.c trigger-source MAP_FIXED 2-page region, touch page 0, munmap page 1, hammer umtx_sleep on the hole 3.0 KB view raw
build.sh build-script cc -O2 -Wall 189 B view raw
run.sh run-script msgbuf before/after delta with WARNING flood proof 634 B view raw
VERDICT.md verdict full narrative 2.6 KB ↓ raw
serial_flood_proof.txt panic-signature serial console backlog from a 2000-call flood that wedged the guest 158.2 KB view raw
fix.diff suggested-fix ratecheck() throttle on the umtx_sleep/umtx_wakeup WARNING kprintf 1.8 KB view raw
README.md readme human-facing summary 1003 B ↓ raw
env.txt environment guest uname, modules, HW-gate note 190 B view 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 human-facing summary
↓ download raw

DF-0202 β€” umtx kprintf log-flood DoS

Summary

sys_umtx_sleep / sys_umtx_wakeup emit a kernel kprintf("WARNING can't translate ...") on every call made on a leaf-PTE-invalid but page-table-walk-resolvable user address, with no rate limit. Any unprivileged user can flood the kernel msgbuf / dmesg / serial console.

Build / Run

./build.sh         # cc -O2 -Wall -o umtx_flood umtx_flood.c
./run.sh 2000      # 2000 umtx_sleep calls; observe msgbuf delta

Expected (bug present)

  • 2000 calls -> 2000 umtx_sleep() (A): WARNING can't translate ... lines added to kern.msgbuf.
  • Larger floods block the serial console (synchronous kprintf) and wedge the guest.

Expected (fixed kernel)

  • 2000 calls -> exactly 1 msgbuf line (ratecheck() 1/s throttle).

Files

  • umtx_flood.c β€” trigger PoC.
  • fix.diff β€” rate-limit via ratecheck().
  • VERDICT.md β€” full narrative + reproduction transcript.
  • serial_flood_proof.txt β€” guest-wedging serial backlog.
VERDICT.md verdict full narrative
↓ download raw

DF-0202 β€” Unthrottled kprintf log-flood DoS via umtx

Verdict: REPRODUCED (DoS). Fix VALIDATED.

Mechanism

sys_umtx_sleep (sys/kern/kern_umtx.c:150-156) and sys_umtx_wakeup (:289-295) emit one kprintf("... WARNING can't translate ...") for every call made on a user address whose leaf PTE is invalid but whose page-table-walk is otherwise resolvable (e.g. an address inside a hole punched out of a populated mmap region). There is NO rate limit.

Any unprivileged user can loop syscall(SYS_umtx_sleep, target, ...) and emit one kernel message per call. At ~300 calls/second the kernel msgbuf fills with attacker-controlled lines, dmesg becomes useless, and on a system with the serial console active (the audit guest) the synchronous blocking writes wedge the entire machine β€” observed directly during verification (the guest stopped answering ssh after a 2000-call burst; boot.log shows the serial backlog).

Trigger

The hole-punched-mmap approach is needed because for a totally unmapped address (e.g. 0x1000), kreadmem64(PTmap+...) itself faults reading the (absent) page-table page, returns -1, and -1 happens to have the PG_V bit set β€” so uservtophys() returns a garbage "valid" physical address and the WARNING guard waddr == -1 is never taken (the call instead returns EBUSY via the value-mismatch path). When the target VA shares a populated 2 MiB page-table page with an adjacent mapped page (so the PTmap walk succeeds but the leaf PTE is invalid), uservtophys() returns -1 correctly and the WARNING path fires.

umtx_flood.c therefore does MAP_FIXED at an isolated region (0x50000000), touches page 0 (populates the PDE), munmaps page 1 (leaves its PTE invalid while the PDE remains present), then hammers umtx_sleep(page_1, 0xffffffff, 1). Each call emits one WARNING.

Reproduction

$ ./build.sh && ./run.sh 2000
before_umtx_lines=0
DF-0202: 2000 umtx_sleep calls in 7.002s (286 calls/s)
DF-0202: returns: EINVAL=2000 other=0
after_umtx_lines=2000
delta=2000
umtx_sleep() (A): WARNING can't translate 0x50001000 (umtx_flood 1369/1)

Each call = one msgbuf line. 2000 calls produce 2000 lines. During verification a larger flood blocked the serial console and the guest became unresponsive β€” see serial_flood_proof.txt.

Fix (validated)

fix.diff wraps both kprintf sites with ratecheck() limited to 1 message/second. On the patched kernel (#1, sha256 a4b8ef09f60586a8e1615aad22242264ada3c78bb2c6ea8edf7caec8798d96c7) the same 2000-call PoC emits exactly 1 msgbuf line:

DF-0202: 2000 umtx_sleep calls in 0.008s (256238 calls/s)
DF-0202: returns: EINVAL=2000 other=0
after_umtx_lines=1
delta=1

Fix verification

fixed

validated

see evidence pack
↓ fix.diffDragonFly 6.5-DEVELOPMENT #1: Fri Jul 17 21:29:31 UTC 2026

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

REPRODUCED (live). umtx_sleep/wakeup unthrottled kprintf -> 2000 msgbuf lines + serial console wedge. Unprivileged.