drm/qxl: qxl_release use after free
commit 933db73351d359f74b14f4af095808260aff11f9 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: f64122c1f6
("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>
[backported to v.4.19 stable]
Signed-off-by: Vasily Averin <vvs@virtuozzo.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a8d36f64dd
commit
0d28ac49eb
4 changed files with 10 additions and 14 deletions
|
@ -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,
|
||||
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);
|
||||
|
@ -544,9 +544,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;
|
||||
}
|
||||
|
|
|
@ -532,8 +532,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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
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)
|
||||
qxl_bo_unref(&old_cursor_bo);
|
||||
|
@ -740,8 +740,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 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,
|
|||
qxl_bo_physical_address(qdev, dimage->bo, 0);
|
||||
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_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
|
||||
|
||||
out_free_palette:
|
||||
if (palette_bo)
|
||||
|
@ -382,8 +382,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)
|
||||
|
@ -433,8 +433,8 @@ void qxl_draw_copyarea(struct qxl_device *qdev,
|
|||
drawable->u.copy_bits.src_pos.y = sy;
|
||||
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_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false);
|
||||
|
||||
out_free_release:
|
||||
if (ret)
|
||||
|
@ -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_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_free_release:
|
||||
if (ret)
|
||||
|
|
|
@ -257,11 +257,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:
|
||||
|
|
Loading…
Reference in a new issue