# DF-2714 — sendfile(2) hdtr headers: unbounded kernel mbuf allocation

## What
`sys_sendfile()` (sys/kern/uipc_syscalls.c:1617-1642) marshals the
`sf_hdtr` header iovec into an mbuf chain with `m_uiomove()` **before**
`kern_sendfile()` performs any validation or socket-buffer accounting.
`iovec_copyin()` only rejects overflow, so the header total may be up to
`SSIZE_MAX-1` bytes.  Every iteration of `m_uiomove()` allocates mbuf
clusters with `M_WAITOK` (sys/kern/uipc_mbuf.c:2664), bounded only by the
global mbuf cluster pool / system memory.

Unlike `sendmsg()` (whose `sosend()` self-throttles on `ssb_space()`),
the sendfile header path has no bound at all.

## Threat
Any unprivileged local user: `fd` = any readable file (`/etc/passwd`),
`s` = any socket (it need not even be valid for sendfile — validation
happens after marshalling).  Two consequences, both reproduced:

1. **Transient**: an attacker-chosen volume of kernel mbuf memory
   (e.g. 56 MB = 80% of the guest's 33,296-cluster pool) is allocated
   and held for the duration of the copy.
2. **Persistent wedge**: a request larger than the pool leaves the
   syscall sleeping uninterruptibly in the objcache allocator
   (state `D3`, `WCHAN=objcache`) while holding every mbuf cluster in
   the system.  `kill -9` does not work.  Network RX/TX starves
   system-wide; reboot required.

## Reproduce
```
cc -O2 -o sendfile_hdtr_dos sendfile_hdtr_dos.c
# bounded (watch netstat -m "mbuf clusters in use" during the call):
./sendfile_hdtr_dos 56
# wedge (request > pool; run under a shell you can afford to lose):
./sendfile_hdtr_dos 256
```
Baseline observations (kernel #0, unpatched):
- run.log: peak `26684/33296 mbuf clusters in use` during a 56 MB
  header sendfile that then returns EINVAL.
- run.2.log: 256 MB request -> `33494/33296 mbuf clusters in use`,
  process `D3 objcache`, survives `kill -9`, syscall never returns.

Patched (fix.diff, kernel #2): both runs return EINVAL immediately;
peak cluster sample `256/33296` (idle baseline).  fix_run.log.

## Fix
Cap header/trailer totals at 1 MB (`SF_HDTR_MAXBYTES`) before
marshalling — see fix.diff (validated).
