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

tcp_pcblist sysctl raw-copies entire inpcb and tcpcb with kernel pointers to unprivileged users

Summary

tcp_pcblist(:1285,1288) bcopy entire struct inpcb + tcpcb into xtcpcb exported CTLFLAG_RD. ~20+ kernel pointers: inp_socket, inp_ppcb, inp_cred, hash/list links, inp_route.ro_rt, t_inpcb, callouts. Only xt_socket sanitized via sotoxsocket. Any unpriv: sysctl net.inet.tcp.pcblist -> KASLR bypass + heap layout. Same anti-pattern FreeBSD removed.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0337 Β· 18 files
FileTypeDescriptionSize
leak_pcblist.c trigger-source sysctl net.inet.tcp.pcblist info-leak PoC 4.3 KB view raw
offsets.c analysis-helper struct field offset printer 1.9 KB view raw
build.sh build-script exact cc build command 167 B view raw
run.sh run-script exact run invocation 129 B view raw
run.log run-log baseline (#0) decisive run, 113 ptrs leaked 1.2 KB view raw
run.1.log run-log stress run 1 161 B view raw
run.2.log run-log stress run 2 161 B view raw
run.3.log run-log stress run 3 161 B view raw
fix_run.log run-log patched (#1) decisive run, 0 ptrs leaked 152 B view raw
fix_build.log build-log single-fix kernel build output 5.6 MB ↓ download
fix.diff suggested-fix pointer sanitization in tcp_pcblist 2.6 KB view raw
pcblist.dump leak-sample raw pcblist binary dump 6.4 KB ↓ download
env.txt environment uname, cc version 238 B view raw
patched_env.txt environment patched kernel kern.version + sha256 155 B view raw
VERDICT.md verdict full analysis narrative 2.8 KB ↓ raw
README.md readme build/run/expected instructions 1.2 KB ↓ 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 build/run/expected instructions
↓ download raw

DF-0337 PoC β€” tcp_pcblist info leak

Build

cc -o leak_pcblist leak_pcblist.c

Run (as unprivileged user)

./leak_pcblist

Expected output (bug present)

pcblist total bytes: 5480
records: 5
LEAK: 113 kernel-pointer-sized words in pcblist output
VERDICT: LEAK CONFIRMED (113 kernel pointers exposed to unpriv user)

Expected output (after fix)

pcblist total bytes: 5480
records: 5
LEAK: 0 kernel-pointer-sized words in pcblist output
VERDICT: no kernel pointers found

How it works

The PoC opens a TCP socket (to ensure at least one inpcb is live), calls sysctlbyname("net.inet.tcp.pcblist", ...) to fetch the raw struct xtcpcb array, then scans every 8-byte word for values that fall in the DragonFly kernel pointer range (0xffffffff80000000+ text/data, 0xfffff80000000000+ heap).

The struct xtcpcb contains struct inpcb + struct tcpcb + struct xsocket which together hold ~30 kernel pointer fields. tcp_pcblist() bcopy()s the raw structs without sanitization, leaking all of them to any user.

Files

  • leak_pcblist.c β€” the PoC source
  • offsets.c β€” struct field offset helper (used during analysis)
  • fix.diff β€” the verified fix (pointer sanitization)
VERDICT.md verdict full analysis narrative
↓ download raw

DF-0337 β€” tcp_pcblist sysctl raw-copies entire inpcb + tcpcb (info leak)

Verdict: REPRODUCED β€” info leak of 113 kernel pointers to unprivileged user

Mechanism

tcp_pcblist() in sys/netinet/tcp_subr.c:1284-1293 builds the net.inet.tcp.pcblist sysctl response by bcopy()ing the entire struct inpcb and struct tcpcb into the exported struct xtcpcb:

bcopy(inp, &xt.xt_inp, sizeof *inp);          // line 1285
bcopy(inp_ppcb, &xt.xt_tp, sizeof xt.xt_tp);  // line 1288
sotoxsocket(inp->inp_socket, &xt.xt_socket);   // line 1292

Only xt_socket is sanitized (via sotoxsocket()). Every other pointer field in both structs is leaked raw:

  • inpcb (~15 pointers): inp_hash/inp_list/inp_portlist LIST_ENTRY links, inp_ppcb, inp_pcbinfo, inp_socket, inp_route.ro_rt, inp_depend4.inp4_options/moptions, inp_depend6.inp6_options/outputopts/moptions/icmp6filt, inp_porthash, inp_phd, inp_pf_sk
  • tcpcb (~12 pointers): t_segq (TAILQ_HEAD), t_pcbport, tt_rexmt/tt_persist/tt_keep/tt_2msl/tt_delack callouts, tt_msg, tt_sndmore, t_inpcb, scb.sackblocks (TAILQ_HEAD), scb.lastfound, scb.freecache, t_outputq (TAILQ_ENTRY)
  • xsocket (2 pointers): xso_so and so_pcb β€” sotoxsocket() deliberately copies these as "convenience handles"

The sysctl is CTLFLAG_RD (readable by any unprivileged user).

Proof

pcblist total bytes: 5480
sizeof(struct xtcpcb): 1096
records: 5
LEAK: 113 kernel-pointer-sized words in pcblist output
VERDICT: LEAK CONFIRMED (113 kernel pointers exposed to unpriv user)

Sample leaked pointers (3 runs, stable within a boot):

  rec 1 off  24: fffff80117bb8600   (inp_hash.le_next β€” heap)
  rec 1 off  32: ffffffff81563f90   (inp_hash.le_prev β€” text)
  rec 1 off 128: fffff80116d773a0   (inp_socket β€” heap)
  rec 1 off 256: fffff8004f102590   (inp_ppcb = tcpcb β€” heap)
  rec 1 off 336: fffff80116d77610   (tt_rexmt callout β€” heap)
  rec 1 off 928: fffff80117b3df40   (xt_socket.xso_so β€” heap)
  rec 1 off 1088: ffffffff811013d0  (stack residue β€” text addr)

3 stress runs: 113, 113, 113 β€” deterministic within a boot.

Impact

KASLR defeat + heap-layout disclosure. On a default DragonFly kernel (KASLR currently OFF), this directly leaks commit_creds, prepare_kernel_cred, slab object addresses, and the layout of adjacent heap objects β€” fueling further exploitation of any memory-corruption primitive. FreeBSD removed this anti-pattern years ago; DragonFly still ships it.

Fix

fix.diff β€” after the bcopy calls, explicitly NULL every pointer field in xt_inp, xt_tp, and xt_socket (including xso_so and so_pcb which sotoxsocket deliberately copies). Also bzero(&xt) first to kill stack residue in xt_alignment_hack. Validated: baseline 113 pointers β†’ patched 0 pointers (3Γ— each).

Fix verification

fixed

validated

see evidence pack
↓ fix.diffDragonFly 6.5-DEVELOPMENT #1: Sat Jul 18 01:50:35 UTC 2026

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

REPRODUCED (live). tcp_pcblist bcopy entire inpcb+tcpcb -> 113 KVA ptrs leaked to unprivileged user. KASLR defeat.