video: tegra: host: Add submit checks
Arto Merilainen [Wed, 7 Jan 2015 12:29:05 +0000 (14:29 +0200)]
Currently nvhost performs minimal checking for submits it passes
to hardware: The kernel does not check if job syncpoints are allocated
and the gather classes are not verified currently.

This patch adds checks for syncpoint ids and gather classes.

Bug 1525996

Change-Id: I79b9e676a3c131cea301be8e15f5bbdfc53483ae
Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-on: http://git-master/r/670253
GVS: Gerrit_Virtual_Submit

drivers/video/tegra/host/bus_client.c

index 0100fc5..1069842 100644 (file)
@@ -436,8 +436,13 @@ static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
                                (uintptr_t)args->syncpt_incrs;
        u32 __user *fences = (u32 __user *)(uintptr_t)args->fences;
        u32 __user *class_ids = (u32 __user *)(uintptr_t)args->class_ids;
+       struct nvhost_device_data *pdata = platform_get_drvdata(ctx->pdev);
 
        struct nvhost_master *host = nvhost_get_host(ctx->pdev);
+       const u32 *syncpt_array =
+               (nvhost_get_syncpt_policy() == SYNCPT_PER_CHANNEL_INSTANCE) ?
+               ctx->syncpts :
+               ctx->ch->syncpts;
        u32 *local_class_ids = NULL;
        int err, i;
 
@@ -499,6 +504,14 @@ static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
                if (err)
                        cmdbuf_ext.pre_fence = -1;
 
+               /* verify that the given class id is valid for this engine */
+               if (class_id &&
+                   class_id != pdata->class &&
+                   class_id != NV_HOST1X_CLASS_ID) {
+                       err = -EINVAL;
+                       goto fail;
+               }
+
                nvhost_job_add_gather(job, cmdbuf.mem, cmdbuf.words,
                                      cmdbuf.offset, class_id,
                                      cmdbuf_ext.pre_fence);
@@ -531,14 +544,30 @@ static int nvhost_ioctl_channel_submit(struct nvhost_channel_userctx *ctx,
 
        for (i = 0; i < num_syncpt_incrs; ++i) {
                struct nvhost_syncpt_incr sp;
+               bool found = false;
+               int j;
 
                /* Copy */
                err = copy_from_user(&sp, syncpt_incrs + i, sizeof(sp));
                if (err)
                        goto fail;
 
-               /* Validate */
-               if (sp.syncpt_id >= host->info.nb_pts) {
+               /* Validate the trivial case */
+               if (sp.syncpt_id == 0) {
+                       err = -EINVAL;
+                       goto fail;
+               }
+
+               /* ..and then ensure that the syncpoints have been reserved
+                * for this client */
+               for (j = 0; j < NVHOST_MODULE_MAX_SYNCPTS; j++) {
+                       if (syncpt_array[j] == sp.syncpt_id) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found) {
                        err = -EINVAL;
                        goto fail;
                }