Skip to content

Commit

Permalink
drm/qxl: qxl_release use after free
Browse files Browse the repository at this point in the history
commit 933db73 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: 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>
[backported to v4.9-stable]
Signed-off-by: Vasily Averin <vvs@virtuozzo.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Vasily Averin authored and Greg Kroah-Hartman committed May 5, 2020
1 parent 6affa87 commit 39c4c5c
Show file tree
Hide file tree
Showing 4 changed files with 11 additions and 15 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 @@ -529,8 +529,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 @@ -572,9 +572,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
8 changes: 4 additions & 4 deletions drivers/gpu/drm/qxl/qxl_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -333,8 +333,8 @@ static int qxl_crtc_apply_cursor(struct drm_crtc *crtc)
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 @@ -436,8 +436,8 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
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);
Expand Down Expand Up @@ -497,8 +497,8 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc,
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;
}
Expand Down
8 changes: 4 additions & 4 deletions drivers/gpu/drm/qxl/qxl_draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
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 @@ -256,11 +256,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 39c4c5c

Please sign in to comment.