⬢ DragonFlyBSD Kernel Audit
DF-5392 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/isa/isa_common.c
+++ b/sys/bus/isa/isa_common.c
@@ -75,6 +75,13 @@
 
 MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device");
 
+/*
+ * Cap on candidate addresses probed per resource range in isa_find_*.
+ * A crafted PnP descriptor with a huge window and align=1 could otherwise
+ * spin the allocator ~2^32 times (boot-time stall).
+ */
+#define	ISA_FIND_MAX_TRIES	65536
+
 static devclass_t isa_devclass;
 static int isa_running;
 
@@ -127,11 +134,13 @@
 	result->ic_nmem = config->ic_nmem;
 	for (i = 0; i < config->ic_nmem; i++) {
 		u_int32_t start, end, size, align;
+		int tries = 0;
 		for (start = config->ic_mem[i].ir_start,
 			     end = config->ic_mem[i].ir_end,
 			     size = config->ic_mem[i].ir_size,
 			     align = config->ic_mem[i].ir_align;
-		     start + size - 1 <= end;
+		     start <= end && start + size - 1 <= end
+		     && ++tries <= ISA_FIND_MAX_TRIES;
 		     start += MAX(align, 1)) {
 			bus_set_resource(child, SYS_RES_MEMORY, i,
 					 start, size, -1);
@@ -942,6 +951,23 @@
 	struct isa_device* idev = DEVTOISA(child);
 	struct isa_config_entry *newice, *ice;
 
+	/*
+	 * Security: the count fields index fixed-size arrays in every
+	 * consumer (isa_find_* loops, config callbacks).  Reject any
+	 * config with out-of-range counts instead of persisting it.
+	 */
+	if (config->ic_nmem < 0 || config->ic_nmem > ISA_NMEM
+	    || config->ic_nport < 0 || config->ic_nport > ISA_NPORT
+	    || config->ic_nirq < 0 || config->ic_nirq > ISA_NIRQ
+	    || config->ic_ndrq < 0 || config->ic_ndrq > ISA_NDRQ) {
+		kprintf("isa_add_config: %s%d bogus counts "
+		    "(nmem=%d nport=%d nirq=%d ndrq=%d), rejected\n",
+		    device_get_name(child), device_get_unit(child),
+		    config->ic_nmem, config->ic_nport,
+		    config->ic_nirq, config->ic_ndrq);
+		return EINVAL;
+	}
+
 	newice = kmalloc(sizeof *ice, M_DEVBUF, M_WAITOK);
 	newice->ice_priority = priority;
 	newice->ice_config = *config;
--- a/sys/bus/isa/pnp.c
+++ b/sys/bus/isa/pnp.c
@@ -335,13 +335,13 @@
 			case PNP_QUIRK_EXTRA_IO:
 				if (config == NULL)
 					break;
-                                if (qp->arg1 != 0) {
+                                if (qp->arg1 != 0 && config->ic_nport < ISA_NPORT) {
                                         config->ic_nport++;
                                         config->ic_port[config->ic_nport - 1] = config->ic_port[0];
                                         config->ic_port[config->ic_nport - 1].ir_start += qp->arg1;
                                         config->ic_port[config->ic_nport - 1].ir_end += qp->arg1;
                                 }
-                                if (qp->arg2 != 0) {
+                                if (qp->arg2 != 0 && config->ic_nport < ISA_NPORT) {
                                         config->ic_nport++;
                                         config->ic_port[config->ic_nport - 1] = config->ic_port[0];
                                         config->ic_port[config->ic_nport - 1].ir_start += qp->arg2;
--- a/sys/bus/isa/pnpparse.c
+++ b/sys/bus/isa/pnpparse.c
@@ -98,7 +98,7 @@
 			break;
 	    
 		case PNP_TAG_IRQ_FORMAT:
-			if (config->ic_nirq == ISA_NIRQ) {
+			if (config->ic_nirq >= ISA_NIRQ) {
 				pnp_printf(id, "too many irqs\n");
 				return (1);
 			}
@@ -116,7 +116,7 @@
 			break;
 
 		case PNP_TAG_DMA_FORMAT:
-			if (config->ic_ndrq == ISA_NDRQ) {
+			if (config->ic_ndrq >= ISA_NDRQ) {
 				pnp_printf(id, "too many drqs\n");
 				return (1);
 			}
@@ -134,7 +134,7 @@
 			break;
 
 		case PNP_TAG_IO_RANGE:
-			if (config->ic_nport == ISA_NPORT) {
+			if (config->ic_nport >= ISA_NPORT) {
 				pnp_printf(id, "too many ports\n");
 				return (1);
 			}
@@ -171,7 +171,7 @@
 			break;
 
 		case PNP_TAG_IO_FIXED:
-			if (config->ic_nport == ISA_NPORT) {
+			if (config->ic_nport >= ISA_NPORT) {
 				pnp_printf(id, "too many ports\n");
 				return (1);
 			}
@@ -235,7 +235,7 @@
 			break;
 			
 		case PNP_TAG_MEMORY_RANGE:
-			if (config->ic_nmem == ISA_NMEM) {
+			if (config->ic_nmem >= ISA_NMEM) {
 				pnp_printf(id, "too many memory ranges\n");
 				return (1);
 			}
@@ -271,7 +271,7 @@
 			break;
 
 		case PNP_TAG_MEMORY32_RANGE:
-			if (config->ic_nmem == ISA_NMEM) {
+			if (config->ic_nmem >= ISA_NMEM) {
 				pnp_printf(id, "too many memory ranges\n");
 				return (1);
 			}
@@ -301,7 +301,7 @@
 			break;
 
 		case PNP_TAG_MEMORY32_FIXED:
-			if (config->ic_nmem == ISA_NMEM) {
+			if (config->ic_nmem >= ISA_NMEM) {
 				pnp_printf(id, "too many memory ranges\n");
 				return (1);
 			}
@@ -363,7 +363,7 @@
 
 	parent = device_get_parent(dev);
 	for (i = 0; i < from->ic_nmem; i++) {
-		if (to->ic_nmem == ISA_NMEM) {
+		if (to->ic_nmem >= ISA_NMEM) {
 			device_printf(parent, "too many memory ranges\n");
 			return;
 		}
@@ -371,7 +371,7 @@
 		to->ic_nmem++;
 	}
 	for (i = 0; i < from->ic_nport; i++) {
-		if (to->ic_nport == ISA_NPORT) {
+		if (to->ic_nport >= ISA_NPORT) {
 			device_printf(parent, "too many port ranges\n");
 			return;
 		}
@@ -379,7 +379,7 @@
 		to->ic_nport++;
 	}
 	for (i = 0; i < from->ic_nirq; i++) {
-		if (to->ic_nirq == ISA_NIRQ) {
+		if (to->ic_nirq >= ISA_NIRQ) {
 			device_printf(parent, "too many irq ranges\n");
 			return;
 		}
@@ -387,7 +387,7 @@
 		to->ic_nirq++;
 	}
 	for (i = 0; i < from->ic_ndrq; i++) {
-		if (to->ic_ndrq == ISA_NDRQ) {
+		if (to->ic_ndrq >= ISA_NDRQ) {
 			device_printf(parent, "too many drq ranges\n");
 			return;
 		}