⬢ DragonFlyBSD Kernel Audit
DF-5483 / fix.diff
← back to finding ↓ download raw
--- sys/platform/pc64/acpica/acpi_pstate_machdep.c
+++ sys/platform/pc64/acpica/acpi_pstate_machdep.c
@@ -487,6 +487,24 @@ acpi_pst_intel_check_csr(const struct acp
 	case ACPI_ADR_SPACE_SYSTEM_IO:
 		if (ctrl->pr_res == NULL) {
 			kprintf("cpu%d: ioport allocation failed for control "
 				"register\n", mycpuid);
 			return ENXIO;
 		}
+		/*
+		 * The IO port came from firmware (_PCT).  A GAS address
+		 * beyond the 16-bit IO space cannot be a port: the x86
+		 * accessors silently truncate such an "address", so a
+		 * bogus table would make the kernel write to an entirely
+		 * different (truncated) port.  Reject it explicitly.
+		 */
+		if (ctrl->pr_gas.Address >= 0x10000 ||
+		    ctrl->pr_gas.BitWidth / NBBY > 0x10000 - ctrl->pr_gas.Address) {
+			kprintf("cpu%d: control register IO address %#jx "
+				"out of range\n", mycpuid,
+				(uintmax_t)ctrl->pr_gas.Address);
+			return EINVAL;
+		}
 		error = acpi_pst_md_gas_verify(&ctrl->pr_gas);
 		if (error) {
 			kprintf("cpu%d: Invalid control register GAS\n",
 				mycpuid);
 			return error;
@@ -500,6 +518,16 @@ acpi_pst_intel_check_csr(const struct acp
 		if (status->pr_res == NULL) {
 			kprintf("cpu%d: ioport allocation failed for status "
 				"register\n", mycpuid);
 			return ENXIO;
 		}
+		if (status->pr_gas.Address >= 0x10000 ||
+		    status->pr_gas.BitWidth / NBBY > 0x10000 - status->pr_gas.Address) {
+			kprintf("cpu%d: status register IO address %#jx "
+				"out of range\n", mycpuid,
+				(uintmax_t)status->pr_gas.Address);
+			return EINVAL;
+		}
 		error = acpi_pst_md_gas_verify(&status->pr_gas);
 		if (error) {
 			kprintf("cpu%d: Invalid status register GAS\n",
 				mycpuid);