summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2012-05-31 08:15:28 +0300
committerSimone Willett <swillett@nvidia.com>2012-06-03 08:01:37 -0700
commitfdf40891983fc3fe1942877dcb07a4eab25f1796 (patch)
treef95b2e3f593cece2d8bd89c7cef8489f9fc42d6e
parent22049ebd104af134fce3cdf39c813fb993d869e9 (diff)
video: tegra: host: Restrict register access
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
-rw-r--r--drivers/video/tegra/host/bus_client.c32
-rw-r--r--drivers/video/tegra/host/bus_client.h4
-rw-r--r--drivers/video/tegra/host/dev.c11
3 files changed, 40 insertions, 7 deletions
diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c
index 962de32f359f..651a8dec738c 100644
--- a/drivers/video/tegra/host/bus_client.c
+++ b/drivers/video/tegra/host/bus_client.c
@@ -50,10 +50,28 @@
#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--) {
@@ -62,12 +80,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--) {
@@ -76,6 +102,8 @@ void nvhost_write_module_regs(struct nvhost_device *ndev,
}
wmb();
nvhost_module_idle(ndev);
+
+ return 0;
}
struct nvhost_channel_userctx {
diff --git a/drivers/video/tegra/host/bus_client.h b/drivers/video/tegra/host/bus_client.h
index adc3a704ea5d..e95ea0bc3401 100644
--- a/drivers/video/tegra/host/bus_client.h
+++ b/drivers/video/tegra/host/bus_client.h
@@ -24,10 +24,10 @@
#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);
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c
index ca73528fbeeb..67520a884d3e 100644
--- a/drivers/video/tegra/host/dev.c
+++ b/drivers/video/tegra/host/dev.c
@@ -205,6 +205,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))
@@ -216,17 +217,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;
}
}