DF-3696 / fix.diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | --- 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,12 @@ } if (rdp->status & AR_S_DEGRADED) { /* do the XOR game if possible */ + /* not implemented: fail this I/O instead of leaking the + * request and leaving the bio forever incomplete */ + bzero(request, sizeof(struct ata_request)); + objcache_put(ata_request_cache, request); + biofinish(bp, NULL, EIO); + return(0); } else { request->this = drv; @@ -938,15 +963,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 +1684,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 +2001,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 +2763,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 +4013,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) { |