DragonFlyBSD Kernel Audit
DF-2027 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/amd/amdgpu/atom.h b/sys/dev/drm/amd/amdgpu/atom.h
index 1111111..2222222 100644
@@ -127,6 +127,7 @@
 	struct card_info *card;
 	struct lock mutex;
 	void *bios;
+	uint32_t bios_size;
 	uint32_t cmd_table, data_table;
 	uint16_t *iio;
 
diff --git a/sys/dev/drm/amd/amdgpu/atom.c b/sys/dev/drm/amd/amdgpu/atom.c
index 3333333..4444444 100644
@@ -1306,6 +1306,7 @@
 
 	ctx->card = card;
 	ctx->bios = bios;
+	ctx->bios_size = 0;
 
 	if (CU16(0) != ATOM_BIOS_MAGIC) {
 		pr_info("Invalid BIOS magic\n");
@@ -1392,8 +1393,25 @@
 	if (!mdt[index])
 		return false;
 
-	if (size)
-		*size = CU16(idx);
+	/*
+	 * idx (and the data table it points at) is read directly from the VBIOS
+	 * image and is therefore attacker-controlled.  Validate that the whole
+	 * table -- including its size/frev/crev header -- lies within the BIOS
+	 * image before returning it, so callers that dereference
+	 * (ctx->bios + idx) cannot read past the kmalloc'd VBIOS buffer.
+	 * ctx->bios_size of 0 means unknown (legacy callers): skip the check.
+	 */
+	{
+		uint16_t tbl_size = CU16(idx);
+
+		if (ctx->bios_size &&
+		    ((uint32_t)idx + 4 > ctx->bios_size ||
+		     (uint32_t)idx + tbl_size > ctx->bios_size))
+			return false;
+		if (size)
+			*size = tbl_size;
+	}
+
 	if (frev)
 		*frev = CU8(idx + 2);
 	if (crev)
diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c b/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c
index 5555555..6666666 100644
@@ -2035,6 +2035,7 @@
 	atom_card_info->pll_write = cail_pll_write;
 
 	adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios);
+	adev->mode_info.atom_context->bios_size = adev->bios_size;
 	if (!adev->mode_info.atom_context) {
 		amdgpu_atombios_fini(adev);
 		return -ENOMEM;