# DF-5554 — cam_calc_geometry() 64→32-bit truncation (sys/bus/cam/cam.c)

## What

`cam_calc_geometry()` computes fake C/H/S geometry for a disk from
`ccg->volume_size` (u_int64_t, cam_ccb.h:779) but keeps every arithmetic
local in `uint32_t` (cam.c:378):

- `size_mb = ccg->volume_size / size_mb;` (cam.c:389) — u64/u32 quotient
  **truncated to u32**;
- `ccg->cylinders = ccg->volume_size / secs_per_cylinder;` (cam.c:398) —
  same truncation into the u32 result field.

`volume_size` is filled by the da periph straight from device-reported
READ CAPACITY data (`scsi_8btou64(rcaplong->addr)`, scsi_da.c:1851 →
`dasetgeom` scsi_da.c:2303), i.e. fully controlled by any SCSI target the
host negotiates with (malicious USB gadget, iSCSI/NBD export, virtio-scsi
backend). Every SIM in the tree funnels XPT_CALC_GEOMETRY into this one
function (ahci, sili, virtio_scsi, umass, mps/mpr, 20+ drivers).

## Reproduce (guest, root)

```
sh build.sh                    # KLD df5554.ko via kmod.mk (production symbol)
sh run.sh                      # kldload; dmesg | grep DF5554
```

## Expected

Baseline (stock kernel #0, Jul 2 2026) — `run.log`:
- sane 8TB (1.56e10 sectors): `ok (matches 64-bit math)` — harness fidelity;
- 2^43 sectors: `ker: H=64 S=32 C=0` vs `tru: H=255 S=63 C=547531467`
  — **both** truncations fire (extended-translation decision flips because
  size_mb wraps 2^32→0, and cylinders wraps 2^32→0);
- 2^32×16065 (+16064): `C=0` (exact cylinder wrap);
- max-u64: `C=1500097198` vs true 1148256711715502 (arbitrary modular value);
- block_size=0 / zero-volume guards behave.

Patched (kernel #1 with `fix.diff`) — `run.patched.log`:
- 2^43 sectors: `H=255 S=63 C=547531467` — **exact 64-bit truth**;
- unrepresentable quotients saturate at `C=4294967295` (UINT32_MAX clamp),
  never silently wrap to 0/arbitrary;
- guards unchanged.

## Impact ceiling

Wrong kernel-reported disk geometry (dmesg announce, `diskinfo`,
disk_info.d_ncylinders) for crafted-capacity devices. No memory-safety
impact; downstream consumers divide only by secpercyl (=16065/2048, never
0) and size from the 64-bit d_media_blocks. Severity Low (logic).

Guest is reset (`vm.sh reset with-src`) after each leg.
