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

config_volume readpol case falls through into setupstate: VF_CONFIG_SETUPSTATE silently set for every volume configured with readpol

Summary

The inner readpol switch is not followed by break before 'case kw_setupstate', so any 'readpol' keyword sets the disk-restore-only flag VF_CONFIG_SETUPSTATE. give_plex_to_volume then skips invalidate_subdisks for plexes added to volumes that already have plexes, and the setupstate forceup-all path can resurrect stale/down plexes - mirror data-integrity break from a completely ordinary keyword. Add-break fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4135 Β· 3 files
FileTypeDescriptionSize
README.md file 2.7 KB ↓ raw
manifest.json file 407 B view raw
verdict.json file 1.2 KB view raw
README.md file
↓ download raw

DF-4135 β€” config_volume() readpol case falls through into

setupstate, silently setting VF_CONFIG_SETUPSTATE

Root cause

sys/dev/raid/vinum/vinumconfig.c:1527-1557 β€” the inner switch (get_keyword(...)) for kw_readpol is not followed by a break before case kw_setupstate::

    case kw_readpol:
        switch (get_keyword(token[++parameter], &keyword_set)) {
        case kw_round: ... break;
        case kw_prefer: { ... } break;
        default:
        throw_rude_remark(EINVAL, "Invalid read policy");
        }                                    /* <-- no break */
    case kw_setupstate:                      /* <-- fallthrough */
        vol->flags |= VF_CONFIG_SETUPSTATE;
        break;

Every volume configured with a readpol keyword (a normal, documented option) silently gains VF_CONFIG_SETUPSTATE β€” a flag that is meant to be set only while restoring a configuration from disk, when all plexes are known-empty.

Consequence

give_plex_to_volume() (vinumconfig.c:202-204) skips invalidate_subdisks() for any plex added to a volume that already has plexes:

    else if ((vol->plexes > 0)
    &&((vol->flags & VF_CONFIG_SETUPSTATE) == 0))   /* skipped! */
    invalidate_subdisks(&PLEX[plexno], sd_stale);

so the newly added mirror plex's subdisks keep the sd_empty state instead of being invalidated to sd_stale. Combined with the plex state machine (vinumstate.c:515-541, where an all-empty plex with VF_CONFIG_SETUPSTATE forceups every plex of the volume via forceup(), which blindly marks all subdisks sd_up), a down/stale plex holding outdated data can be resurrected as sd_up when a freshly added empty plex is processed first β€” the volume then serves reads from unrevived, stale data on a mirror whose admin expects resync semantics.

Threat

Silent data-integrity break (stale-data resurrection / skipped mirror invalidation) on any volume configured with readpol β€” a completely ordinary configuration keyword. Trigger is a plain config line: volume mv readpol round ....

Fix

--- a/sys/dev/raid/vinum/vinumconfig.c
+++ b/sys/dev/raid/vinum/vinumconfig.c
@@ -1551,6 +1551,7 @@ config_volume(int update)
        }
        break;

+       default:
        throw_rude_remark(EINVAL, "Invalid read policy");
        }
+       break;                  /* terminate readpol */

    case kw_setupstate:

(the missing break after the inner switch is the actual defect).

Verification

Analysis-only (skipped live): Low-severity logic defect; the control-flow fallthrough is certain from source (confidence certain), the data-integrity impact requires the plex processing order described above. Live data corruption testing on the guest would require a populated mirror and is out of proportion to the severity.

Fix verification

not_testable
per-fix-DF-4135

Confirmed kernel references

Detail

Evidence (decisive lines)

README.md analysis with code excerpts

PoC changes

n/a - analysis only

Verified recommended fix

Add break after the inner readpol switch.

Verdict

Missing break after the readpol inner switch (vinumconfig.c:1550-1556) is certain from source; any volume configured with readpol silently gains VF_CONFIG_SETUPSTATE, which skips invalidate_subdisks() in give_plex_to_volume (:202-204) and enables the setupstate forceup-all path (vinumstate.c:540). Data-integrity impact (mirror plex not invalidated; possible stale-data resurrection via forceup) requires specific plex processing orders. Live data-corruption test skipped as out of proportion to severity.