--- /dev/null
+From 933db73351d359f74b14f4af095808260aff11f9 Mon Sep 17 00:00:00 2001
+From: Vasily Averin <vvs@virtuozzo.com>
+Date: Wed, 29 Apr 2020 12:01:24 +0300
+Subject: drm/qxl: qxl_release use after free
+
+From: Vasily Averin <vvs@virtuozzo.com>
+
+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: f64122c1f6ad ("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 v4.9-stable]
+Signed-off-by: Vasily Averin <vvs@virtuozzo.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/qxl/qxl_cmd.c | 5 ++---
+ drivers/gpu/drm/qxl/qxl_display.c | 8 ++++----
+ drivers/gpu/drm/qxl/qxl_draw.c | 8 ++++----
+ drivers/gpu/drm/qxl/qxl_ioctl.c | 5 +----
+ 4 files changed, 11 insertions(+), 15 deletions(-)
+
+--- a/drivers/gpu/drm/qxl/qxl_cmd.c
++++ b/drivers/gpu/drm/qxl/qxl_cmd.c
+@@ -529,8 +529,8 @@ int qxl_hw_surface_alloc(struct qxl_devi
+ /* 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);
+@@ -572,9 +572,8 @@ int qxl_hw_surface_dealloc(struct qxl_de
+ 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;
+ }
+--- a/drivers/gpu/drm/qxl/qxl_display.c
++++ b/drivers/gpu/drm/qxl/qxl_display.c
+@@ -292,8 +292,8 @@ qxl_hide_cursor(struct qxl_device *qdev)
+ 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);
+ return 0;
+ }
+
+@@ -333,8 +333,8 @@ static int qxl_crtc_apply_cursor(struct
+ 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;
+
+@@ -436,8 +436,8 @@ static int qxl_crtc_cursor_set2(struct d
+ 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);
+
+ /* finish with the userspace bo */
+ ret = qxl_bo_reserve(user_bo, false);
+@@ -497,8 +497,8 @@ static int qxl_crtc_cursor_move(struct d
+ cmd->u.position.y = qcrtc->cur_y + qcrtc->hot_spot_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);
+
+ return 0;
+ }
+--- a/drivers/gpu/drm/qxl/qxl_draw.c
++++ b/drivers/gpu/drm/qxl/qxl_draw.c
+@@ -241,8 +241,8 @@ void qxl_draw_opaque_fb(const struct qxl
+ 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
+ }
+ 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
+ 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_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)
+--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
++++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
+@@ -256,11 +256,8 @@ static int qxl_process_single_command(st
+ 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: