From: Harry Wentland <[email protected]>

[Why]
amdgpu_dm_process_dmub_aux_transfer_sync() copies p_notify->aux_reply.length
bytes into payload->data without clamping. payload->data is typically a 16-byte
DPCD scratch buffer, while aux_reply.length is echoed from the sink via the DMUB
ring. While this is clamped by DMUB it's prudent to ensure we validate
this in the driver as well.

[How]
Clamp the copy to sizeof(aux_reply.data), the scratch buffer the reply was read
into, and use that for both the memcpy and the return value. For regular
transfers additionally clamp to payload->length to cover callers whose
destination buffer is smaller than 16 bytes. The write-status-update retry path
(dce_aux_transfer_with_retries) deliberately zeroes payload->length while still
expecting the partial-write status byte, so that bound is skipped in that case
to avoid dropping the reply. Also guard against a NULL payload->data.

Fixes: 81927e2808be ("drm/amd/display: Support for DMUB AUX")
Cc: [email protected]
Assisted-by: Copilot:claude-opus-4.8
Reviewed-by: Alex Hung <[email protected]>
Signed-off-by: Harry Wentland <[email protected]>
Signed-off-by: George Zhang <[email protected]>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_dmub.c    | 24 +++++++++++++++----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
index 97cb2a09153d..1f9830ce2ea6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c
@@ -798,12 +798,26 @@ int amdgpu_dm_process_dmub_aux_transfer_sync(
                payload->reply[0] = (adev->dm.dmub_notify->aux_reply.command >> 
4) & 0xF;
 
        /*write req may receive a byte indicating partially written number as 
well*/
-       if (p_notify->aux_reply.length)
-               memcpy(payload->data, p_notify->aux_reply.data,
-                               p_notify->aux_reply.length);
+       if (p_notify->aux_reply.length && payload->data) {
+               /* Bound the reply to the scratch buffer it was read into. */
+               ret = min((uint32_t)p_notify->aux_reply.length,
+                         (uint32_t)sizeof(p_notify->aux_reply.data));
+
+               /*
+                * During a write-status-update retry the caller zeroes
+                * payload->length while still expecting the partial-write
+                * status byte in payload->data (see 
dce_aux_transfer_with_retries),
+                * so only clamp to payload->length for regular transfers.
+                */
+               if (!payload->write_status_update)
+                       ret = min(ret, payload->length);
+
+               memcpy(payload->data, p_notify->aux_reply.data, ret);
+       } else {
+               /* success */
+               ret = p_notify->aux_reply.length;
+       }
 
-       /* success */
-       ret = p_notify->aux_reply.length;
        *operation_result = p_notify->result;
 out:
        reinit_completion(&adev->dm.dmub_aux_transfer_done);
-- 
2.53.0

Reply via email to