Linux v4.8-rc2-42-g5ff132c

This commit is contained in:
Justin M. Forbes 2016-08-17 15:08:12 -05:00
parent d5efb68b2d
commit 773618662c
4 changed files with 338 additions and 19 deletions

2
gitrev
View File

@ -1 +1 @@
ae5d68be42cd0275a91faf56d2b527b448c3caf4
5ff132c07aa155d759ab3da946c86351313d3020

View File

@ -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 <rstrode@redhat.com>
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

View File

@ -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

View File

@ -0,0 +1,46 @@
From: Eric Dumazet <edumazet@google.com>
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 <marco.gra@gmail.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Cc: Yuchung Cheng <ycheng@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
---
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)