# DF-5322 — `struct tlabel` leaked on every split-transaction timeout

**File:** `sys/bus/firewire/firewire.c:348` (`firewire_xfer_timeout()`)
**Severity:** Low · **Bucket:** kernleak · **Confidence:** certain
**Status: reproduced (5000 objects / 80000 bytes leaked over 5000
timeouts) on the QEMU guest via the production code path; fix validated
(delta 0).**

## Root cause

`firewire_xfer_timeout()` unlinks an expired tlabel with
`STAILQ_REMOVE_HEAD(&fc->tlabels[i], link)` (firewire.c:348) but never
frees it.  The **only** `kfree` of a `struct tlabel` in the file is in
`fw_tl_free()` (firewire.c:900), which frees an entry only when it still
finds it in the list.  After the timeout removed it:

* kernel-internal xfers: `fw_xfer_done() -> fw_asy_callback_free ->
  fw_xfer_free -> fw_xfer_unload -> fw_tl_free()` finds nothing;
* `/dev/fw` `FW_ASYREQ` xfers: the waiter's `fw_xfer_free_buf()` ->
  same `fw_tl_free()` — finds nothing.

So **every** split-transaction timeout leaks exactly one
`sizeof(struct tlabel)` (= 16 bytes on x86_64) allocation from `M_FW`.

## Trigger

Any local user permitted to use `/dev/fwN.M` can create these at will:
`FW_ASYREQ` a read to a node that never answers (or pull the cable) —
each transaction times out after 200 ms and leaks 16 bytes
(~1 MB/day at the natural retry rate; unbounded in aggregate with
kernel-internal fwmem traffic added on busy buses).

## What to run here (guest, root)

```
./build.sh      # df5322.ko: compiles the PRODUCTION firewire.c in
sh run.sh       # mode 0: 5000 timeouts through the production
                # firewire_xfer_timeout() + fw_xfer_free() paths
```

Baseline output (`run.log`):

```
DF5322: 5000 split-transaction timeouts
DF5322: M_FW inuse delta = 5000 objects, memuse delta = 80000 bytes
DF5322: LEAK REPRODUCED: ~1 tlabel leaked per timeout
```

Fixed (`fix.diff` applied to `/usr/src`, module rebuilt, `fix_run.log`):

```
DF5322: M_FW inuse delta = 0 objects, memuse delta = 0 bytes
```

`fix.diff` is shared with DF-5321 (the timeout now kfrees the tlabel it
unlinks, plus the tlabel-lock/CAS rework); see `../DF-5321/VERDICT.md`
for the full fix-validation narrative.
