# DF-3211 — md_lookup_swap() decodes only the low 32 bits of the 64-bit NFSv3 file size into a signed int → negative / truncated swap size

File: `sys/vfs/nfs/nfs_mountrpc.c:286, 292-299`; consumer `sys/vfs/nfs/nfs_vfsops.c:666-701`, `sys/vm/vm_swap.c` (`swaponvp` takes `u_quad_t`).

## What
NFSv3 `fattr.size` is a 64-bit hyper (wire words [5]=hi, [6]=lo — `sys/vfs/nfs/nfsproto.h:325`
`nfsuint64 nfsv3fa_size` after type/mode/nlink/uid/gid). `md_lookup_swap` reads only:

```c
size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);   /* :286 — low word only, into int */
...
nfsv3_diskless.swap_nblks = size / 1024;           /* :296 — signed division */
```

* swap file with `size mod 2^32` in `[2^31, 2^32)` (e.g. a 2–4 GiB swap file) → `size` **negative** →
  `swap_nblks` negative.
* swap file ≥ 4 GiB → size silently wrong (mod 2^32): e.g. 8 GiB → 0 → swap silently disabled.
* NFSv2 path has the same signed-int landing (`:292`, v2 size is a u32 word [5]): ≥ 2 GiB v2 swap file →
  negative `swap_nblks`.

## Downstream (nfs_mountroot, nfs_vfsops.c:666-701)
`if (nd->swap_nblks)` — a negative value is truthy → `swap_nblks *= 2` (still negative) →
`VTONFS(vp)->n_size = nd->swap_nblks * DEV_BSIZE` — **negative file size on the swap vnode** →
`swaponvp(td, vp, nd->swap_nblks)` — the `int` sign-extends into `swaponvp`'s `u_quad_t nblks`
(sys/vm/vm_swap.c) → swap accounting believes ~2^64 blocks exist on an NFS file. Corrupt swap geometry /
bogus vm_swap_size at best; boot-time failure at worst.

## Threat
Trigger: a legitimate NFS server exporting a >2 GiB swap file (misconfig-sized or simply large), or — per
DF-3205 — any LAN forger answering the boot LOOKUP (xid is deterministic, source unfiltered). Impact ceiling:
boot-path DoS / swap-accounting corruption. Not runtime reachable post-boot.

## Fix
Decode the full hyper (`fxdr_hyper(&fattribs.v3[5])`, xdr_subs.h:83) and bound-check before storing into the
`int` field (see fix.diff).
