aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLuca Barbieri <luca@luca-barbieri.com>2010-01-10 14:10:53 -0500
committerBen Skeggs <bskeggs@redhat.com>2010-01-14 18:56:50 -0500
commit12f735b79f0ad63964dedabed3eee8a581bb66a5 (patch)
tree22a774a050cbd0967d0b89788375271f226ba252 /drivers
parentac8fb975e8c88d312a376b035494be17548d01c6 (diff)
drm/nouveau: check pushbuffer bounds in ioctl
Currently there is no check that the pushbuffer request bounds are inside the TTM BO. This allows to instruct the kernel to do relocations on user-selected addresses, since the relocation bounds checking relies on the request bounds. This can oops the kernel accidentally and is easily exploitable. This patch adds bound checking and alignment checking for ->offset and ->nr_dwords. It also makes some variables unsigned, which should have no effect, but prevents possible bounds checking problems. Signed-off-by: Luca Barbieri <luca@luca-barbieri.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 2009db2426c3..504833044080 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -466,13 +466,14 @@ u_memcpya(uint64_t user, unsigned nmemb, unsigned size)
466static int 466static int
467nouveau_gem_pushbuf_reloc_apply(struct nouveau_channel *chan, int nr_bo, 467nouveau_gem_pushbuf_reloc_apply(struct nouveau_channel *chan, int nr_bo,
468 struct drm_nouveau_gem_pushbuf_bo *bo, 468 struct drm_nouveau_gem_pushbuf_bo *bo,
469 int nr_relocs, uint64_t ptr_relocs, 469 unsigned nr_relocs, uint64_t ptr_relocs,
470 int nr_dwords, int first_dword, 470 unsigned nr_dwords, unsigned first_dword,
471 uint32_t *pushbuf, bool is_iomem) 471 uint32_t *pushbuf, bool is_iomem)
472{ 472{
473 struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL; 473 struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL;
474 struct drm_device *dev = chan->dev; 474 struct drm_device *dev = chan->dev;
475 int ret = 0, i; 475 int ret = 0;
476 unsigned i;
476 477
477 reloc = u_memcpya(ptr_relocs, nr_relocs, sizeof(*reloc)); 478 reloc = u_memcpya(ptr_relocs, nr_relocs, sizeof(*reloc));
478 if (IS_ERR(reloc)) 479 if (IS_ERR(reloc))
@@ -667,6 +668,18 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
667 } 668 }
668 pbbo = nouveau_gem_object(gem); 669 pbbo = nouveau_gem_object(gem);
669 670
671 if ((req->offset & 3) || req->nr_dwords < 2 ||
672 (unsigned long)req->offset > (unsigned long)pbbo->bo.mem.size ||
673 (unsigned long)req->nr_dwords >
674 ((unsigned long)(pbbo->bo.mem.size - req->offset ) >> 2)) {
675 NV_ERROR(dev, "pb call misaligned or out of bounds: "
676 "%d + %d * 4 > %ld\n",
677 req->offset, req->nr_dwords, pbbo->bo.mem.size);
678 ret = -EINVAL;
679 drm_gem_object_unreference(gem);
680 goto out;
681 }
682
670 ret = ttm_bo_reserve(&pbbo->bo, false, false, true, 683 ret = ttm_bo_reserve(&pbbo->bo, false, false, true,
671 chan->fence.sequence); 684 chan->fence.sequence);
672 if (ret) { 685 if (ret) {