video: tegra: host: Restrict register access
Terje Bergstrom [Thu, 31 May 2012 05:15:28 +0000 (08:15 +0300)]
Register access (read/write) to modules MPE, ISP and VI lack sanity
check for the register number. Add checks to ensure only aperture is
accessed. Also make sure that the check accounts for wrapping of
values of offset and count.

Also fixes the register offset for reads which are done in multiple
blocks.

Bug 992938

Change-Id: I35f30cbd1dda31956286e48c5995b24fd262d1ae
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/105585
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit

Rebase-Id: R461550a651b89d773429c6c42d17850fff755be0

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

index d9c2d3c..a6a770e 100644 (file)
 #include "nvhost_job.h"
 #include "nvhost_hwctx.h"
 
-void nvhost_read_module_regs(struct nvhost_device *ndev,
+static int validate_reg(struct nvhost_device *ndev, u32 offset, int count)
+{
+       struct resource *r = nvhost_get_resource(ndev, IORESOURCE_MEM, 0);
+       int err = 0;
+
+       if (offset + 4 * count > resource_size(r)
+                       || (offset + 4 * count < offset))
+               err = -EPERM;
+
+       return err;
+}
+
+int nvhost_read_module_regs(struct nvhost_device *ndev,
                        u32 offset, int count, u32 *values)
 {
        void __iomem *p = ndev->aperture + offset;
+       int err;
+
+       /* verify offset */
+       err = validate_reg(ndev, offset, count);
+       if (err)
+               return err;
 
        nvhost_module_busy(ndev);
        while (count--) {
@@ -63,12 +81,20 @@ void nvhost_read_module_regs(struct nvhost_device *ndev,
        }
        rmb();
        nvhost_module_idle(ndev);
+
+       return 0;
 }
 
-void nvhost_write_module_regs(struct nvhost_device *ndev,
+int nvhost_write_module_regs(struct nvhost_device *ndev,
                        u32 offset, int count, const u32 *values)
 {
        void __iomem *p = ndev->aperture + offset;
+       int err;
+
+       /* verify offset */
+       err = validate_reg(ndev, offset, count);
+       if (err)
+               return err;
 
        nvhost_module_busy(ndev);
        while (count--) {
@@ -77,6 +103,8 @@ void nvhost_write_module_regs(struct nvhost_device *ndev,
        }
        wmb();
        nvhost_module_idle(ndev);
+
+       return 0;
 }
 
 struct nvhost_channel_userctx {
index adc3a70..e95ea0b 100644 (file)
 #include <linux/types.h>
 struct nvhost_device;
 
-void nvhost_read_module_regs(struct nvhost_device *ndev,
+int nvhost_read_module_regs(struct nvhost_device *ndev,
                        u32 offset, int count, u32 *values);
 
-void nvhost_write_module_regs(struct nvhost_device *ndev,
+int nvhost_write_module_regs(struct nvhost_device *ndev,
                        u32 offset, int count, const u32 *values);
 
 int nvhost_client_user_init(struct nvhost_device *dev);
index 831662d..80286be 100644 (file)
@@ -206,6 +206,7 @@ static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx,
                return -EINVAL;
 
        while (num_offsets--) {
+               int err;
                int remaining = args->block_size >> 2;
                u32 offs;
                if (get_user(offs, offsets))
@@ -217,17 +218,21 @@ static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx,
                                if (copy_from_user(vals, values,
                                                        batch*sizeof(u32)))
                                        return -EFAULT;
-                               nvhost_write_module_regs(ndev,
+                               err = nvhost_write_module_regs(ndev,
                                                offs, batch, vals);
+                               if (err)
+                                       return err;
                        } else {
-                               nvhost_read_module_regs(ndev,
+                               err = nvhost_read_module_regs(ndev,
                                                offs, batch, vals);
+                               if (err)
+                                       return err;
                                if (copy_to_user(values, vals,
                                                        batch*sizeof(u32)))
                                        return -EFAULT;
                        }
                        remaining -= batch;
-                       offs += batch;
+                       offs += batch*sizeof(u32);
                        values += batch;
                }
        }