msm: kgsl: check for number of commands in kgsl_ioctl_gpu_aux_command

kgsl_ioctl_gpu_aux_command creates a separate drawobj for each command
in numcmds sent from userspace. All drawbojs created will have same
timestamp. We can not queue more than one drawobj with same timestamp.
Each new drawobj must have timestamp greater than previously queued
drawobjs. This results in failure of kgsl_ioctl_gpu_aux_command.
Add proper check and return early when numcmds is invalid.

Change-Id: I06413c16b0a21abcffb121b2e332752eb71e6be0
Signed-off-by: Pranav Patel <pranavp@codeaurora.org>
Signed-off-by: Akhil P Oommen <akhilpo@codeaurora.org>
This commit is contained in:
Pranav Patel 2021-04-29 19:45:24 +05:30 • committed by Gerrit - the friendly Code Review server
commit ade36fe563

View file

@ -2025,34 +2025,27 @@ long kgsl_ioctl_gpu_aux_command(struct kgsl_device_private *dev_priv,
u32 queued, count;
int i, index = 0;
long ret;
struct kgsl_gpu_aux_command_generic generic;
/* Aux commands don't make sense without commands */
if (!param->numcmds)
/* We support only one aux command */
if (param->numcmds != 1)
return -EINVAL;
if (!(param->flags &
(KGSL_GPU_AUX_COMMAND_TIMELINE)))
return -EINVAL;
/*
* Make sure we don't overflow count. Couple of drawobjs are reserved:
* One drawobj for timestamp sync and another for aux command sync.
*/
if (param->numcmds > (UINT_MAX - 2))
return -EINVAL;
context = kgsl_context_get_owner(dev_priv, param->context_id);
if (!context)
return -EINVAL;
/*
* We have one drawobj for the timestamp sync plus one for all of the
* commands
* param->numcmds is always one and we have one additional drawobj
* for the timestamp sync if KGSL_GPU_AUX_COMMAND_SYNC flag is passed.
* On top of that we make an implicit sync object for the last queued
* timestamp on this context.
*/
count = param->numcmds + 1;
if (param->flags & KGSL_GPU_AUX_COMMAND_SYNC)
count++;
count = (param->flags & KGSL_GPU_AUX_COMMAND_SYNC) ? 3 : 2;
drawobjs = kvcalloc(count, sizeof(*drawobjs), GFP_KERNEL);
@ -2100,39 +2093,34 @@ long kgsl_ioctl_gpu_aux_command(struct kgsl_device_private *dev_priv,
cmdlist = u64_to_user_ptr(param->cmdlist);
/* Create a draw object for each command */
for (i = 0; i < param->numcmds; i++) {
struct kgsl_gpu_aux_command_generic generic;
/* Create a draw object for KGSL_GPU_AUX_COMMAND_TIMELINE */
if (copy_struct_from_user(&generic, sizeof(generic),
cmdlist, param->cmdsize)) {
ret = -EFAULT;
goto err;
}
if (copy_struct_from_user(&generic, sizeof(generic),
cmdlist, param->cmdsize)) {
ret = -EFAULT;
if (generic.type == KGSL_GPU_AUX_COMMAND_TIMELINE) {
struct kgsl_drawobj_timeline *timelineobj;
timelineobj = kgsl_drawobj_timeline_create(device,
context);
if (IS_ERR(timelineobj)) {
ret = PTR_ERR(timelineobj);
goto err;
}
if (generic.type == KGSL_GPU_AUX_COMMAND_TIMELINE) {
struct kgsl_drawobj_timeline *timelineobj;
drawobjs[index++] = DRAWOBJ(timelineobj);
timelineobj = kgsl_drawobj_timeline_create(device,
context);
if (IS_ERR(timelineobj)) {
ret = PTR_ERR(timelineobj);
goto err;
}
drawobjs[index++] = DRAWOBJ(timelineobj);
ret = kgsl_drawobj_add_timeline(dev_priv, timelineobj,
u64_to_user_ptr(generic.priv), generic.size);
if (ret)
goto err;
} else {
ret = -EINVAL;
ret = kgsl_drawobj_add_timeline(dev_priv, timelineobj,
u64_to_user_ptr(generic.priv), generic.size);
if (ret)
goto err;
}
cmdlist += param->cmdsize;
} else {
ret = -EINVAL;
goto err;
}
ret = device->ftbl->queue_cmds(dev_priv, context,