DF-4372 / 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 | --- a/sys/dev/drm/radeon/radeon.h 2026-06-29 12:51:19.000000000 +0000 +++ b/sys/dev/drm/radeon/radeon.h 2026-09-19 18:44:48.361621795 +0000 @@ -2331,6 +2331,7 @@ int disp_priority; /* BIOS */ uint8_t *bios; + size_t bios_size; /* size of the kmalloc'd *bios image */ bool is_atom_bios; uint16_t bios_header_start; struct radeon_bo *stolen_vga_memory; --- a/sys/dev/drm/radeon/radeon_bios.c 2026-07-22 23:04:24.341615154 +0000 +++ b/sys/dev/drm/radeon/radeon_bios.c 2026-09-19 18:44:48.361621795 +0000 @@ -66,6 +66,7 @@ return false; } rdev->bios = kmalloc(size, M_DRM, M_WAITOK); + rdev->bios_size = size; if (rdev->bios == NULL) { iounmap(bios); return false; @@ -96,6 +97,7 @@ return false; } rdev->bios = kzalloc(size, GFP_KERNEL); + rdev->bios_size = 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_size = 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_size = 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_size = vhdr->ImageLength; memcpy(rdev->bios, &vbios->VbiosContent, vhdr->ImageLength); ret = !!rdev->bios; --- a/sys/dev/drm/radeon/r600_dpm.c 2026-06-29 12:51:19.000000000 +0000 +++ b/sys/dev/drm/radeon/r600_dpm.c 2026-09-19 18:46:26.864362447 +0000 @@ -891,6 +891,15 @@ if (le16_to_cpu(power_info->pplib.usTableSize) >= sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) { if (power_info->pplib3.usFanTableOffset) { + u32 fan_off = data_offset + + le16_to_cpu(power_info->pplib3.usFanTableOffset); + + if (!rdev->bios_size || + fan_off + sizeof(union fan_info) > rdev->bios_size) { + DRM_ERROR("Invalid VBIOS fan table offset %u\n", + fan_off); + return -EINVAL; + } fan_info = (union fan_info *)((uint8_t*)mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib3.usFanTableOffset)); rdev->pm.dpm.fan.t_hyst = fan_info->fan.ucTHyst; @@ -1067,10 +1076,15 @@ /* ext tables */ if (le16_to_cpu(power_info->pplib.usTableSize) >= sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) { - ATOM_PPLIB_EXTENDEDHEADER *ext_hdr = (ATOM_PPLIB_EXTENDEDHEADER *) - (mode_info->atom_context->bios + data_offset + - le16_to_cpu(power_info->pplib3.usExtendendedHeaderOffset)); - if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2) && + u32 ext_off = le16_to_cpu(power_info->pplib3.usExtendendedHeaderOffset); + bool ext_hdr_ok = ext_off != 0 && rdev->bios_size && + ((u64)data_offset + ext_off + + sizeof(ATOM_PPLIB_EXTENDEDHEADER)) <= rdev->bios_size; + ATOM_PPLIB_EXTENDEDHEADER *ext_hdr = ext_hdr_ok ? + (ATOM_PPLIB_EXTENDEDHEADER *) + (mode_info->atom_context->bios + data_offset + ext_off) : NULL; + + if (ext_hdr_ok && (le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2) && ext_hdr->usVCETableOffset) { VCEClockInfoArray *array = (VCEClockInfoArray *) (mode_info->atom_context->bios + data_offset + @@ -1132,7 +1146,7 @@ ((u8 *)state_entry + sizeof(ATOM_PPLIB_VCE_State_Record)); } } - if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) && + if (ext_hdr_ok && (le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) && ext_hdr->usUVDTableOffset) { UVDClockInfoArray *array = (UVDClockInfoArray *) (mode_info->atom_context->bios + data_offset + @@ -1168,7 +1182,7 @@ ((u8 *)entry + sizeof(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record)); } } - if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4) && + if (ext_hdr_ok && (le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4) && ext_hdr->usSAMUTableOffset) { ATOM_PPLIB_SAMClk_Voltage_Limit_Table *limits = (ATOM_PPLIB_SAMClk_Voltage_Limit_Table *) @@ -1195,7 +1209,7 @@ ((u8 *)entry + sizeof(ATOM_PPLIB_SAMClk_Voltage_Limit_Record)); } } - if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) && + if (ext_hdr_ok && (le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) && ext_hdr->usPPMTableOffset) { ATOM_PPLIB_PPM_Table *ppm = (ATOM_PPLIB_PPM_Table *) (mode_info->atom_context->bios + data_offset + @@ -1226,7 +1240,7 @@ rdev->pm.dpm.dyn_state.ppm_table->tj_max = le32_to_cpu(ppm->ulTjmax); } - if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6) && + if (ext_hdr_ok && (le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6) && ext_hdr->usACPTableOffset) { ATOM_PPLIB_ACPClk_Voltage_Limit_Table *limits = (ATOM_PPLIB_ACPClk_Voltage_Limit_Table *) @@ -1253,7 +1267,7 @@ ((u8 *)entry + sizeof(ATOM_PPLIB_ACPClk_Voltage_Limit_Record)); } } - if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7) && + if (ext_hdr_ok && (le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7) && ext_hdr->usPowerTuneTableOffset) { u8 rev = *(u8 *)(mode_info->atom_context->bios + data_offset + le16_to_cpu(ext_hdr->usPowerTuneTableOffset)); |