]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amdgpu: Fix TOCTOU on UniRAS command response size
authorChenglei Xie <Chenglei.Xie@amd.com>
Mon, 11 May 2026 18:13:45 +0000 (14:13 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 27 May 2026 14:48:30 +0000 (10:48 -0400)
The guest maps the PF response in shared VRAM (struct ras_cmd_ctx in the
command buffer). After amdgpu_virt_send_remote_ras_cmd() returns, the code
validated rcmd->output_size against the caller buffer, then copied
rcmd->output_buff_raw using rcmd->output_size again. A malicious PF could
change output_size between those reads so the memcpy length exceeds the
caller’s output_size and overflows guest stack or heap buffers.

Snapshot output_size with READ_ONCE() once, assign cmd->output_size from
that value, and use the same snapshot for the bounds check and memcpy.
Also read cmd_res once with READ_ONCE() so the error branch and
cmd->cmd_res assignment do not observe different values from shared memory.

Signed-off-by: Chenglei Xie <Chenglei.Xie@amd.com>
Reviewed-by: YiPeng Chai <YiPeng.Chai@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c

index c2761f3d06a0abcdb6f1cf3e728b8a893f36f33a..571b81cb04750d1a4aeab61835f666e90042f421 100644 (file)
@@ -108,15 +108,19 @@ static int amdgpu_virt_ras_remote_ioctl_cmd(struct ras_core_context *ras_core,
        ret = amdgpu_virt_send_remote_ras_cmd(ras_core->dev,
                                shared_mem.gpa, mem_len);
        if (!ret) {
-               if (rcmd->cmd_res) {
-                       ret = rcmd->cmd_res;
+               uint32_t cmd_res = READ_ONCE(rcmd->cmd_res);
+               uint32_t osz;
+
+               if (cmd_res) {
+                       ret = cmd_res;
                        goto out;
                }
 
-               cmd->cmd_res = rcmd->cmd_res;
-               cmd->output_size = rcmd->output_size;
-               if (rcmd->output_size && (rcmd->output_size <= output_size) && output_data)
-                       memcpy(output_data, rcmd->output_buff_raw, rcmd->output_size);
+               osz = READ_ONCE(rcmd->output_size);
+               cmd->cmd_res = cmd_res;
+               cmd->output_size = osz;
+               if (osz && osz <= output_size && output_data)
+                       memcpy(output_data, rcmd->output_buff_raw, osz);
        }
 
 out: