⬢ DragonFlyBSD Kernel Audit
DF-4758 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/vinum/vinum.c
+++ b/sys/dev/raid/vinum/vinum.c
@@ -201,6 +201,7 @@
     union daemoninfo di = { .nothing = 0 };
     int i;
     int drives_allocated = vinum_conf.drives_allocated;
+    int daemon_wait = 5 * hz;			    /* DF-4760: bound the daemon wait */
 
     if (DRIVE != NULL) {
 	if (cleardrive) {				    /* remove the vinum config */
@@ -212,10 +213,12 @@
 	}
 	Free(DRIVE);
     }
-    while ((vinum_conf.flags & (VF_STOPPING | VF_DAEMONOPEN))
+    if ((vinum_conf.flags & (VF_STOPPING | VF_DAEMONOPEN))
 	== (VF_STOPPING | VF_DAEMONOPEN)) {		    /* at least one daemon open, we're stopping */
-	queue_daemon_request(daemonrq_return, di);	    /* stop the daemon */
-	tsleep(&vinumclose, 0, "vstop", 1);		    /* and wait for it */
+	queue_daemon_request(daemonrq_return, di);	    /* stop the daemon (queue ONCE: DF-4760) */
+	while ((vinum_conf.flags & VF_DAEMONOPEN) != 0
+	    && daemon_wait-- > 0)			    /* bounded wait: DF-4760 */
+	    tsleep(&vinumclose, 0, "vstop", 1);	    /* and wait for it */
     }
     if (SD != NULL) {
 	for (i = 0; i < vinum_conf.subdisks_allocated; i++) {
@@ -302,6 +305,17 @@
     case MOD_UNLOAD:
 	if (!vinum_inactive(1))				    /* is anything open? */
 	    return EBUSY;				    /* yes, we can't do it */
+	if (vinum_conf.flags & VF_DAEMONOPEN) {		    /* DF-4760: daemon device open */
+	    union daemoninfo di = { .nothing = 0 };
+	    int daemon_wait = 5 * hz;
+
+	    queue_daemon_request(daemonrq_return, di);   /* ask it to leave: ONCE */
+	    while ((vinum_conf.flags & VF_DAEMONOPEN) != 0
+		&& daemon_wait-- > 0)			    /* bounded wait */
+		tsleep(&vinumclose, 0, "vstop", 1);
+	    if (vinum_conf.flags & VF_DAEMONOPEN)	    /* it never left: */
+		return EBUSY;				    /* tear nothing down */
+	}
 	vinum_conf.flags |= VF_STOPPING;		    /* note that we want to stop */
 	sys_sync(NULL, NULL);			    /* write out buffers */
 	free_vinum(0);					    /* clean up */
@@ -560,8 +574,20 @@
 {
     cdev_t dev = ap->a_head.a_dev;
     struct volume *vol;
+    int index;
 
-    vol = &VOL[Volno(dev)];
+    /*
+     * DF-4758: only volume devices carry a volume number in the minor.
+     * Raw plex/sd minors encode the plex/sd number in the low 8 bits,
+     * which Volno() extracts verbatim, so dispatch on the type and
+     * bound the index before touching the VOL[] array.
+     */
+    if (DEVTYPE(dev) != VINUM_VOLUME_TYPE)
+	return (ENODEV);
+    index = Volno(dev);
+    if (index >= vinum_conf.volumes_allocated)
+	return (ENXIO);
+    vol = &VOL[index];
 
     if (vol->state == volume_up) {
 	ap->a_result = (int64_t)vol->size;