DF-1252 / fix.diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | 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); |