mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
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>
This commit is contained in:
parent
ac8fb975e8
commit
12f735b79f
1 changed files with 16 additions and 3 deletions
|
@ -466,13 +466,14 @@ u_memcpya(uint64_t user, unsigned nmemb, unsigned size)
|
|||
static int
|
||||
nouveau_gem_pushbuf_reloc_apply(struct nouveau_channel *chan, int nr_bo,
|
||||
struct drm_nouveau_gem_pushbuf_bo *bo,
|
||||
int nr_relocs, uint64_t ptr_relocs,
|
||||
int nr_dwords, int first_dword,
|
||||
unsigned nr_relocs, uint64_t ptr_relocs,
|
||||
unsigned nr_dwords, unsigned first_dword,
|
||||
uint32_t *pushbuf, bool is_iomem)
|
||||
{
|
||||
struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL;
|
||||
struct drm_device *dev = chan->dev;
|
||||
int ret = 0, i;
|
||||
int ret = 0;
|
||||
unsigned i;
|
||||
|
||||
reloc = u_memcpya(ptr_relocs, nr_relocs, sizeof(*reloc));
|
||||
if (IS_ERR(reloc))
|
||||
|
@ -667,6 +668,18 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
|
|||
}
|
||||
pbbo = nouveau_gem_object(gem);
|
||||
|
||||
if ((req->offset & 3) || req->nr_dwords < 2 ||
|
||||
(unsigned long)req->offset > (unsigned long)pbbo->bo.mem.size ||
|
||||
(unsigned long)req->nr_dwords >
|
||||
((unsigned long)(pbbo->bo.mem.size - req->offset ) >> 2)) {
|
||||
NV_ERROR(dev, "pb call misaligned or out of bounds: "
|
||||
"%d + %d * 4 > %ld\n",
|
||||
req->offset, req->nr_dwords, pbbo->bo.mem.size);
|
||||
ret = -EINVAL;
|
||||
drm_gem_object_unreference(gem);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ttm_bo_reserve(&pbbo->bo, false, false, true,
|
||||
chan->fence.sequence);
|
||||
if (ret) {
|
||||
|
|
Loading…
Reference in a new issue