# DF-4598 — `vinum_scandisk()` `strncpy` into `partname[64]` without NUL termination (stack OOB read)

* File: `sys/dev/raid/vinum/vinumio.c:723`
* Severity: Info · Confidence: likely

## What

```c
char partname[DRIVENAMELEN];      /* DRIVENAMELEN = 64 (local #define, line 677) */
...
if (has_slice >= 0 && has_part)
    strncpy(partname, devicename[driveno], DRIVENAMELEN);
```

When the user-supplied device path is ≥ 64 characters and its basename
matches the `[a-z]+\d+s\d<c>` scan pattern, `strncpy` fills all 64 bytes and
leaves `partname` unterminated. `check_drive(partname)` →
`find_drive_by_dev()` → on create, `ksnprintf(drive->devicename, 64, "%s",
partname)` (vinumconfig.c:534-536) then reads past the 64-byte stack buffer
until it happens to find a NUL — a bounded-by-luck stack overread whose
content is copied into the created drive's `devicename` (visible to the same
root user via `vinum l`).

The sibling constructors (`ksnprintf(partname, DRIVENAMELEN, …)` at 725/728)
are safe; only the `strncpy` branch is affected. The device list comes from
the `read` ioctl tokens (root) or the `vinum.drives` loader tunable, so this
is a hardening/info finding, not an attack surface for unprivileged users.

## Fix

```diff
-	strncpy(partname, devicename[driveno], DRIVENAMELEN);
+	strncpy(partname, devicename[driveno], DRIVENAMELEN - 1);
+	partname[DRIVENAMELEN - 1] = '\0';
```

## Not run on the guest

Requires a ≥64-char matching device path from root; the overread's target
content is stack noise with no privilege consequence. Recorded as `untested`.
