DF-5062 / fix.diff
diff -ruN a/sys/dev/raid/vinum/vinumconfig.c b/sys/dev/raid/vinum/vinumconfig.c --- a/sys/dev/raid/vinum/vinumconfig.c 2026-09-26 18:53:20.555916356 +0000 +++ b/sys/dev/raid/vinum/vinumconfig.c 2026-09-26 18:53:29.411801861 +0000 @@ -760,6 +760,19 @@ made_vol(struct volume *vol) { if (vol->vol_dev == NULL && vol->state != volume_unallocated) { + /* + * DF-5062: the volume number is encoded in the low VINUM_VOL_WIDTH + * bits of the device minor. Never create a node for a volume number + * that does not decode back to itself: volume #256 would get minor + * 0x100, which Volno() decodes as volno 0, silently aliasing every + * access onto VOL[0] (cross-volume data corruption). + */ + if (vol->volno >= (1 << VINUM_VOL_WIDTH)) { + log(LOG_ERR, "vinum: volume %s: volume number %d does not fit in " + "the %d-bit device minor; no device node created\n", + vol->name, vol->volno, VINUM_VOL_WIDTH); + return; + } vol->vol_dev = make_dev(&vinum_ops, VINUMDEV(vol->volno, 0, 0, VINUM_VOLUME_TYPE), UID_ROOT, GID_OPERATOR, 0640, diff -ruN a/sys/dev/raid/vinum/vinumutil.c b/sys/dev/raid/vinum/vinumutil.c --- a/sys/dev/raid/vinum/vinumutil.c 2026-09-26 18:53:20.559916305 +0000 +++ b/sys/dev/raid/vinum/vinumutil.c 2026-09-26 18:53:29.431801603 +0000 @@ -258,7 +258,14 @@ case VINUM_PLEX_TYPE: case VINUM_SD_TYPE: - return VOL[Volno(dev)].plex[(minor(dev) >> VINUM_PLEX_SHIFT) & (MASK(VINUM_PLEX_WIDTH))]; + { + int volno = Volno(dev); /* DF-5063: validate */ + int plexord = (minor(dev) >> VINUM_PLEX_SHIFT) & (MASK(VINUM_PLEX_WIDTH)); + + if (volno >= vinum_conf.volumes_allocated) /* no such volume */ + return -1; /* never touch VOL[] */ + return VOL[volno].plex[plexord]; /* may be -1: empty slot */ + } case VINUM_RAWPLEX_TYPE: return ((minor(dev) & MASK(VINUM_VOL_WIDTH)) >> VINUM_VOL_SHIFT) /* low order 8 bits */ @@ -286,7 +293,14 @@ return -1; case VINUM_SD_TYPE: - return PLEX[Plexno(dev)].sdnos[(minor(dev) >> VINUM_SD_SHIFT) & (MASK(VINUM_SD_WIDTH))]; + { + int plexno = Plexno(dev); /* DF-5063: validate */ + int sdord = (minor(dev) >> VINUM_SD_SHIFT) & (MASK(VINUM_SD_WIDTH)); + + if ((plexno < 0) || (plexno >= vinum_conf.plexes_allocated)) + return -1; /* never index PLEX[-1] */ + return PLEX[plexno].sdnos[sdord]; + } case VINUM_RAWSD_TYPE: return ((minor(dev) & MASK(VINUM_VOL_WIDTH)) >> VINUM_VOL_SHIFT) /* low order 8 bits */ |