diff --git a/gitrev b/gitrev index 2d45a23..682724d 100644 --- a/gitrev +++ b/gitrev @@ -1 +1 @@ -ae5d68be42cd0275a91faf56d2b527b448c3caf4 +5ff132c07aa155d759ab3da946c86351313d3020 diff --git a/qxl-reapply-cursor-after-SetCrtc-calls.patch b/qxl-reapply-cursor-after-SetCrtc-calls.patch index 2787cf7..d70acc4 100644 --- a/qxl-reapply-cursor-after-SetCrtc-calls.patch +++ b/qxl-reapply-cursor-after-SetCrtc-calls.patch @@ -1,4 +1,4 @@ -From 99ea1a3c387899424fb5c6b17baa56e8d68a3484 Mon Sep 17 00:00:00 2001 +From 92777b4dfc3920edb449d0be6ead65d8460653cc Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 12 May 2015 12:51:18 -0400 Subject: [PATCH] drm/qxl: reapply cursor after SetCrtc calls @@ -23,21 +23,102 @@ https://bugzilla.redhat.com/show_bug.cgi?id=1200901 2 files changed, 99 insertions(+) diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c -index 3aef127..fcc5f3b 100644 +index 3aef127..34ab444 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c -@@ -211,6 +211,7 @@ static void qxl_crtc_destroy(struct drm_crtc *crtc) +@@ -184,60 +184,61 @@ static struct mode_size { + {1440, 900}, + {1400, 1050}, + {1680, 1050}, + {1600, 1200}, + {1920, 1080}, + {1920, 1200} + }; + + static int qxl_add_common_modes(struct drm_connector *connector, + unsigned pwidth, + unsigned pheight) + { + struct drm_device *dev = connector->dev; + struct drm_display_mode *mode = NULL; + int i; + for (i = 0; i < ARRAY_SIZE(common_modes); i++) { + mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, + 60, false, false, false); + if (common_modes[i].w == pwidth && common_modes[i].h == pheight) + mode->type |= DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, mode); + } + return i - 1; + } + + static void qxl_crtc_destroy(struct drm_crtc *crtc) + { struct qxl_crtc *qxl_crtc = to_qxl_crtc(crtc); - + drm_crtc_cleanup(crtc); + kfree(qxl_crtc->cursor); kfree(qxl_crtc); } - -@@ -296,6 +297,92 @@ qxl_hide_cursor(struct qxl_device *qdev) + + static int qxl_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags) + { + struct drm_device *dev = crtc->dev; + struct qxl_device *qdev = dev->dev_private; + struct qxl_framebuffer *qfb_src = to_qxl_framebuffer(fb); + struct qxl_framebuffer *qfb_old = to_qxl_framebuffer(crtc->primary->fb); + struct qxl_bo *bo_old = gem_to_qxl_bo(qfb_old->obj); + struct qxl_bo *bo = gem_to_qxl_bo(qfb_src->obj); + unsigned long flags; + struct drm_clip_rect norect = { + .x1 = 0, + .y1 = 0, + .x2 = fb->width, + .y2 = fb->height + }; + int inc = 1; + int one_clip_rect = 1; + int ret = 0; + + crtc->primary->fb = fb; + bo_old->is_primary = false; + bo->is_primary = true; + + ret = qxl_bo_reserve(bo, false); +@@ -269,60 +270,145 @@ static int qxl_crtc_page_flip(struct drm_crtc *crtc, return 0; } - + + static int + qxl_hide_cursor(struct qxl_device *qdev) + { + struct qxl_release *release; + struct qxl_cursor_cmd *cmd; + int ret; + + ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), QXL_RELEASE_CURSOR_CMD, + &release, NULL); + if (ret) + return ret; + + ret = qxl_release_reserve_list(release, true); + if (ret) { + qxl_release_free(qdev, release); + return ret; + } + + cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); + 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); + return 0; + } + +static int qxl_crtc_stash_cursor(struct drm_crtc *crtc, + struct qxl_cursor *cursor) +{ @@ -100,12 +181,11 @@ index 3aef127..fcc5f3b 100644 + + cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); + cmd->type = QXL_CURSOR_SET; -+ cmd->u.set.position.x = qcrtc->cur_x; -+ cmd->u.set.position.y = qcrtc->cur_y; ++ cmd->u.set.position.x = qcrtc->cur_x + qcrtc->hot_spot_x; ++ cmd->u.set.position.y = qcrtc->cur_y + qcrtc->hot_spot_y; + + cmd->u.set.shape = qxl_bo_physical_address(qdev, cursor_bo, 0); + -+ + cmd->u.set.visible = 1; + qxl_release_unmap(qdev, release, &cmd->release_info); + @@ -127,10 +207,64 @@ index 3aef127..fcc5f3b 100644 static int qxl_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, -@@ -370,6 +457,12 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc, - + uint32_t width, + uint32_t height, int32_t hot_x, int32_t hot_y) + { + struct drm_device *dev = crtc->dev; + struct qxl_device *qdev = dev->dev_private; + struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); + struct drm_gem_object *obj; + struct qxl_cursor *cursor; + struct qxl_cursor_cmd *cmd; + struct qxl_bo *cursor_bo, *user_bo; + struct qxl_release *release; + void *user_ptr; + + int size = 64*64*4; + int ret = 0; + if (!handle) + return qxl_hide_cursor(qdev); + + obj = drm_gem_object_lookup(file_priv, handle); + if (!obj) { + DRM_ERROR("cannot find cursor object\n"); + return -ENOENT; + } + + user_bo = gem_to_qxl_bo(obj); + + ret = qxl_bo_reserve(user_bo, false); +@@ -343,60 +429,66 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc, + &release, NULL); + if (ret) + goto out_kunmap; + + ret = qxl_alloc_bo_reserved(qdev, release, sizeof(struct qxl_cursor) + size, + &cursor_bo); + if (ret) + goto out_free_release; + + ret = qxl_release_reserve_list(release, false); + if (ret) + goto out_free_bo; + + ret = qxl_bo_kmap(cursor_bo, (void **)&cursor); + if (ret) + goto out_backoff; + + cursor->header.unique = 0; + cursor->header.type = SPICE_CURSOR_TYPE_ALPHA; + cursor->header.width = 64; + cursor->header.height = 64; + cursor->header.hot_spot_x = hot_x; + cursor->header.hot_spot_y = hot_y; + cursor->data_size = size; + cursor->chunk.next_chunk = 0; + cursor->chunk.prev_chunk = 0; + cursor->chunk.data_size = size; + memcpy(cursor->chunk.data, user_ptr, size); - + + ret = qxl_crtc_stash_cursor(crtc, cursor); + if (ret) { + DRM_ERROR("cannot save cursor, may be lost on next mode set\n"); @@ -138,9 +272,63 @@ index 3aef127..fcc5f3b 100644 + } + qxl_bo_kunmap(cursor_bo); - + qxl_bo_kunmap(user_bo); -@@ -655,6 +748,12 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, + + qcrtc->cur_x += qcrtc->hot_spot_x - hot_x; + qcrtc->cur_y += qcrtc->hot_spot_y - hot_y; + qcrtc->hot_spot_x = hot_x; + qcrtc->hot_spot_y = hot_y; + + cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); + cmd->type = QXL_CURSOR_SET; + cmd->u.set.position.x = qcrtc->cur_x + qcrtc->hot_spot_x; + cmd->u.set.position.y = qcrtc->cur_y + qcrtc->hot_spot_y; + + cmd->u.set.shape = qxl_bo_physical_address(qdev, cursor_bo, 0); + + 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); + + /* finish with the userspace bo */ + ret = qxl_bo_reserve(user_bo, false); + if (!ret) { + qxl_bo_unpin(user_bo); + qxl_bo_unreserve(user_bo); + } + drm_gem_object_unreference_unlocked(obj); + +@@ -628,60 +720,66 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, + x, y, + mode->hdisplay, mode->vdisplay, + adjusted_mode->hdisplay, + adjusted_mode->vdisplay); + + if (bo->is_primary == false) + recreate_primary = true; + + if (bo->surf.stride * bo->surf.height > qdev->vram_size) { + DRM_ERROR("Mode doesn't fit in vram size (vgamem)"); + return -EINVAL; + } + + ret = qxl_bo_reserve(bo, false); + if (ret != 0) + return ret; + ret = qxl_bo_pin(bo, bo->type, NULL); + if (ret != 0) { + qxl_bo_unreserve(bo); + return -EINVAL; + } + qxl_bo_unreserve(bo); + if (recreate_primary) { + qxl_io_destroy_primary(qdev); + qxl_io_log(qdev, + "recreate primary: %dx%d,%d,%d\n", + bo->surf.width, bo->surf.height, bo->surf.stride, bo->surf.format); qxl_io_create_primary(qdev, 0, bo); bo->is_primary = true; @@ -151,17 +339,101 @@ index 3aef127..fcc5f3b 100644 + ret = 0; + } } - + if (bo->is_primary) { + DRM_DEBUG_KMS("setting surface_id to 0 for primary surface %d on crtc %d\n", bo->surface_id, qcrtc->index); + surf_id = 0; + } else { + surf_id = bo->surface_id; + } + + if (old_bo && old_bo != bo) { + old_bo->is_primary = false; + ret = qxl_bo_reserve(old_bo, false); + qxl_bo_unpin(old_bo); + qxl_bo_unreserve(old_bo); + } + + qxl_monitors_config_set(qdev, qcrtc->index, x, y, + mode->hdisplay, + mode->vdisplay, surf_id); + return 0; + } + + static void qxl_crtc_prepare(struct drm_crtc *crtc) + { + DRM_DEBUG("current: %dx%d+%d+%d (%d).\n", + crtc->mode.hdisplay, crtc->mode.vdisplay, + crtc->x, crtc->y, crtc->enabled); + } + + static void qxl_crtc_commit(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 8e633ca..6b63c54 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h -@@ -137,6 +137,7 @@ struct qxl_crtc { +@@ -110,60 +110,61 @@ struct qxl_bo { + void *kptr; + int type; + + /* Constant after initialization */ + struct drm_gem_object gem_base; + bool is_primary; /* is this now a primary surface */ + bool hw_surf_alloc; + struct qxl_surface surf; + uint32_t surface_id; + struct qxl_release *surf_create; + }; + #define gem_to_qxl_bo(gobj) container_of((gobj), struct qxl_bo, gem_base) + #define to_qxl_bo(tobj) container_of((tobj), struct qxl_bo, tbo) + + struct qxl_gem { + struct mutex mutex; + struct list_head objects; + }; + + struct qxl_bo_list { + struct ttm_validate_buffer tv; + }; + + struct qxl_crtc { + struct drm_crtc base; + int index; + int cur_x; int cur_y; int hot_spot_x; int hot_spot_y; + struct qxl_cursor *cursor; }; - + struct qxl_output { + int index; + struct drm_connector base; + struct drm_encoder enc; + }; + + struct qxl_framebuffer { + struct drm_framebuffer base; + struct drm_gem_object *obj; + }; + + #define to_qxl_crtc(x) container_of(x, struct qxl_crtc, base) + #define drm_connector_to_qxl_output(x) container_of(x, struct qxl_output, base) + #define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, enc) + #define to_qxl_framebuffer(x) container_of(x, struct qxl_framebuffer, base) + + struct qxl_mman { + struct ttm_bo_global_ref bo_global_ref; + struct drm_global_reference mem_global_ref; + bool mem_global_referenced; + struct ttm_bo_device bdev; + }; + + struct qxl_mode_info { + int num_modes; + struct qxl_mode *modes; + bool mode_config_initialized; + +-- +2.7.4 + diff --git a/sources b/sources index 2b641ad..d6e2eca 100644 --- a/sources +++ b/sources @@ -2,3 +2,4 @@ fe259c02c75eec61d1aa4b1211f3c853 perf-man-4.7.tar.gz 0d6c6c82846042198bc6ac4260a88b03 patch-4.8-rc2.xz c2585d3b7786c38e36218ef608ed9b16 patch-4.8-rc2-git1.xz +8535396052a9242a0e33e31200d647ef patch-4.8-rc2-git2.xz diff --git a/tcp-fix-use-after-free-in-tcp_xmit_retransmit_queue.patch b/tcp-fix-use-after-free-in-tcp_xmit_retransmit_queue.patch new file mode 100644 index 0000000..36ada7a --- /dev/null +++ b/tcp-fix-use-after-free-in-tcp_xmit_retransmit_queue.patch @@ -0,0 +1,46 @@ +From: Eric Dumazet +Date: 2016-08-17 12:56:26 +Subject: [PATCH net] tcp: fix use after free in tcp_xmit_retransmit_queue() + +When tcp_sendmsg() allocates a fresh and empty skb, it puts it at the +tail of the write queue using tcp_add_write_queue_tail() + +Then it attempts to copy user data into this fresh skb. + +If the copy fails, we undo the work and remove the fresh skb. + +Unfortunately, this undo lacks the change done to tp->highest_sack and +we can leave a dangling pointer (to a freed skb) + +Later, tcp_xmit_retransmit_queue() can dereference this pointer and +access freed memory. For regular kernels where memory is not unmapped, +this might cause SACK bugs because tcp_highest_sack_seq() is buggy, +returning garbage instead of tp->snd_nxt, but with various debug +features like CONFIG_DEBUG_PAGEALLOC, this can crash the kernel. + +This bug was found by Marco Grassi thanks to syzkaller. + +Fixes: 6859d49475d4 ("[TCP]: Abstract tp->highest_sack accessing & point to next skb") +Reported-by: Marco Grassi +Signed-off-by: Eric Dumazet +Cc: Ilpo Järvinen +Cc: Yuchung Cheng +Cc: Neal Cardwell +--- + include/net/tcp.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index c00e7d51bb18..7717302cab91 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1523,6 +1523,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli + { + if (sk->sk_send_head == skb_unlinked) + sk->sk_send_head = NULL; ++ if (tcp_sk(sk)->highest_sack == skb_unlinked) ++ tcp_sk(sk)->highest_sack = NULL; + } + + static inline void tcp_init_send_head(struct sock *sk) +