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

drm/amdgpu: Fix CPER ring debugfs read buffer overflow risk

The CPER ring debugfs read code always writes a 12-byte header when the
file is read for the first time (*offset == 0):

copy_to_user(buf, ring_header, 12);

But the code never checks whether the user buffer (@size) is at least
12 bytes long. After writing the 12-byte header, the code then gives the
full original @size to the CPER payload handler:

record_req->buf_size = size;

This means the function can write:

12 bytes (header) + payload bytes (up to @size)

into a buffer that is only @size bytes big. In other words, the kernel
may write more data than the user asked for. This can overflow the user
buffer.

The fix is:

- If the user buffer is smaller than 12 bytes on the first read,
return -EINVAL instead of copying the header.
- After writing the 12-byte header, subtract 12 from @size and pass
the reduced size to record_req->buf_size. This ensures the CPER
payload only uses the remaining free space in the buffer.

Reads after the first one (*offset != 0) do not write the header, so
their behavior stays exactly the same. The only user-visible change is
that tiny buffers now fail safely instead of risking an overflow.

Fixes:
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c:523
amdgpu_ras_cper_debugfs_read()
warn: userbuf overflow? is 'ring_header_size' <= 'size'

Fixes: 527e3d40339b ("drm/amd/ras: Add CPER ring read for uniras")
Reported by: Dan Carpenter <dan.carpenter@linaro.org>
Cc: Xiang Liu <xiang.liu@amd.com>
Cc: Tao Zhou <tao.zhou1@amd.com>
Cc: Yang Wang <kevinyang.wang@amd.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
Reviewed-by: Tao Zhou <tao.zhou1@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Srinivasan Shanmugam and committed by
Alex Deucher
93c19634 f3854e04

+5
+5
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
··· 520 520 return -ENOMEM; 521 521 522 522 if (!(*offset)) { 523 + /* Need at least 12 bytes for the header on the first read */ 524 + if (size < ring_header_size) 525 + return -EINVAL; 526 + 523 527 if (copy_to_user(buf, ring_header, ring_header_size)) 524 528 return -EFAULT; 525 529 buf += ring_header_size; 530 + size -= ring_header_size; 526 531 } 527 532 528 533 r = amdgpu_ras_mgr_handle_ras_cmd(ring->adev,