DF-1947 / 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 | diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c b/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c --- a/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c +++ b/sys/dev/drm/amd/amdgpu/amdgpu_ucode.c @@ -334,6 +334,17 @@ cp_hdr = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data; dmcu_hdr = (const struct dmcu_firmware_header_v1_0 *)ucode->fw->data; + const struct firmware *fw = ucode->fw; + uint32_t fw_size = fw->datasize; + uint32_t arr_off = le32_to_cpu(header->ucode_array_offset_bytes); + uint32_t ucode_size_bytes = le32_to_cpu(header->ucode_size_bytes); + + /* DF-1947: the firmware source window for every memcpy below is + * fw->data[arr_off .. arr_off+ucode_size). Validate it once before + * any branch uses it. */ + if (arr_off > fw_size || ucode_size_bytes > fw_size - arr_off) + return -EINVAL; + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP || (ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC1 && ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC2 && @@ -344,40 +355,52 @@ ucode->ucode_id != AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM && ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_ERAM && ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_INTV)) { - ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes); + ucode->ucode_size = ucode_size_bytes; - memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data + - le32_to_cpu(header->ucode_array_offset_bytes)), + memcpy(ucode->kaddr, (void *)((uint8_t *)fw->data + arr_off), ucode->ucode_size); } else if (ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC1 || ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2) { - ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes) - - le32_to_cpu(cp_hdr->jt_size) * 4; + uint32_t jt_size = le32_to_cpu(cp_hdr->jt_size); + /* DF-1947: guard the uint32 subtraction against underflow. */ + if (jt_size > UINT32_MAX / 4 || jt_size * 4 > ucode_size_bytes) + return -EINVAL; + ucode->ucode_size = ucode_size_bytes - jt_size * 4; - memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data + - le32_to_cpu(header->ucode_array_offset_bytes)), + memcpy(ucode->kaddr, (void *)((uint8_t *)fw->data + arr_off), ucode->ucode_size); } else if (ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC1_JT || ucode->ucode_id == AMDGPU_UCODE_ID_CP_MEC2_JT) { - ucode->ucode_size = le32_to_cpu(cp_hdr->jt_size) * 4; + uint32_t jt_size = le32_to_cpu(cp_hdr->jt_size); + uint32_t jt_off = le32_to_cpu(cp_hdr->jt_offset); + if (jt_size > UINT32_MAX / 4 || jt_off > UINT32_MAX / 4) + return -EINVAL; + ucode->ucode_size = jt_size * 4; + if (arr_off > fw_size || + jt_off * 4 > fw_size - arr_off || + ucode->ucode_size > (fw_size - arr_off) - jt_off * 4) + return -EINVAL; - memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data + - le32_to_cpu(header->ucode_array_offset_bytes) + - le32_to_cpu(cp_hdr->jt_offset) * 4), + memcpy(ucode->kaddr, (void *)((uint8_t *)fw->data + + arr_off + jt_off * 4), ucode->ucode_size); } else if (ucode->ucode_id == AMDGPU_UCODE_ID_DMCU_ERAM) { - ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes) - - le32_to_cpu(dmcu_hdr->intv_size_bytes); + uint32_t intv_size = le32_to_cpu(dmcu_hdr->intv_size_bytes); + /* DF-1947: guard the uint32 subtraction against underflow. */ + if (intv_size > ucode_size_bytes) + return -EINVAL; + ucode->ucode_size = ucode_size_bytes - intv_size; - memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data + - le32_to_cpu(header->ucode_array_offset_bytes)), + memcpy(ucode->kaddr, (void *)((uint8_t *)fw->data + arr_off), ucode->ucode_size); } else if (ucode->ucode_id == AMDGPU_UCODE_ID_DMCU_INTV) { - ucode->ucode_size = le32_to_cpu(dmcu_hdr->intv_size_bytes); + uint32_t intv_off = le32_to_cpu(dmcu_hdr->intv_offset_bytes); + uint32_t intv_size = le32_to_cpu(dmcu_hdr->intv_size_bytes); + if (intv_off > fw_size || intv_size > fw_size - intv_off) + return -EINVAL; + ucode->ucode_size = intv_size; - memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data + - le32_to_cpu(header->ucode_array_offset_bytes) + - le32_to_cpu(dmcu_hdr->intv_offset_bytes)), + memcpy(ucode->kaddr, (void *)((uint8_t *)fw->data + intv_off), ucode->ucode_size); } else if (ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL) { ucode->ucode_size = adev->gfx.rlc.save_restore_list_cntl_size_bytes; @@ -407,15 +430,31 @@ if (NULL == ucode->fw) return 0; - comm_hdr = (const struct common_firmware_header *)ucode->fw->data; - header = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data; + const struct firmware *fw = ucode->fw; + uint32_t fw_size = fw->datasize; + uint32_t jt_size, jt_off, arr_off, ucode_size_bytes; + + comm_hdr = (const struct common_firmware_header *)fw->data; + header = (const struct gfx_firmware_header_v1_0 *)fw->data; + jt_size = le32_to_cpu(header->jt_size); + jt_off = le32_to_cpu(header->jt_offset); + arr_off = le32_to_cpu(comm_hdr->ucode_array_offset_bytes); + ucode_size_bytes = le32_to_cpu(comm_hdr->ucode_size_bytes); + + /* DF-1947: jt_size*4 must not wrap, must fit in source window, and + * the source window itself must lie in fw->data. */ + if (jt_size > UINT32_MAX / 4 || jt_off > UINT32_MAX / 4) + return -EINVAL; + if (arr_off > fw_size || ucode_size_bytes > fw_size - arr_off) + return -EINVAL; + if (jt_off * 4 > ucode_size_bytes || + jt_size * 4 > ucode_size_bytes - jt_off * 4) + return -EINVAL; + dst_addr = ucode->kaddr + - ALIGN(le32_to_cpu(comm_hdr->ucode_size_bytes), - PAGE_SIZE); - src_addr = (uint8_t *)ucode->fw->data + - le32_to_cpu(comm_hdr->ucode_array_offset_bytes) + - (le32_to_cpu(header->jt_offset) * 4); - memcpy(dst_addr, src_addr, le32_to_cpu(header->jt_size) * 4); + ALIGN(ucode_size_bytes, PAGE_SIZE); + src_addr = (uint8_t *)fw->data + arr_off + jt_off * 4; + memcpy(dst_addr, src_addr, jt_size * 4); return 0; } |