On 3/12/26 09:18, Jesse.Zhang wrote: > When allocating memory for a BO list array, the multiplication > bo_number * info_size may overflow on 32-bit systems if userspace > supplies large values. This could lead to allocating a smaller buffer > than expected, followed by a memset or copy_from_user that writes > beyond the allocated memory, potentially causing memory corruption or > information disclosure. > > Add an overflow check using check_mul_overflow to detect such cases. > Also ensure the resulting allocation size does not exceed INT_MAX, > as the subsequent user copy operations may rely on this limit. > Return -EINVAL if either condition fails.
That is completely unnecessary, vmemdup_array_user() already does that check. > > A crash log illustrating the issue: > > [ 2943.053706] RIP: 0010:__kvmalloc_node_noprof+0x5be/0x8a0 > ... > [ 2943.053725] Call Trace: > [ 2943.053728] amdgpu_bo_create_list_entry_array+0x42/0x130 [amdgpu] > [ 2943.053947] amdgpu_bo_list_ioctl+0x51/0x300 [amdgpu] > [ 2943.054277] drm_ioctl+0x2cb/0x5a0 [drm] > [ 2943.054379] __x64_sys_ioctl+0x9e/0xf0 > > The overflow occurs in the allocation inside > amdgpu_bo_create_list_entry_array, leading to a crash in > vmemdup_user (via __kvmalloc_node_noprof). How and on which kernel can you reproduce that? Regards, Christian. > > Signed-off-by: Jesse.Zhang <[email protected]> > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 8 +++++++- > 1 file changed, 7 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c > index 87ec46c56a6e..efab39ba7f51 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c > @@ -29,6 +29,7 @@ > */ > > #include <linux/sort.h> > +#include <linux/overflow.h> > #include <linux/uaccess.h> > > #include "amdgpu.h" > @@ -187,6 +188,11 @@ int amdgpu_bo_create_list_entry_array(struct > drm_amdgpu_bo_list_in *in, > const uint32_t bo_info_size = in->bo_info_size; > const uint32_t bo_number = in->bo_number; > struct drm_amdgpu_bo_list_entry *info; > + size_t alloc_size; > + > + if (check_mul_overflow((size_t)bo_number, (size_t)info_size, > + &alloc_size) || alloc_size > INT_MAX) > + return -EINVAL; > > /* copy the handle array from userspace to a kernel buffer */ > if (likely(info_size == bo_info_size)) { > @@ -201,7 +207,7 @@ int amdgpu_bo_create_list_entry_array(struct > drm_amdgpu_bo_list_in *in, > if (!info) > return -ENOMEM; > > - memset(info, 0, bo_number * info_size); > + memset(info, 0, alloc_size); > for (i = 0; i < bo_number; ++i, uptr += bo_info_size) { > if (copy_from_user(&info[i], uptr, bytes)) { > kvfree(info);
