⬢ DragonFlyBSD Kernel Audit
DF-4331 / fix.diff
← back to finding ↓ download raw
--- 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;
 }
 
 /*