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

daemon_save_config() 'break' aborts the whole drive loop on the first malformed drive β€” later drives' config replicas never updated

Summary

The malformed-drive branch frees the drive then 'break's out of the loop over ALL drives instead of continuing, so every drive allocated after it is skipped for that save - tail drives' replicas stay stale, defeating the dual-replica design and skewing the last_update-sorted rescans. break->continue fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

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

DF-4597 β€” daemon_save_config() breaks out of the whole drive loop on the first malformed drive

What

The loop "Write the configuration to all vinum slices" iterates driveno over every allocated drive. For the first drive whose devicename or label.name is empty it does:

if ((drive->devicename[0] == '\0')
|| (drive->label.name[0] == '\0')) {
    unlockdrive(drive);
    free_drive(drive);     /* get rid of it */
    break;                 /* <-- exits the for(driveno) loop entirely */
}

Every drive after the malformed one is silently skipped for this save: their on-disk config replicas (both copies per drive) are not updated, so replicas diverge. The next save (which re-enters the loop from drive 0; the malformed entry is now freed, so a different first-malformed drive can re-trigger it) may or may not reach the tail drives. With a malformed drive early in the table, later drives can stay stale indefinitely β€” the exact situation the dual-replica scheme exists to avoid. A continue (after free_drive) is what the surrounding code structure implies.

Trigger: a referenced-but-nameless drive entry (created by config lines referencing a drive name without a device, e.g. sd … drive ghost), then any configuration change. Root-configurable only β†’ Low.

Fix

    free_drive(drive);              /* get rid of it */
-   break;
+   continue;

Not run on the guest

Observable only as "drives after index i did not get the new config", which needs β‰₯2 real drives plus a malformed entry; the mechanism is a two-line code reading. Recorded as untested.

VERDICT.md
↓ download raw

DF-4597 β€” VERDICT

Status: untested (code-certain logic bug; multi-drive setup not built on the guest for it β€” the mechanism is a two-line reading of the loop).

Analysis

sys/dev/raid/vinum/vinumio.c:601-606: inside for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++), the malformed-drive branch executes free_drive(drive); break; β€” terminating the save pass for all remaining drives instead of continuing to the next entry (the sibling branches at 607-616 all use continue/close+fallthrough). Result: after any malformed (empty devicename/label) entry, later drives' config replicas are not written for that save; with a persistent malformed entry at a low index (referenced-only drives created by sd … drive <name> config lines), tail drives' replicas can stay stale across many saves, defeating the dual-replica design and confusing the "newest label wins" logic of the next vinum_scandisk/read (drivecmp sorts by label.last_update, vinumio.c:841-856). Low severity: root-configured state only, no memory-safety impact.

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

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md analysis with path:line citations

Verified recommended fix

Replace the break with continue after free_drive() in the malformed-drive branch.

Verdict

Code-certain logic bug: the malformed-drive branch of daemon_save_config() (vinumio.c:601-606) breaks out of the entire drive loop instead of continuing, so every drive allocated after the first malformed entry is skipped for that config save -- replicas diverge and the last_update-sorted rescan of vinum_scandisk can pick stale configs. Root-configured state only.