# DF-4596 — `set_drive_parms()` overwrites `drive->freelist` without freeing the previous allocation (re-init leak)

* File: `sys/dev/raid/vinum/vinumio.c:143-148`
* Severity: Low · Confidence: certain (code) / impact small (256 B per cycle)

## What

```c
drive->freelist_size = INITIAL_DRIVE_FREELIST;
drive->freelist = (struct drive_freelist *)
    Malloc(INITIAL_DRIVE_FREELIST * sizeof(struct drive_freelist));  /* old pointer clobbered */
```

`set_drive_parms()` is reached from `init_drive()` ← `read_drive_label()` ←
`check_drive()`/`config_drive()`. Nothing here checks whether
`drive->freelist` is already allocated. A drive that was previously
initialized and later closed **keeps its freelist**: `close_drive()` /
`close_locked_drive()` (vinumio.c:202-230) only drop the vnode; only
`free_drive()` (vinumconfig.c:572-588) frees the freelist, and it is not
called on the state transitions `drive_up → drive_down` (e.g.
`vinum setstate d1 down`, I/O failure, `daemon_save_config` downing a drive).

Re-initializing such a drive — `vinum read /dev/…` on the same device, or the
boot scan — runs `set_drive_parms()` again, and the old
`INITIAL_DRIVE_FREELIST(16) * sizeof(struct drive_freelist)` allocation
leaks. Loopable by an administrator (or the boot scan against flapping
drives); 256 bytes per cycle. Kernel memory exhaustion over time; no
use-after-free (the old block is simply orphaned).

## Fix

```diff
     drive->freelist_size = INITIAL_DRIVE_FREELIST;
+    if (drive->freelist)
+	Free(drive->freelist);
     drive->freelist = (struct drive_freelist *)
 	Malloc(INITIAL_DRIVE_FREELIST * sizeof(struct drive_freelist));
```

## Not run on the guest

The leak is 256 B/cycle into `M_DEVBUF`; the guest has no per-allocation-site
accounting to observe it cheaply, and the code path (down → re-read) is plain
from source. Recorded as `untested`.
