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);