DIOCGSLICEINFO leaks kernel pointers (KASLR bypass) via raw struct diskslices copyout
| Field | Value |
|---|---|
| ID | DF-0075 |
| Status | new |
| Severity | Medium |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| CWE | CWE-200 Exposure of Sensitive Information to an Unauthorized Actor |
| File | sys/kern/subr_diskslice.c |
| Lines | 556-559 |
| Area | kern (disk slice / disklabel parsing) |
| Confidence | likely |
| Discovered | 2026-06-30 |
| Reported | pending |
Summary
Independent of the heap overflow (DF-0074), the DIOCGSLICEINFO bcopy at
sys/kern/subr_diskslice.c:557 returns the raw in-kernel struct
diskslices (followed by every struct diskslice) to userspace via the
copyout in mapped_ioctl (sys_generic.c:729). That structure contains, and
exposes verbatim, multiple kernel virtual addresses:
dss_cdevsw(struct cdevsw *,diskslice.h:168)- per-slice
ds_dev(cdev_t = struct cdev *) ds_label.opaque(void *to a kmalloc'd label or NULL)ds_ops(static kernel-data pointer todisklabel32_ops/disklabel64_ops)ds_devs[MAXPARTITIONS]pointer array (diskslice.h:144-158)
A local user who can open a slice device can read kernel .text/.data and
kmalloc-heap pointers, defeating KASLR and easing exploitation of separate
memory-corruption bugs β including DF-0074 in the same ioctl. This happens on
every DIOCGSLICEINFO call, not only for GPT disks.
Recommended fix
Stop returning the raw kernel structure. Define a separate ioctl output
structure containing only public, non-pointer fields (offsets, sizes, types,
UUIDs, openmasks) and copy those field-by-field into a bzero'd output buffer.
At minimum, zero every pointer-valued field before the bcopy.
Timeline
- 2026-06-30 Discovered during automated file-by-file audit of
sys/kern/subr_diskslice.c. - pending Reported to DragonFlyBSD security contact.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0075 Β· 14 files| File | Type | Description | Size | |
|---|---|---|---|---|
| poc_df0075.c | trigger-source | DIOCGSLICEINFO leak PoC | 2.6 KB | view raw |
| dump2.c | trigger-source | raw hexdump helper | 1.3 KB | view raw |
| build.sh | build-script | cc -O -o poc_df0075 poc_df0075.c | 152 B | view raw |
| run.sh | run-script | ./poc_df0075 /dev/vbd0 | 211 B | view raw |
| run.log | run-log | baseline leak (3 ptrs incl disklabel64_ops) | 446 B | view raw |
| run.2.log | run-log | stress run 2 | 441 B | view raw |
| run.3.log | run-log | stress run 3 | 441 B | view raw |
| fix.diff | suggested-fix | sanitize kernel pointers in DIOCGSLICEINFO copyout | 1.1 KB | view raw |
| fix_build.log | build-log | single-fix kernel build (DF-0075+DF-0056), rc=0 | 5.6 MB | β download |
| fix_run.log | run-log | patched kernel: 0 pointers leaked | 220 B | view raw |
| env.txt | environment | uname, cc version | 232 B | view raw |
| VERDICT.md | verdict | full narrative | 2.4 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 |
DF-0075 β DIOCGSLICEINFO kernel pointer leak
Verdict: REPRODUCED (info leak of kernel KVA pointers)
subr_diskslice.c:556-559 services DIOCGSLICEINFO with a raw
bcopy(ssp, data, ...) of the in-kernel struct diskslices (header +
active struct diskslices). That struct embeds several kernel virtual
addresses that are copied out verbatim to userspace:
diskslices.dss_cdevswβstruct cdevsw *(declared but, in current master, never assigned, so observed NULL)diskslice.ds_devβcdev_t[diskslice.h:144]diskslice.ds_labelβdisklabel_t.opaque(kmalloc'd label) [diskslice.h:155]diskslice.ds_opsβstruct disklabel_ops *(static kernel .data) [diskslice.h:156]diskslice.ds_devs[]βvoid *[][diskslice.h:158]
Reproduction
On the audit guest (/dev/vbd0, the labeled root disk), three kernel
addresses are leaked deterministically (3/3 runs identical):
[+0x220] 0xfffff8008da2fc00 <- ds_dev (cdev_t, kernel heap) [+0x268] 0xfffff8008edb5080 <- ds_label.opaque (kmalloc'd disklabel) [+0x270] 0xffffffff810e0a40 <- ds_ops == disklabel64_ops (nm-verified)
0xffffffff810e0a40 matches disklabel64_ops from nm /boot/kernel/kernel
exactly, making the leak unambiguous: a static kernel .data symbol is
returned to userland on every DIOCGSLICEINFO call.
ssh dfbsd 'cd /home/maxx/poc/DF-0075 && ./poc_df0075'
Realistic reachability / impact ceiling
The raw disk nodes on this guest are root:operator crw-r-----; the
unprivileged maxx user (not in operator) cannot open them, so the
unprivileged reachability requires operator-group membership β a realistic
storage/backup-admin precondition but not the strict default. Demonstrated
as root. Impact is a KASLR-bypass / kernel-pointer info leak (not
privilege escalation): the leaked .data/heap addresses defeat KVA
randomization and would ease exploitation of a separate memory-corruption
bug (e.g. DF-0074, same ioctl). No memory-corruption primitive is
introduced by this bug itself.
Fix
fix.diff copies the struct out as before, then sanitizes every
kernel-pointer field in the destination buffer (dss_cdevsw, per-slice
ds_dev, ds_label.opaque, ds_ops, ds_devs[]) before return. Validated
on a built single-fix kernel: baseline leaks 3 pointers (incl.
disklabel64_ops); patched kernel leaks 0.
Fix verification
fixedvalidated
see evidence pack
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
REPRODUCED. DIOCGSLICEINFO bcopy leaks 3 KVA ptrs incl disklabel64_ops. Fix: sanitize ptr fields.
No comments yet.