DragonFlyBSD Kernel Audit
DF-1250 / 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;
+	uint32_t			bios_length;	/* DF-1250/1251: allocation size of *bios, in bytes */
 	bool				is_atom_bios;
 	uint16_t			bios_header_start;
 	struct radeon_bo		*stolen_vga_memory;
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
@@ -66,6 +66,7 @@
 		return false;
 	}
 	rdev->bios = kmalloc(size, M_DRM, M_WAITOK);
+	rdev->bios_length = size;
 	if (rdev->bios == NULL) {
 		iounmap(bios);
 		return false;
@@ -96,6 +97,7 @@
 		return false;
 	}
 	rdev->bios = kzalloc(size, GFP_KERNEL);
+	rdev->bios_length = size;
 	if (rdev->bios == NULL) {
 		vga_pci_unmap_bios(vga_dev, bios);
 		return false;
@@ -151,6 +153,7 @@
 	}
 
 	rdev->bios = kmemdup(bios, size, GFP_KERNEL);
+	rdev->bios_length = size;
 	pmap_unmapdev((vm_offset_t)bios, 256 * 1024);
 	pci_write_config(bsddev, PCIR_BIOS, saved_rom_bar, 4);
 
@@ -267,6 +270,7 @@
 		return false;
 
 	rdev->bios = kmalloc(size, M_DRM, M_WAITOK);
+	rdev->bios_length = size;
 	if (!rdev->bios) {
 		DRM_ERROR("Unable to allocate bios\n");
 		return false;
@@ -715,6 +719,7 @@
 	}
 
 	rdev->bios = kmalloc(vhdr->ImageLength, M_DRM, M_WAITOK);
+	rdev->bios_length = vhdr->ImageLength;
 	memcpy(rdev->bios, &vbios->VbiosContent, vhdr->ImageLength);
 	ret = !!rdev->bios;
 
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
@@ -371,7 +371,19 @@
 		return false;
 
 	raw = rdev->bios + edid_info;
+	/* DF-1250: raw[0x7e] is attacker-controlled (malicious VBIOS). Make
+	 * sure the EDID block stays inside the BIOS allocation before we
+	 * dereference raw[0x7e] and memcpy it out; otherwise a small (e.g.
+	 * 512-byte) BIOS slab with raw[0x7e]=0xff leaks ~32 KB of adjacent
+	 * kernel heap via the memcpy below. */
+	if (rdev->bios_length == 0 ||
+	    (uint64_t)edid_info + 0x7f > rdev->bios_length)
+		return false;
 	size = EDID_LENGTH * (raw[0x7e] + 1);
+	if ((uint64_t)edid_info + size > rdev->bios_length) {
+		dev_warn(rdev->dev, "hardcoded EDID table overruns BIOS image\n");
+		return false;
+	}
 	edid = kmalloc(size, M_DRM, M_WAITOK);
 	if (edid == NULL)
 		return false;