Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: Fix invalid DPIA AUX reply causing system hang

[Why]
Some DPIA AUX replies have incorrect data length from original request.
This could lead to overwriting of destination buffer if reply length is
larger, which could cause invalid access to stack since many destination
buffers are declared as local variables.

[How]
Check for invalid length from DPIA AUX replies and trigger a retry if
reply length is not the same as original request. A DRM_WARN() dmesg log
is also produced.

Reviewed-by: Roman Li <Roman.Li@amd.com>
Acked-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Stylon Wang <stylon.wang@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org # 6.0.x

authored by

Stylon Wang and committed by
Alex Deucher
a5d313b4 be590ba8

+20 -6
+20
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 147 147 /* Number of bytes in PSP footer for firmware. */ 148 148 #define PSP_FOOTER_BYTES 0x100 149 149 150 + /* 151 + * DMUB Async to Sync Mechanism Status 152 + */ 153 + #define DMUB_ASYNC_TO_SYNC_ACCESS_FAIL 1 154 + #define DMUB_ASYNC_TO_SYNC_ACCESS_TIMEOUT 2 155 + #define DMUB_ASYNC_TO_SYNC_ACCESS_SUCCESS 3 156 + #define DMUB_ASYNC_TO_SYNC_ACCESS_INVALID 4 157 + 150 158 /** 151 159 * DOC: overview 152 160 * ··· 10184 10176 *operation_result = AUX_RET_ERROR_TIMEOUT; 10185 10177 } else if (status_type == DMUB_ASYNC_TO_SYNC_ACCESS_FAIL) { 10186 10178 *operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE; 10179 + } else if (status_type == DMUB_ASYNC_TO_SYNC_ACCESS_INVALID) { 10180 + *operation_result = AUX_RET_ERROR_INVALID_REPLY; 10187 10181 } else { 10188 10182 *operation_result = AUX_RET_ERROR_UNKNOWN; 10189 10183 } ··· 10233 10223 payload->reply[0] = adev->dm.dmub_notify->aux_reply.command; 10234 10224 if (!payload->write && adev->dm.dmub_notify->aux_reply.length && 10235 10225 payload->reply[0] == AUX_TRANSACTION_REPLY_AUX_ACK) { 10226 + 10227 + if (payload->length != adev->dm.dmub_notify->aux_reply.length) { 10228 + DRM_WARN("invalid read from DPIA AUX %x(%d) got length %d!\n", 10229 + payload->address, payload->length, 10230 + adev->dm.dmub_notify->aux_reply.length); 10231 + return amdgpu_dm_set_dmub_async_sync_status(is_cmd_aux, ctx, 10232 + DMUB_ASYNC_TO_SYNC_ACCESS_INVALID, 10233 + (uint32_t *)operation_result); 10234 + } 10235 + 10236 10236 memcpy(payload->data, adev->dm.dmub_notify->aux_reply.data, 10237 10237 adev->dm.dmub_notify->aux_reply.length); 10238 10238 }
-6
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
··· 51 51 #define AMDGPU_DMUB_NOTIFICATION_MAX 5 52 52 53 53 /* 54 - * DMUB Async to Sync Mechanism Status 55 - */ 56 - #define DMUB_ASYNC_TO_SYNC_ACCESS_FAIL 1 57 - #define DMUB_ASYNC_TO_SYNC_ACCESS_TIMEOUT 2 58 - #define DMUB_ASYNC_TO_SYNC_ACCESS_SUCCESS 3 59 - /* 60 54 #include "include/amdgpu_dal_power_if.h" 61 55 #include "amdgpu_dm_irq.h" 62 56 */