⬢ DragonFlyBSD Kernel Audit
DF-4942 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.c
+++ b/sys/dev/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.c
@@ -170,28 +170,36 @@
 	 * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK
 	 * directly in the create method */
 	case mmDC_GPIO_DDC1_A:
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC1;
 		return true;
 	case mmDC_GPIO_DDC2_A:
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC2;
 		return true;
 	case mmDC_GPIO_DDC3_A:
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC3;
 		return true;
 	case mmDC_GPIO_DDC4_A:
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC4;
 		return true;
 	case mmDC_GPIO_DDC5_A:
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC5;
 		return true;
 	case mmDC_GPIO_DDC6_A:
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC6;
 		return true;
 	case mmDC_GPIO_DDCVGA_A:
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC_VGA;
 		return true;
 	/* GPIO_I2CPAD */
 	case mmDC_GPIO_I2CPAD_A:
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_I2C_PAD;
 		return true;
 	/* Not implemented */
@@ -377,8 +385,12 @@
 	break;
 	case GPIO_ID_GPIO_PAD:
 		info->offset = mmGPIOPAD_A;
-		info->mask = (1 << en);
-		result = (info->mask <= GPIO_GPIO_PAD_MAX);
+		/* validate the pin INDEX, not the derived mask
+		 * (mask 1<<en was compared against GPIO_GPIO_PAD_MAX==30:
+		 * valid pads 5..30 were rejected and en >= 32 hit UB) */
+		result = (en <= GPIO_GPIO_PAD_MAX);
+		if (result)
+			info->mask = (1 << en);
 	break;
 	case GPIO_ID_VIP_PAD:
 	default:
--- a/sys/dev/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c
+++ b/sys/dev/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c
@@ -163,28 +163,36 @@
 	 * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK
 	 * directly in the create method */
 	case REG(DC_GPIO_DDC1_A):
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC1;
 		return true;
 	case REG(DC_GPIO_DDC2_A):
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC2;
 		return true;
 	case REG(DC_GPIO_DDC3_A):
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC3;
 		return true;
 	case REG(DC_GPIO_DDC4_A):
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC4;
 		return true;
 	case REG(DC_GPIO_DDC5_A):
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC5;
 		return true;
 	case REG(DC_GPIO_DDC6_A):
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC6;
 		return true;
 	case REG(DC_GPIO_DDCVGA_A):
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_DDC_VGA;
 		return true;
 	/* GPIO_I2CPAD */
 	case REG(DC_GPIO_I2CPAD_A):
+		*id = GPIO_ID_DDC_DATA;
 		*en = GPIO_DDC_LINE_I2C_PAD;
 		return true;
 	/* Not implemented */
--- a/sys/dev/drm/amd/display/dc/gpio/gpio_service.c
+++ b/sys/dev/drm/amd/display/dc/gpio/gpio_service.c
@@ -418,6 +418,17 @@
 	if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en))
 		return NULL;
 
+	/* offset_to_id() used to leave *id unwritten for DDC-family
+	 * offsets, and returns success for non-DDC domains (e.g. the
+	 * GPIOPAD map yields en up to GPIO_GPIO_PAD_MAX = 30) while this
+	 * consumer treats en as a gpio_ddc_line and lets the factory index
+	 * ddc_data_regs[]/ddc_clk_regs[] (GPIO_DDC_LINE_COUNT = 8 entries)
+	 * with it.  Only accept a genuine DDC decode. */
+	if (id != GPIO_ID_DDC_DATA) {
+		ASSERT_CRITICAL(false);
+		return NULL;
+	}
+
 	ddc = kzalloc(sizeof(struct ddc), GFP_KERNEL);
 
 	if (!ddc) {