DragonFlyBSD Kernel Audit
DF-1252 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/radeon/radeon.h b/sys/dev/drm/radeon/radeon.h
--- a/sys/dev/drm/radeon/radeon.h
+++ b/sys/dev/drm/radeon/radeon.h
@@ -2331,6 +2331,7 @@
 	int				disp_priority;
 	/* BIOS */
 	uint8_t				*bios;
+	size_t				bios_size;
 	bool				is_atom_bios;
 	uint16_t			bios_header_start;
 	struct radeon_bo		*stolen_vga_memory;
@@ -2686,6 +2687,12 @@
 #define RBIOS8(i) (rdev->bios[i])
 #define RBIOS16(i) (RBIOS8(i) | (RBIOS8((i)+1) << 8))
 #define RBIOS32(i) ((RBIOS16(i)) | (RBIOS16((i)+2) << 16))
+/* Returns true if [off, off+len) is within the cached BIOS image. */
+static inline bool radeon_bios_in(struct radeon_device *rdev, size_t off, size_t len)
+{
+	return rdev->bios != NULL && off < rdev->bios_size &&
+	       len <= rdev->bios_size && off + len <= rdev->bios_size;
+}
 
 int radeon_combios_init(struct radeon_device *rdev);
 void radeon_combios_fini(struct radeon_device *rdev);
diff --git a/sys/dev/drm/radeon/radeon_bios.c b/sys/dev/drm/radeon/radeon_bios.c
--- a/sys/dev/drm/radeon/radeon_bios.c
+++ b/sys/dev/drm/radeon/radeon_bios.c
@@ -54,7 +54,7 @@
 		if (!radeon_card_posted(rdev))
 			return false;
 
-	rdev->bios = NULL;
+	rdev->bios = NULL; rdev->bios_size = 0;
 	vram_base = pci_resource_start(rdev->pdev, 0);
 	bios = ioremap(vram_base, size);
 	if (!bios) {
@@ -70,6 +70,7 @@
 		iounmap(bios);
 		return false;
 	}
+	rdev->bios_size = size;
 	memcpy_fromio(rdev->bios, bios, size);
 	iounmap(bios);
 	return true;
@@ -81,7 +82,7 @@
 	size_t size;
 	device_t vga_dev = device_get_parent(rdev->dev->bsddev);
 
-	rdev->bios = NULL;
+	rdev->bios = NULL; rdev->bios_size = 0;
 	/* XXX: some cards may return 0 for rom size? ddx has a workaround */
 	bios = vga_pci_map_bios(vga_dev, &size);
 	if (!bios) {
@@ -100,6 +101,7 @@
 		vga_pci_unmap_bios(vga_dev, bios);
 		return false;
 	}
+	rdev->bios_size = size;
 	memcpy_fromio(rdev->bios, bios, size);
 	vga_pci_unmap_bios(vga_dev, bios);
 	return true;
@@ -120,7 +122,7 @@
 	uint8_t *bios;
 	size_t size;
 
-	rdev->bios = NULL;
+	rdev->bios = NULL; rdev->bios_size = 0;
 
 	saved_rom_bar = pci_read_config(bsddev, PCIR_BIOS, 4);
 	rom_addr = saved_rom_bar & ~1U; /* strip enable bit */
@@ -151,6 +153,7 @@
 	}
 
 	rdev->bios = kmemdup(bios, size, GFP_KERNEL);
+	rdev->bios_size = rdev->bios ? size : 0;
 	pmap_unmapdev((vm_offset_t)bios, 256 * 1024);
 	pci_write_config(bsddev, PCIR_BIOS, saved_rom_bar, 4);
 
@@ -271,6 +274,7 @@
 		DRM_ERROR("Unable to allocate bios\n");
 		return false;
 	}
+	rdev->bios_size = size;
 
 	for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
 		DRM_INFO("%s: Call radeon_atrm_call()\n", __func__);
@@ -715,6 +719,7 @@
 	}
 
 	rdev->bios = kmalloc(vhdr->ImageLength, M_DRM, M_WAITOK);
+	rdev->bios_size = rdev->bios ? vhdr->ImageLength : 0;
 	memcpy(rdev->bios, &vbios->VbiosContent, vhdr->ImageLength);
 	ret = !!rdev->bios;
 
@@ -746,7 +751,7 @@
 		r = radeon_read_platform_bios(rdev);
 	if (r == false || rdev->bios == NULL) {
 		DRM_ERROR("Unable to locate a BIOS ROM\n");
-		rdev->bios = NULL;
+		rdev->bios = NULL; rdev->bios_size = 0;
 		return false;
 	}
 	if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
@@ -776,6 +781,6 @@
 	return true;
 free_bios:
 	kfree(rdev->bios);
-	rdev->bios = NULL;
+	rdev->bios = NULL; rdev->bios_size = 0;
 	return false;
 }
diff --git a/sys/dev/drm/radeon/radeon_combios.c b/sys/dev/drm/radeon/radeon_combios.c
--- a/sys/dev/drm/radeon/radeon_combios.c
+++ b/sys/dev/drm/radeon/radeon_combios.c
@@ -1247,6 +1247,10 @@
 			tmp = RBIOS16(lcd_info + 64 + i * 2);
 			if (tmp == 0)
 				break;
+			/* tmp is an unchecked 16-bit offset into the BIOS image;
+			 * validate it before dereferencing (max access is tmp+30). */
+			if (!radeon_bios_in(rdev, tmp, 30))
+				continue;
 
 			if ((RBIOS16(tmp) == lvds->native_mode.hdisplay) &&
 			    (RBIOS16(tmp + 2) == lvds->native_mode.vdisplay)) {
@@ -2753,7 +2757,8 @@
 				} else {
 					u8 entries = RBIOS8(offset + 0x5 + 0xb);
 					u16 voltage_table_offset = RBIOS16(offset + 0x5 + 0xc);
-					if (entries && voltage_table_offset) {
+					if (entries && voltage_table_offset &&
+					    radeon_bios_in(rdev, voltage_table_offset, 3)) {
 						rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.reg =
 							RBIOS16(voltage_table_offset) * 4;
 						tmp = RBIOS8(voltage_table_offset + 0x2);