video: tegra: host: Remove error case panics
Terje Bergstrom [Fri, 1 Jun 2012 08:09:36 +0000 (11:09 +0300)]
Remove BUG_ON()s in error cases:
* If IOCTL size is too large, return error instead
* If sync point id is out of range, return error. Prevents panics in
  sanity checks nvhost_cdma.

Bug 993642

Change-Id: I3cfa7a23dc557c811e20b726885f82666437de7f
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/105866
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>

drivers/video/tegra/host/bus_client.c
drivers/video/tegra/host/dev.c
drivers/video/tegra/host/nvhost_acm.c
drivers/video/tegra/host/nvhost_syncpt.h

index 651a8de..6bfce9a 100644 (file)
@@ -179,14 +179,17 @@ fail:
 
 static int set_submit(struct nvhost_channel_userctx *ctx)
 {
-       struct device *device = &ctx->ch->dev->dev;
+       struct nvhost_device *ndev = ctx->ch->dev;
+       struct nvhost_master *host = nvhost_get_host(ndev);
 
        /* submit should have at least 1 cmdbuf */
-       if (!ctx->hdr.num_cmdbufs)
+       if (!ctx->hdr.num_cmdbufs ||
+                       !nvhost_syncpt_is_valid(&host->syncpt,
+                               ctx->hdr.syncpt_id))
                return -EIO;
 
        if (!ctx->nvmap) {
-               dev_err(device, "no nvmap context set\n");
+               dev_err(&ndev->dev, "no nvmap context set\n");
                return -EFAULT;
        }
 
@@ -402,11 +405,10 @@ static long nvhost_channelctl(struct file *filp,
 
        if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) ||
                (_IOC_NR(cmd) == 0) ||
-               (_IOC_NR(cmd) > NVHOST_IOCTL_CHANNEL_LAST))
+               (_IOC_NR(cmd) > NVHOST_IOCTL_CHANNEL_LAST) ||
+               (_IOC_SIZE(cmd) > NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE))
                return -EFAULT;
 
-       BUG_ON(_IOC_SIZE(cmd) > NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE);
-
        if (_IOC_DIR(cmd) & _IOC_WRITE) {
                if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
                        return -EFAULT;
index 67520a8..2c05fbf 100644 (file)
@@ -255,11 +255,10 @@ static long nvhost_ctrlctl(struct file *filp,
 
        if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) ||
                (_IOC_NR(cmd) == 0) ||
-               (_IOC_NR(cmd) > NVHOST_IOCTL_CTRL_LAST))
+               (_IOC_NR(cmd) > NVHOST_IOCTL_CTRL_LAST) ||
+               (_IOC_SIZE(cmd) > NVHOST_IOCTL_CTRL_MAX_ARG_SIZE))
                return -EFAULT;
 
-       BUG_ON(_IOC_SIZE(cmd) > NVHOST_IOCTL_CTRL_MAX_ARG_SIZE);
-
        if (_IOC_DIR(cmd) & _IOC_WRITE) {
                if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
                        return -EFAULT;
index 6d96bd0..dfd8432 100644 (file)
@@ -134,7 +134,11 @@ static void to_state_running_locked(struct nvhost_device *dev)
 
                for (i = 0; i < dev->num_clks; i++) {
                        int err = clk_enable(dev->clk[i]);
-                       BUG_ON(err);
+                       if (err) {
+                               dev_err(&dev->dev, "Cannot turn on clock %s",
+                                       dev->clocks[i].name);
+                               return;
+                       }
                }
 
                if (prev_state == NVHOST_POWER_STATE_POWERGATED
@@ -369,7 +373,11 @@ int nvhost_module_init(struct nvhost_device *dev)
 
                snprintf(devname, MAX_DEVID_LENGTH, "tegra_%s", dev->name);
                c = clk_get_sys(devname, dev->clocks[i].name);
-               BUG_ON(IS_ERR_OR_NULL(c));
+               if (IS_ERR_OR_NULL(c)) {
+                       dev_err(&dev->dev, "Cannot get clock %s\n",
+                                       dev->clocks[i].name);
+                       continue;
+               }
 
                rate = clk_round_rate(c, rate);
                clk_enable(c);
index b58921b..fcc9fce 100644 (file)
@@ -140,6 +140,11 @@ int nvhost_syncpt_patch_wait(struct nvhost_syncpt *sp, void *patch_addr);
 
 void nvhost_syncpt_debug(struct nvhost_syncpt *sp);
 
+static inline int nvhost_syncpt_is_valid(struct nvhost_syncpt *sp, u32 id)
+{
+       return id != NVSYNCPT_INVALID && id < sp->nb_pts;
+}
+
 int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx);
 
 void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx);