--- a/sys/dev/raid/mrsas/mrsas_fp.c +++ b/sys/dev/raid/mrsas/mrsas_fp.c @@ -264,6 +264,44 @@ return 1; } + /* + * Validate the per-LD geometry the driver later uses unchecked as loop + * bounds and divisors. A malicious or buggy firmware delivering a map + * with spanDepth > MAX_RAIDMAP_SPAN_DEPTH makes mr_update_span_set() + * write past LD_SPAN_SET.strip_offset[MAX_SPAN_DEPTH] and past the end + * of sc->log_to_span[] (the last member of mrsas_softc); a zero + * quad->diff reaches the unguarded division in mr_update_span_set() + * and a zero spanRowSize the divisions in get_arm() / + * mr_spanset_get_phy_params() (kernel #DE panic). + */ + { + u_int32_t l, s, q; + for (l = 0; l < MAX_LOGICAL_DRIVES; l++) { + u_int16_t ld = pFwRaidMap->ldTgtIdToLd[l]; + MR_LD_RAID *raid; + if (ld >= MAX_LOGICAL_DRIVES) + continue; + raid = MR_LdRaidGet(ld, map); + if (raid->spanDepth == 0 || raid->spanDepth > MAX_RAIDMAP_SPAN_DEPTH) + goto bad_map; + for (s = 0; s < raid->spanDepth; s++) { + MR_SPAN_INFO *si = &map->raidMap.ldSpanMap[ld]. + spanBlock[s].block_span_info; + MR_LD_SPAN *sp = &map->raidMap.ldSpanMap[ld]. + spanBlock[s].span; + if (si->noElements == 0 || si->noElements > MAX_QUAD_DEPTH) + goto bad_map; + for (q = 0; q < si->noElements; q++) + if (si->quad[q].diff == 0) + goto bad_map; + if (sp->spanRowSize == 0 && + (raid->level == 0 || raid->level == 5 || + raid->level == 6)) + goto bad_map; + } + } + } + if (sc->UnevenSpanSupport) { mr_update_span_set(map, ldSpanInfo); } @@ -271,6 +309,11 @@ mrsas_update_load_balance_params(map, sc->load_balance_info); return 0; + +bad_map: + device_printf(sc->mrsas_dev, "invalid RAID map geometry (ld/span/quad), " + "rejecting map\n"); + return 1; } /*