β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4598

vinum_scandisk() strncpy leaves partname[64] unterminated β†’ stack OOB read in find_drive_by_dev()'s %s copy

Summary

For a >=64-char device path matching the scan shape, strncpy fills all 64 bytes without a NUL; the ksnprintf %s in find_drive_by_dev then reads past the stack buffer until an accidental NUL, copying stack bytes into the drive's devicename. Root/loader-env input; hardening. Copy-63-and-terminate fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4598 Β· 2 files
FileTypeDescriptionSize
README.md β€” 1.5 KB ↓ raw
VERDICT.md β€” 1.4 KB ↓ raw

DF-4598 β€” vinum_scandisk() strncpy into partname[64] without NUL termination (stack OOB read)

What

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

-   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.

VERDICT.md
↓ download raw

DF-4598 β€” VERDICT

Status: untested (Info-severity hardening finding; root/loader-input only, no guest run).

Analysis

sys/dev/raid/vinum/vinumio.c:723 β€” the has_slice >= 0 && has_part branch of vinum_scandisk() uses strncpy(partname, devicename[driveno], DRIVENAMELEN) with partname[64]. A device path of β‰₯ 64 characters whose basename matches the %*[a-z]%*d%*[s]%d%c scan shape (ksscanf, line 711) yields an unterminated partname. The first consumer that treats it as a C string is find_drive_by_dev()'s create path (ksnprintf(drive->devicename, sizeof(...), "%s", devname), vinumconfig.c:534-536) β€” a stack overread whose length is bounded only by the first accidental NUL. The copied bytes land in the new drive's devicename, inspectable by the same root user. The strcmp in the search loop terminates safely because the comparison operand is a NUL-terminated ≀63-byte devicename. No unprivileged path; recorded as Info.

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

(No fix.diff for this item: documented recommendation only - see Fix above.)

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean
per-fix-DF-4598

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md analysis (in README.md) with path:line citations

Verified recommended fix

strncpy at most DRIVENAMELEN-1 bytes and NUL-terminate partname.

Verdict

strncpy of a >=64-char device path into partname[64] (vinumio.c:723) leaves the stack buffer unterminated when the basename matches the slice/partition scan pattern; find_drive_by_dev()'s ksnprintf("%s", partname) then reads past the buffer until a NUL, copying stack bytes into the new drive's devicename. Root/loader-env input only; hardening finding.