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);

Reply via email to