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

DMSG wire msgid discloses the kernel heap address of every kernel-initiated transaction state to the cluster peer (msgid = (uint64_t)(uintptr_t)state)

Field Value
ID DF-2708
Status new
Severity Medium
CVSS 3.1 CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
CWE CWE-200 Exposure of Sensitive Information
File sys/kern/kern_dmsg.c
Lines 1804 (assignment), 1833 (transmission)
Area kern
Confidence certain
Discovered 2026-08-30
Pass 2 (GLM 5.3 second pass)
Bucket kernleak
Reported pending
Known CVE none
CVE match novel

Summary

kdmsg_msg_alloc() derives kernel-initiated msgids from the state object pointer and transmits them in every message header. The auto-initiated LNK_CONN of every cluster reconnect β€” plus each kernel-initiated LNK_SPAN and VOLCONF β€” hands the peer the kmalloc'd kdmsg_state_t address from the HAMMER2-msg zone. Verified: peer received msgid=0xfffff8011741eae0 on the wire; dmesg simultaneously printed "volconf update 0xfffff8011741eae0" for the same conn_state object.

Threat model & preconditions

Any cluster peer (or MITM, given no rx CRC/auth) learns live kernel heap addresses with no log access; defeats heap-layout randomization and primes pointer forgery for same-subsystem corruption (e.g. DF-2707's stale-rbnode writes). Different sink than DF-2614 (console msgbuf); not reachable by unprivileged local users.

Proof of concept

VERIFIED on the stock INVARIANTS guest (findings/poc/DF-2708/): mount hammer2 with cluster_fd = socketpair end, read the auto-LNK_CONN frame, print head.msgid; cross-check against the REMOTE_ADD-driven "volconf update %p" console line β€” identical values.

Allocate kernel-initiated msgids from a per-iocom 64-bit counter under msglk (plus a uint64_t msgid_seq in struct kdmsg_iocom): state->msgid = ++iocom->msgid_seq;

Timeline

  • 2026-08-30 Discovered during pass-2 audit of kern_dmsg.c (GLM 5.3); wire leak verified same run.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2708 Β· 5 files
FileTypeDescriptionSize
README.md β€” 2.6 KB ↓ raw
run.log β€” 151 B view raw
dmesg.txt β€” 7.8 KB view raw
manifest.json β€” 687 B view raw
verdict.json β€” 2.4 KB view raw

DF-2708 β€” DMSG wire msgid discloses the kernel heap address of every

kernel-initiated transaction state to the cluster peer

What was verified (stock INVARIANTS kernel #0, guest dfbsd)

kdmsg_msg_alloc() assigns each kernel-initiated transaction state state->msgid = (uint64_t)(uintptr_t)state (sys/kern/kern_dmsg.c:1804) and transmits it as msg->any.head.msgid (:1833) β€” so every kernel-initiated transaction hands the peer the kmalloc address of its kdmsg_state_t (allocated :1796 from the HAMMER2-msg zone, ~160-byte class). The kernel's auto-initiated LNK_CONN on every cluster reconnect (kdmsg_iocom_autoinitiate(), kern_dmsg.c:184-191) is the always-present instance; kernel-initiated LNK_SPANs (hammer2_update_spans) leak one pointer each.

PoC: df2707_trigger leak (source shared with the DF-2707 pack) mounts a hammer2 volume with cluster_fd = our socketpair end, reads the auto-LNK_CONN, and cross-checks against the console print volconf update %p of the very same object (hmp->iocom.conn_state, hammer2_iocom.c:376, populated via the REMOTE_ADD ioctl).

Result (exact values, one run):

trigger stdout: AUTO_CONN cmd=80001106 msgid=0xfffff8011741eae0
dmesg:          volconf update 0xfffff8011741eae0        <-- identical

Repeat runs (3 mounts across this session) always produced a fresh 0xfffff80xxxxxxxxx direct-map kernel heap pointer.

Impact

Any cluster peer β€” the userland hammer2 service daemon's remote connection, a malicious/compromised cluster node, or a network MITM (receive-side CRCs are not verified, LNK_AUTH unimplemented) β€” learns kernel heap addresses without any log access. Defeats heap-layout randomization and primes pointer forgery for exploitation of memory corruption in the same subsystem (e.g. DF-2707's stale-rbnode writes). Not directly reachable by an unprivileged local user (mount/REMOTE_ADD require root; the leak goes to the peer, not to dmesg).

Build & run

scp -F dfbsd-qemu/config findings/poc/DF-2707/df2707_trigger.c \
                      findings/poc/DF-2707/run_df2707.sh dfbsd:/root/poc/df2707/
dfbsd-qemu/vm.sh run_root 'sh /root/poc/df2707/run_df2707.sh leak'
# compare: AUTO_CONN msgid  ==  dmesg 'volconf update' value

Fix direction

Use an opaque per-iocom 64-bit counter (protected by msglk) for kernel-initiated msgids instead of the state pointer, matching the msg_seq allocator already present for salt (kern_dmsg.c:2002-2003). Peer-initiated states already use peer-chosen msgids, so no protocol change is needed. (msgid uniqueness within statewr_tree is all the protocol requires, kern_dmsg.c:1808-1809.)

Fix verification

not_testable
per-fix-DF-2708

Confirmed kernel references

Detail

Exploit chain

cluster peer reads head.msgid of the kernel's auto-LNK_CONN (one per reconnect) or any kernel-initiated LNK_SPAN -> direct kernel heap pointer -> heap-layout disclosure defeating KASLR-style randomization, priming pointer forgery for same-subsystem corruption bugs (e.g. DF-2707 stale-rbnode writes).

Evidence (decisive lines)

['run.log (trigger stdout: AUTO_CONN cmd=80001106 msgid=0xfffff8011741eae0)', 'dmesg.txt (volconf update 0xfffff8011741eae0 - identical value, same object)']

PoC changes

Used the DF-2614 cluster_fd mount harness in a leak mode that prints the wire msgid and cross-checks it against the console %p print of conn_state.

Verified recommended fix

Allocate kernel-initiated msgids from a per-iocom 64-bit counter under msglk instead of the state pointer (peer-initiated states already use peer-chosen msgids; uniqueness in statewr_tree is the only requirement).

Verdict

kdmsg_msg_alloc() sets state->msgid = (uint64_t)(uintptr_t)state (kern_dmsg.c:1804) and transmits it as head.msgid (:1833), disclosing the kmalloc'd kdmsg_state_t heap address of every kernel-initiated transaction to the cluster peer. Verified on the stock INVARIANTS guest: the auto-LNK_CONN observed on the peer socket carried msgid=0xfffff8011741eae0 and dmesg simultaneously printed 'volconf update 0xfffff8011741eae0' for the same object (hmp->iocom.conn_state via the REMOTE_ADD ioctl). Fresh 0xfffff80xxxxxxxxx pointers observed on every mount across 4+ runs.