Skip to content

Commit

Permalink
drm/nouveau: Fix null deref in nouveau_fence_emit due to deleted fence
Browse files Browse the repository at this point in the history
Currently Nouveau will unvalidate all buffers if it is forced to wait on
one, and then start revalidating from the beginning.  While doing so, it
destroys the operation fence, causing nouveau_fence_emit to crash.

This patch fixes this bug by taking the fence object out of validate_op
and creating it just before emit.  The fence pointer is initialized to 0
and unref'ed unconditionally.

In addition to fixing the bug, this prevents its reintroduction and
simplifies the code.

Signed-off-by: Luca Barbieri <luca@luca-barbieri.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
  • Loading branch information
Luca Barbieri authored and Dave Airlie committed Jan 11, 2010
1 parent dc8d76c commit d6126c5
Showing 1 changed file with 13 additions and 20 deletions.
33 changes: 13 additions & 20 deletions drivers/gpu/drm/nouveau/nouveau_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains,
}

struct validate_op {
struct nouveau_fence *fence;
struct list_head vram_list;
struct list_head gart_list;
struct list_head both_list;
Expand Down Expand Up @@ -252,17 +251,11 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
}

static void
validate_fini(struct validate_op *op, bool success)
validate_fini(struct validate_op *op, struct nouveau_fence* fence)
{
struct nouveau_fence *fence = op->fence;

if (unlikely(!success))
op->fence = NULL;

validate_fini_list(&op->vram_list, op->fence);
validate_fini_list(&op->gart_list, op->fence);
validate_fini_list(&op->both_list, op->fence);
nouveau_fence_unref((void *)&fence);
validate_fini_list(&op->vram_list, fence);
validate_fini_list(&op->gart_list, fence);
validate_fini_list(&op->both_list, fence);
}

static int
Expand Down Expand Up @@ -420,10 +413,6 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
INIT_LIST_HEAD(&op->gart_list);
INIT_LIST_HEAD(&op->both_list);

ret = nouveau_fence_new(chan, &op->fence, false);
if (ret)
return ret;

if (nr_buffers == 0)
return 0;

Expand Down Expand Up @@ -541,6 +530,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
struct drm_nouveau_gem_pushbuf_bo *bo = NULL;
struct nouveau_channel *chan;
struct validate_op op;
struct nouveau_fence* fence = 0;
uint32_t *pushbuf = NULL;
int ret = 0, do_reloc = 0, i;

Expand Down Expand Up @@ -597,15 +587,15 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,

OUT_RINGp(chan, pushbuf, req->nr_dwords);

ret = nouveau_fence_emit(op.fence);
ret = nouveau_fence_new(chan, &fence, true);
if (ret) {
NV_ERROR(dev, "error fencing pushbuf: %d\n", ret);
WIND_RING(chan);
goto out;
}

if (nouveau_gem_pushbuf_sync(chan)) {
ret = nouveau_fence_wait(op.fence, NULL, false, false);
ret = nouveau_fence_wait(fence, NULL, false, false);
if (ret) {
for (i = 0; i < req->nr_dwords; i++)
NV_ERROR(dev, "0x%08x\n", pushbuf[i]);
Expand All @@ -614,7 +604,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
}

out:
validate_fini(&op, ret == 0);
validate_fini(&op, fence);
nouveau_fence_unref((void**)&fence);
mutex_unlock(&dev->struct_mutex);
kfree(pushbuf);
kfree(bo);
Expand All @@ -634,6 +625,7 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
struct drm_gem_object *gem;
struct nouveau_bo *pbbo;
struct validate_op op;
struct nouveau_fence* fence = 0;
int i, ret = 0, do_reloc = 0;

NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
Expand Down Expand Up @@ -772,15 +764,16 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
OUT_RING(chan, 0);
}

ret = nouveau_fence_emit(op.fence);
ret = nouveau_fence_new(chan, &fence, true);
if (ret) {
NV_ERROR(dev, "error fencing pushbuf: %d\n", ret);
WIND_RING(chan);
goto out;
}

out:
validate_fini(&op, ret == 0);
validate_fini(&op, fence);
nouveau_fence_unref((void**)&fence);
mutex_unlock(&dev->struct_mutex);
kfree(bo);

Expand Down

0 comments on commit d6126c5

Please sign in to comment.