]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blobdiff - drivers/media/platform/tegra/nvavp/nvavp_dev.c
media: tegra: nvavp: Fix reloc offset check
[sojka/nv-tegra/linux-3.10.git] / drivers / media / platform / tegra / nvavp / nvavp_dev.c
index be6c0e269a998221edd890d3fe279d4c33bc0f7f..4ca6d3069d3f32edaaf8bf72a7eab47a3a184fa9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * drivers/media/video/tegra/nvavp/nvavp_dev.c
  *
- * Copyright (c) 2011-2014, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2011-2016, NVIDIA CORPORATION.  All rights reserved.
  *
  * This file is licensed under the terms of the GNU General Public License
  * version 2. This program is licensed "as is" without any warranty of any
@@ -614,8 +614,8 @@ static void clock_disable_handler(struct work_struct *work)
                            clock_disable_work);
 
        channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL);
-       mutex_lock(&nvavp->open_lock);
        mutex_lock(&channel_info->pushbuffer_lock);
+       mutex_lock(&nvavp->open_lock);
        if (nvavp_check_idle(nvavp, NVAVP_VIDEO_CHANNEL) && nvavp->pending) {
                nvavp->pending = false;
                nvavp_clks_disable(nvavp);
@@ -1021,14 +1021,14 @@ static int nvavp_load_ucode(struct nvavp_info *nvavp)
                        }
                }
 
-               dev_info(&nvavp->nvhost_dev->dev,
+               dev_dbg(&nvavp->nvhost_dev->dev,
                        "read ucode firmware from '%s' (%d bytes)\n",
                        fw_ucode_file, nvavp_ucode_fw->size);
 
                ptr = (void *)nvavp_ucode_fw->data;
 
                if (strncmp((const char *)ptr, "NVAVPAPP", 8)) {
-                       dev_info(&nvavp->nvhost_dev->dev,
+                       dev_dbg(&nvavp->nvhost_dev->dev,
                                "ucode hdr string mismatch\n");
                        ret = -EINVAL;
                        goto err_req_ucode;
@@ -1094,14 +1094,14 @@ static int nvavp_load_os(struct nvavp_info *nvavp, char *fw_os_file)
                        goto err_req_fw;
                }
 
-               dev_info(&nvavp->nvhost_dev->dev,
+               dev_dbg(&nvavp->nvhost_dev->dev,
                        "read firmware from '%s' (%d bytes)\n",
                        fw_os_file, nvavp_os_fw->size);
 
                ptr = (void *)nvavp_os_fw->data;
 
                if (strncmp((const char *)ptr, "NVAVP-OS", 8)) {
-                       dev_info(&nvavp->nvhost_dev->dev,
+                       dev_dbg(&nvavp->nvhost_dev->dev,
                                "os hdr string mismatch\n");
                        ret = -EINVAL;
                        goto err_os_bin;
@@ -1130,7 +1130,7 @@ static int nvavp_load_os(struct nvavp_info *nvavp, char *fw_os_file)
                memcpy(os_info->os_bin, ptr, os_info->size);
                memset(os_info->data + os_info->size, 0, SZ_1M - os_info->size);
 
-               dev_info(&nvavp->nvhost_dev->dev,
+               dev_dbg(&nvavp->nvhost_dev->dev,
                        "entry=%08x control=%08x debug=%08x size=%d\n",
                        os_info->entry_offset, os_info->control_offset,
                        os_info->debug_offset, os_info->size);
@@ -1140,7 +1140,7 @@ static int nvavp_load_os(struct nvavp_info *nvavp, char *fw_os_file)
        memcpy(os_info->data, os_info->os_bin, os_info->size);
        os_info->reset_addr = os_info->phys + os_info->entry_offset;
 
-       dev_info(&nvavp->nvhost_dev->dev,
+       dev_dbg(&nvavp->nvhost_dev->dev,
                "AVP os at vaddr=%p paddr=%llx reset_addr=%llx\n",
                os_info->data, (u64)(os_info->phys), (u64)os_info->reset_addr);
        return 0;
@@ -1176,14 +1176,14 @@ static int nvavp_os_init(struct nvavp_info *nvavp)
 #if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU) /* Tegra2 with AVP MMU */
        /* paddr is phys address */
        /* vaddr is AVP_KERNEL_VIRT_BASE */
-       dev_info(&nvavp->nvhost_dev->dev,
+       dev_dbg(&nvavp->nvhost_dev->dev,
                "using AVP MMU to relocate AVP os\n");
        sprintf(fw_os_file, "nvavp_os.bin");
        nvavp->os_info.reset_addr = AVP_KERNEL_VIRT_BASE;
 #elif defined(CONFIG_TEGRA_AVP_KERNEL_ON_SMMU) /* Tegra3 with SMMU */
        /* paddr is any address behind SMMU */
        /* vaddr is TEGRA_SMMU_BASE */
-       dev_info(&nvavp->nvhost_dev->dev,
+       dev_dbg(&nvavp->nvhost_dev->dev,
                "using SMMU at %lx to load AVP kernel\n",
                (unsigned long)nvavp->os_info.phys);
        BUG_ON(nvavp->os_info.phys != 0xeff00000
@@ -1193,7 +1193,7 @@ static int nvavp_os_init(struct nvavp_info *nvavp)
                (unsigned long)nvavp->os_info.phys);
        nvavp->os_info.reset_addr = nvavp->os_info.phys;
 #else /* nvmem= carveout */
-       dev_info(&nvavp->nvhost_dev->dev,
+       dev_dbg(&nvavp->nvhost_dev->dev,
                "using nvmem= carveout at %llx to load AVP os\n",
                (u64)nvavp->os_info.phys);
        sprintf(fw_os_file, "nvavp_os_%08llx.bin", (u64)nvavp->os_info.phys);
@@ -1525,6 +1525,12 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
        if (!hdr.cmdbuf.mem)
                return 0;
 
+       if (hdr.num_relocs > NVAVP_MAX_RELOCATION_COUNT) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "invalid num_relocs %d\n", hdr.num_relocs);
+               return -EINVAL;
+       }
+
        if (copy_from_user(clientctx->relocs, (void __user *)hdr.relocs,
                        sizeof(struct nvavp_reloc) * hdr.num_relocs)) {
                return -EFAULT;
@@ -1537,6 +1543,14 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
                return PTR_ERR(cmdbuf_dmabuf);
        }
 
+       if ((hdr.cmdbuf.offset & 3)
+               || (hdr.cmdbuf.offset >= cmdbuf_dmabuf->size)) {
+               dev_err(&nvavp->nvhost_dev->dev,
+                       "invalid cmdbuf offset %d\n", hdr.cmdbuf.offset);
+               ret = -EINVAL;
+               goto err_dmabuf_attach;
+       }
+
        cmdbuf_attach = dma_buf_attach(cmdbuf_dmabuf, &nvavp->nvhost_dev->dev);
        if (IS_ERR(cmdbuf_attach)) {
                dev_err(&nvavp->nvhost_dev->dev, "cannot attach cmdbuf_dmabuf\n");
@@ -1574,6 +1588,18 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
                        goto err_reloc_info;
                }
 
+               if ((clientctx->relocs[i].cmdbuf_offset & 3)
+                       || (clientctx->relocs[i].cmdbuf_offset >=
+                               cmdbuf_dmabuf->size)
+                       || (clientctx->relocs[i].cmdbuf_offset >=
+                               (cmdbuf_dmabuf->size - hdr.cmdbuf.offset))) {
+                       dev_err(&nvavp->nvhost_dev->dev,
+                               "invalid reloc offset in cmdbuf %d\n",
+                               clientctx->relocs[i].cmdbuf_offset);
+                       ret = -EINVAL;
+                       goto err_reloc_info;
+               }
+
                reloc_addr = cmdbuf_data +
                             (clientctx->relocs[i].cmdbuf_offset >> 2);
 
@@ -1582,6 +1608,17 @@ static int nvavp_pushbuffer_submit_ioctl(struct file *filp, unsigned int cmd,
                        ret = PTR_ERR(target_dmabuf);
                        goto target_dmabuf_fail;
                }
+
+               if ((clientctx->relocs[i].target_offset & 3)
+                       || (clientctx->relocs[i].target_offset >=
+                               target_dmabuf->size)) {
+                       dev_err(&nvavp->nvhost_dev->dev,
+                               "invalid target offset in reloc %d\n",
+                               clientctx->relocs[i].target_offset);
+                       ret = -EINVAL;
+                       goto target_attach_fail;
+               }
+
                target_attach = dma_buf_attach(target_dmabuf,
                                               &nvavp->nvhost_dev->dev);
                if (IS_ERR(target_attach)) {
@@ -1950,8 +1987,11 @@ static int tegra_nvavp_release(struct nvavp_clientctx *clientctx,
 
        if (nvavp->refcount > 0)
                nvavp->refcount--;
-       if (!nvavp->refcount)
+       if (!nvavp->refcount) {
+               mutex_unlock(&nvavp->open_lock);
                nvavp_uninit(nvavp);
+               mutex_lock(&nvavp->open_lock);
+       }
 
        if (IS_VIDEO_CHANNEL_ID(channel_id))
                nvavp->video_refcnt--;