mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
accel/rocket: fix NULL dereference and integer overflow in rocket_job_push()
rocket_job_push() allocates a temporary array to hold all input and
output GEM object pointers:
bos = kvmalloc_array(job->in_bo_count + job->out_bo_count,
sizeof(void *), GFP_KERNEL);
memcpy(bos, job->in_bos, job->in_bo_count * sizeof(void *));
memcpy(&bos[job->in_bo_count], job->out_bos, ...);
Two bugs exist:
1. Missing NULL check: if kvmalloc_array() fails, bos is NULL and
the subsequent memcpy() dereferences it, causing a kernel NULL
pointer dereference.
2. Integer overflow: in_bo_count and out_bo_count are both u32, set
directly from userspace-supplied in_bo_handle_count and
out_bo_handle_count with no prior validation. Their sum is computed
in u32 arithmetic and can wrap to a smaller value, causing the
allocation count passed to kvmalloc_array() to be smaller than
intended. Subsequent uses still operate on the original counts when
copying and locking objects, which may lead to out-of-bounds accesses
on the temporary array.
Fix by using check_add_overflow() to detect count overflow before the
allocation, and adding a NULL check on the allocation result.
Fixes: 0810d5ad88 ("accel/rocket: Add job submission IOCTL")
Cc: stable@vger.kernel.org
Signed-off-by: Muhammad Bilal <meatuni001@gmail.com>
Link: https://lore.kernel.org/r/20260524155716.90955-1-meatuni001@gmail.com
Signed-off-by: Tomeu Vizoso <tomeu@tomeuvizoso.net>
This commit is contained in:
parent
70e6a33d68
commit
a85402bff2
|
|
@ -8,6 +8,7 @@
|
|||
#include <drm/drm_gem.h>
|
||||
#include <drm/rocket_accel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
|
@ -189,14 +190,19 @@ static int rocket_job_push(struct rocket_job *job)
|
|||
struct rocket_device *rdev = job->rdev;
|
||||
struct drm_gem_object **bos;
|
||||
struct ww_acquire_ctx acquire_ctx;
|
||||
u32 bo_count;
|
||||
int ret = 0;
|
||||
|
||||
bos = kvmalloc_array(job->in_bo_count + job->out_bo_count, sizeof(void *),
|
||||
GFP_KERNEL);
|
||||
if (check_add_overflow(job->in_bo_count, job->out_bo_count, &bo_count))
|
||||
return -EINVAL;
|
||||
|
||||
bos = kvmalloc_array(bo_count, sizeof(*bos), GFP_KERNEL);
|
||||
if (!bos)
|
||||
return -ENOMEM;
|
||||
memcpy(bos, job->in_bos, job->in_bo_count * sizeof(void *));
|
||||
memcpy(&bos[job->in_bo_count], job->out_bos, job->out_bo_count * sizeof(void *));
|
||||
|
||||
ret = drm_gem_lock_reservations(bos, job->in_bo_count + job->out_bo_count, &acquire_ctx);
|
||||
ret = drm_gem_lock_reservations(bos, bo_count, &acquire_ctx);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
|
@ -221,7 +227,7 @@ static int rocket_job_push(struct rocket_job *job)
|
|||
rocket_attach_object_fences(job->out_bos, job->out_bo_count, job->inference_done_fence);
|
||||
|
||||
err_unlock:
|
||||
drm_gem_unlock_reservations(bos, job->in_bo_count + job->out_bo_count, &acquire_ctx);
|
||||
drm_gem_unlock_reservations(bos, bo_count, &acquire_ctx);
|
||||
err:
|
||||
kvfree(bos);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user