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)
PoC verification
Evidence pack
findings/poc/DF-4135 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | file | 2.7 KB | β raw | |
| manifest.json | file | 407 B | view raw | |
| verdict.json | file | 1.2 KB | view 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_testableConfirmed 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.
No comments yet.