Commit 0d28ac49 authored by Vasily Averin's avatar Vasily Averin Committed by Greg Kroah-Hartman

drm/qxl: qxl_release use after free

commit 933db733 upstream.

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: f64122c1 ("drm: add new QXL driver. (v1.4)")
Signed-off-by: default avatarVasily Averin <vvs@virtuozzo.com>
Link: http://patchwork.freedesktop.org/patch/msgid/fa17b338-66ae-f299-68fe-8d32419d9071@virtuozzo.comSigned-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
[backported to v.4.19 stable]
Signed-off-by: default avatarVasily Averin <vvs@virtuozzo.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a8d36f64
...@@ -501,8 +501,8 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev, ...@@ -501,8 +501,8 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev,
/* no need to add a release to the fence for this surface bo, /* 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 since it is only released when we ask to destroy the surface
and it would never signal otherwise */ and it would never signal otherwise */
qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
qxl_release_fence_buffer_objects(release); qxl_release_fence_buffer_objects(release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
surf->hw_surf_alloc = true; surf->hw_surf_alloc = true;
spin_lock(&qdev->surf_id_idr_lock); spin_lock(&qdev->surf_id_idr_lock);
...@@ -544,9 +544,8 @@ int qxl_hw_surface_dealloc(struct qxl_device *qdev, ...@@ -544,9 +544,8 @@ int qxl_hw_surface_dealloc(struct qxl_device *qdev,
cmd->surface_id = id; cmd->surface_id = id;
qxl_release_unmap(qdev, release, &cmd->release_info); 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_release_fence_buffer_objects(release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
return 0; return 0;
} }
......
...@@ -532,8 +532,8 @@ static int qxl_primary_apply_cursor(struct drm_plane *plane) ...@@ -532,8 +532,8 @@ static int qxl_primary_apply_cursor(struct drm_plane *plane)
cmd->u.set.visible = 1; cmd->u.set.visible = 1;
qxl_release_unmap(qdev, release, &cmd->release_info); 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_release_fence_buffer_objects(release);
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
return ret; return ret;
...@@ -694,8 +694,8 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane, ...@@ -694,8 +694,8 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane,
cmd->u.position.y = plane->state->crtc_y + fb->hot_y; cmd->u.position.y = plane->state->crtc_y + fb->hot_y;
qxl_release_unmap(qdev, release, &cmd->release_info); 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_release_fence_buffer_objects(release);
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
if (old_cursor_bo) if (old_cursor_bo)
qxl_bo_unref(&old_cursor_bo); qxl_bo_unref(&old_cursor_bo);
...@@ -740,8 +740,8 @@ static void qxl_cursor_atomic_disable(struct drm_plane *plane, ...@@ -740,8 +740,8 @@ static void qxl_cursor_atomic_disable(struct drm_plane *plane,
cmd->type = QXL_CURSOR_HIDE; cmd->type = QXL_CURSOR_HIDE;
qxl_release_unmap(qdev, release, &cmd->release_info); 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_release_fence_buffer_objects(release);
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
} }
static int qxl_plane_prepare_fb(struct drm_plane *plane, static int qxl_plane_prepare_fb(struct drm_plane *plane,
......
...@@ -241,8 +241,8 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image, ...@@ -241,8 +241,8 @@ void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image,
qxl_bo_physical_address(qdev, dimage->bo, 0); qxl_bo_physical_address(qdev, dimage->bo, 0);
qxl_release_unmap(qdev, release, &drawable->release_info); qxl_release_unmap(qdev, release, &drawable->release_info);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
qxl_release_fence_buffer_objects(release); qxl_release_fence_buffer_objects(release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
out_free_palette: out_free_palette:
if (palette_bo) if (palette_bo)
...@@ -382,8 +382,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, ...@@ -382,8 +382,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev,
} }
qxl_bo_kunmap(clips_bo); qxl_bo_kunmap(clips_bo);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
qxl_release_fence_buffer_objects(release); qxl_release_fence_buffer_objects(release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
out_release_backoff: out_release_backoff:
if (ret) if (ret)
...@@ -433,8 +433,8 @@ void qxl_draw_copyarea(struct qxl_device *qdev, ...@@ -433,8 +433,8 @@ void qxl_draw_copyarea(struct qxl_device *qdev,
drawable->u.copy_bits.src_pos.y = sy; drawable->u.copy_bits.src_pos.y = sy;
qxl_release_unmap(qdev, release, &drawable->release_info); qxl_release_unmap(qdev, release, &drawable->release_info);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
qxl_release_fence_buffer_objects(release); qxl_release_fence_buffer_objects(release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
out_free_release: out_free_release:
if (ret) if (ret)
...@@ -477,8 +477,8 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec) ...@@ -477,8 +477,8 @@ void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec)
qxl_release_unmap(qdev, release, &drawable->release_info); qxl_release_unmap(qdev, release, &drawable->release_info);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
qxl_release_fence_buffer_objects(release); qxl_release_fence_buffer_objects(release);
qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
out_free_release: out_free_release:
if (ret) if (ret)
......
...@@ -257,11 +257,8 @@ static int qxl_process_single_command(struct qxl_device *qdev, ...@@ -257,11 +257,8 @@ static int qxl_process_single_command(struct qxl_device *qdev,
apply_surf_reloc(qdev, &reloc_info[i]); apply_surf_reloc(qdev, &reloc_info[i]);
} }
qxl_release_fence_buffer_objects(release);
ret = qxl_push_command_ring_release(qdev, release, cmd->type, true); 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_bos:
out_free_release: out_free_release:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment