Skip to content

Commit

Permalink
drm/qxl: qxl_release use after free
Browse files Browse the repository at this point in the history
qxl_release should not be accesses after qxl_push_*_ring_release() calls:
userspace driver can process submitted command quickly, move qxl_release
into release_ring, generate interrupt and trigger garbage collector.

It can lead to crashes in qxl driver or trigger memory corruption
in some kmalloc-192 slab object

Gerd Hoffmann proposes to swap the qxl_release_fence_buffer_objects() +
qxl_push_{cursor,command}_ring_release() calls to close that race window.

cc: stable@vger.kernel.org
Fixes: f64122c ("drm: add new QXL driver. (v1.4)")
Signed-off-by: Vasily Averin <vvs@virtuozzo.com>
Link: http://patchwork.freedesktop.org/patch/msgid/fa17b338-66ae-f299-68fe-8d32419d9071@virtuozzo.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
  • Loading branch information
Vasily Averin authored and Gerd Hoffmann committed Apr 29, 2020
1 parent 5b5703d commit 933db73
Show file tree
Hide file tree
Showing 4 changed files with 7 additions and 11 deletions.
5 changes: 2 additions & 3 deletions drivers/gpu/drm/qxl/qxl_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,8 +500,8 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev,
/* no need to add a release to the fence for this surface bo,
since it is only released when we ask to destroy the surface
and it would never signal otherwise */
qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
qxl_release_fence_buffer_objects(release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);

surf->hw_surf_alloc = true;
spin_lock(&qdev->surf_id_idr_lock);
Expand Down Expand Up @@ -543,9 +543,8 @@ int qxl_hw_surface_dealloc(struct qxl_device *qdev,
cmd->surface_id = id;
qxl_release_unmap(qdev, release, &cmd->release_info);

qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);

qxl_release_fence_buffer_objects(release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);

return 0;
}
Expand Down
6 changes: 3 additions & 3 deletions drivers/gpu/drm/qxl/qxl_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,8 +510,8 @@ static int qxl_primary_apply_cursor(struct drm_plane *plane)
cmd->u.set.visible = 1;
qxl_release_unmap(qdev, release, &cmd->release_info);

qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
qxl_release_fence_buffer_objects(release);
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);

return ret;

Expand Down Expand Up @@ -652,8 +652,8 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane,
cmd->u.position.y = plane->state->crtc_y + fb->hot_y;

qxl_release_unmap(qdev, release, &cmd->release_info);
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
qxl_release_fence_buffer_objects(release);
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);

if (old_cursor_bo != NULL)
qxl_bo_unpin(old_cursor_bo);
Expand Down Expand Up @@ -700,8 +700,8 @@ static void qxl_cursor_atomic_disable(struct drm_plane *plane,
cmd->type = QXL_CURSOR_HIDE;
qxl_release_unmap(qdev, release, &cmd->release_info);

qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
qxl_release_fence_buffer_objects(release);
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
}

static void qxl_update_dumb_head(struct qxl_device *qdev,
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/qxl/qxl_draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
}
qxl_bo_kunmap(clips_bo);

qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
qxl_release_fence_buffer_objects(release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);

out_release_backoff:
if (ret)
Expand Down
5 changes: 1 addition & 4 deletions drivers/gpu/drm/qxl/qxl_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,8 @@ static int qxl_process_single_command(struct qxl_device *qdev,
apply_surf_reloc(qdev, &reloc_info[i]);
}

qxl_release_fence_buffer_objects(release);
ret = qxl_push_command_ring_release(qdev, release, cmd->type, true);
if (ret)
qxl_release_backoff_reserve_list(release);
else
qxl_release_fence_buffer_objects(release);

out_free_bos:
out_free_release:
Expand Down

0 comments on commit 933db73

Please sign in to comment.