⬢ DragonFlyBSD Kernel Audit
DF-3694 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/disk/nata/ata-raid.c
+++ b/sys/dev/disk/nata/ata-raid.c
@@ -247,6 +247,8 @@
 
     switch (cmd) {
     case IOCATARAIDSTATUS:
+	if (status->lun < 0 || status->lun >= MAX_ARRAYS)
+	    return EINVAL;
 	error = ata_raid_status(status);
 	break;
 			
@@ -255,14 +257,20 @@
 	break;
 	 
     case IOCATARAIDDELETE:
+	if (*lun < 0 || *lun >= MAX_ARRAYS)
+	    return EINVAL;
 	error = ata_raid_delete(*lun);
 	break;
      
     case IOCATARAIDADDSPARE:
+	if (config->lun < 0 || config->lun >= MAX_ARRAYS)
+	    return EINVAL;
 	error = ata_raid_addspare(config);
 	break;
 			    
     case IOCATARAIDREBUILD:
+	if (*lun < 0 || *lun >= MAX_ARRAYS)
+	    return EINVAL;
 	error = ata_raid_rebuild(*lun);
 	break;
     }
@@ -326,6 +334,17 @@
 
     if (!(rdp->status & AR_S_READY) ||
 	(bbp->b_cmd != BUF_CMD_READ && bbp->b_cmd != BUF_CMD_WRITE)) {
+	biofinish(bp, NULL, EIO);
+	return(0);
+    }
+
+    /* metadata is untrusted: never index disks[] out of range */
+    if (rdp->width < 1 || rdp->width > MAX_DISKS ||
+	((rdp->type == AR_T_RAID1 || rdp->type == AR_T_RAID01) &&
+	 rdp->width * 2 > MAX_DISKS) ||
+	(rdp->type == AR_T_RAID5 && rdp->width < 2)) {
+	kprintf("ar%d: illegal array geometry (width %d)\n",
+	       rdp->lun, rdp->width);
 	biofinish(bp, NULL, EIO);
 	return(0);
     }
@@ -608,6 +627,9 @@
 	    }
 	    if (rdp->status & AR_S_DEGRADED) {
 		/* do the XOR game if possible */
+		ata_free_request(request);
+		biofinish(bp, NULL, EIO);
+		return(0);
 	    }
 	    else {
 		request->this = drv;
@@ -938,15 +960,15 @@
 
     case AR_T_RAID1:
     case AR_T_RAID01:
-	for (disk = 0; disk < rdp->width; disk++) {
-	    if (!(rdp->disks[disk].flags & AR_DF_ONLINE) &&
-		!(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) {
+	for (disk = 0; disk < rdp->width && disk < MAX_DISKS; disk++) {
+	    int mir_online =
+		(disk + rdp->width < MAX_DISKS) ?
+		(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE) : 0;
+
+	    if (!(rdp->disks[disk].flags & AR_DF_ONLINE) && !mir_online) {
 		rdp->status &= ~AR_S_READY;
 	    }
-	    else if (((rdp->disks[disk].flags & AR_DF_ONLINE) &&
-		      !(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) ||
-		     (!(rdp->disks[disk].flags & AR_DF_ONLINE) &&
-		      (rdp->disks [disk + rdp->width].flags & AR_DF_ONLINE))) {
+	    else if (!(rdp->disks[disk].flags & AR_DF_ONLINE) || !mir_online) {
 		rdp->status |= AR_S_DEGRADED;
 	    }
 	}
@@ -1659,6 +1681,11 @@
 	goto adaptec_out;
     }
 
+    if (be16toh(meta->configs[0].total_disks) > MAX_DISKS) {
+	device_printf(parent, "Adaptec total_disks out of range\n");
+	goto adaptec_out;
+    }
+
     if (testing || bootverbose)
 	ata_raid_adaptec_print_meta(meta);
 
@@ -1971,7 +1998,7 @@
 	if (rdp->disks[disk].dev) {
 	    if (ata_raid_rw(rdp->disks[disk].dev,
 			    HPTV2_LBA(rdp->disks[disk].dev), meta,
-			    sizeof(struct promise_raid_conf),
+			    sizeof(struct hptv2_raid_conf),
 			    ATA_R_WRITE | ATA_R_DIRECT)) {
 		device_printf(rdp->disks[disk].dev, "write metadata failed\n");
 		error = EIO;
@@ -2733,7 +2760,7 @@
 	if (rdp->disks[disk].serial[0])
 	    bcopy(rdp->disks[disk].serial,&meta->disks[disk],sizeof(u_int32_t));
 	else
-	    meta->disks[disk] = (u_int32_t)(uintptr_t)rdp->disks[disk].dev;
+	    meta->disks[disk] = karc4random();
     }
 
     for (disk = 0; disk < rdp->total_disks; disk++) {
@@ -3983,7 +4010,7 @@
     meta->disk_sectors = 
 	rdp->total_sectors / (rdp->width - (rdp->type == AR_RAID5));
     for (disk = 0; disk < rdp->total_disks; disk++)
-	meta->disks[disk] = (u_int32_t)(uintptr_t)rdp->disks[disk].dev;
+	meta->disks[disk] = karc4random();
 
     for (disk = 0; disk < rdp->total_disks; disk++) {
 	if (rdp->disks[disk].dev) {