forked from gentoo/gentoo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
app-emulation/qemu: various fixes/updates
Sync in the updates from the 9999 ebuild: - updated seabios pin - add new targets - add sanity checks for targets Add fix from upstream for blockcommit crashes #558396. Add fix from upstream for CVE-2015-5225 #558416. Add fix posted upstream (but not yet merged) for e1000 infinite loop #559656.
- Loading branch information
Showing
4 changed files
with
277 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
https://bugs.gentoo.org/558416 | ||
|
||
fix from upstream git | ||
|
||
From eb8934b0418b3b1d125edddc4fc334a54334a49b Mon Sep 17 00:00:00 2001 | ||
From: Gerd Hoffmann <[email protected]> | ||
Date: Mon, 17 Aug 2015 19:56:53 +0200 | ||
Subject: [PATCH] vnc: fix memory corruption (CVE-2015-5225) | ||
MIME-Version: 1.0 | ||
Content-Type: text/plain; charset=UTF-8 | ||
Content-Transfer-Encoding: 8bit | ||
|
||
The _cmp_bytes variable added by commit "bea60dd ui/vnc: fix potential | ||
memory corruption issues" can become negative. Result is (possibly | ||
exploitable) memory corruption. Reason for that is it uses the stride | ||
instead of bytes per scanline to apply limits. | ||
|
||
For the server surface is is actually fine. vnc creates that itself, | ||
there is never any padding and thus scanline length always equals stride. | ||
|
||
For the guest surface scanline length and stride are typically identical | ||
too, but it doesn't has to be that way. So add and use a new variable | ||
(guest_ll) for the guest scanline length. Also rename min_stride to | ||
line_bytes to make more clear what it actually is. Finally sprinkle | ||
in an assert() to make sure we never use a negative _cmp_bytes again. | ||
|
||
Reported-by: 范祚至(库特) <[email protected]> | ||
Reviewed-by: P J P <[email protected]> | ||
Signed-off-by: Gerd Hoffmann <[email protected]> | ||
--- | ||
ui/vnc.c | 15 ++++++++++----- | ||
1 file changed, 10 insertions(+), 5 deletions(-) | ||
|
||
diff --git a/ui/vnc.c b/ui/vnc.c | ||
index e26973a..caf82f5 100644 | ||
--- a/ui/vnc.c | ||
+++ b/ui/vnc.c | ||
@@ -2872,7 +2872,7 @@ static int vnc_refresh_server_surface(VncDisplay *vd) | ||
pixman_image_get_width(vd->server)); | ||
int height = MIN(pixman_image_get_height(vd->guest.fb), | ||
pixman_image_get_height(vd->server)); | ||
- int cmp_bytes, server_stride, min_stride, guest_stride, y = 0; | ||
+ int cmp_bytes, server_stride, line_bytes, guest_ll, guest_stride, y = 0; | ||
uint8_t *guest_row0 = NULL, *server_row0; | ||
VncState *vs; | ||
int has_dirty = 0; | ||
@@ -2891,17 +2891,21 @@ static int vnc_refresh_server_surface(VncDisplay *vd) | ||
* Update server dirty map. | ||
*/ | ||
server_row0 = (uint8_t *)pixman_image_get_data(vd->server); | ||
- server_stride = guest_stride = pixman_image_get_stride(vd->server); | ||
+ server_stride = guest_stride = guest_ll = | ||
+ pixman_image_get_stride(vd->server); | ||
cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES, | ||
server_stride); | ||
if (vd->guest.format != VNC_SERVER_FB_FORMAT) { | ||
int width = pixman_image_get_width(vd->server); | ||
tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width); | ||
} else { | ||
+ int guest_bpp = | ||
+ PIXMAN_FORMAT_BPP(pixman_image_get_format(vd->guest.fb)); | ||
guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb); | ||
guest_stride = pixman_image_get_stride(vd->guest.fb); | ||
+ guest_ll = pixman_image_get_width(vd->guest.fb) * ((guest_bpp + 7) / 8); | ||
} | ||
- min_stride = MIN(server_stride, guest_stride); | ||
+ line_bytes = MIN(server_stride, guest_ll); | ||
|
||
for (;;) { | ||
int x; | ||
@@ -2932,9 +2936,10 @@ static int vnc_refresh_server_surface(VncDisplay *vd) | ||
if (!test_and_clear_bit(x, vd->guest.dirty[y])) { | ||
continue; | ||
} | ||
- if ((x + 1) * cmp_bytes > min_stride) { | ||
- _cmp_bytes = min_stride - x * cmp_bytes; | ||
+ if ((x + 1) * cmp_bytes > line_bytes) { | ||
+ _cmp_bytes = line_bytes - x * cmp_bytes; | ||
} | ||
+ assert(_cmp_bytes >= 0); | ||
if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) { | ||
continue; | ||
} | ||
-- | ||
2.5.0 | ||
|
124 changes: 124 additions & 0 deletions
124
app-emulation/qemu/files/qemu-2.4.0-block-mirror-crash.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
https://bugs.gentoo.org/558396 | ||
|
||
fix from upstream git | ||
|
||
From e424aff5f307227b1c2512bbb8ece891bb895cef Mon Sep 17 00:00:00 2001 | ||
From: Kevin Wolf <[email protected]> | ||
Date: Thu, 13 Aug 2015 10:41:50 +0200 | ||
Subject: [PATCH] mirror: Fix coroutine reentrance | ||
|
||
This fixes a regression introduced by commit dcfb3beb ("mirror: Do zero | ||
write on target if sectors not allocated"), which was reported to cause | ||
aborts with the message "Co-routine re-entered recursively". | ||
|
||
The cause for this bug is the following code in mirror_iteration_done(): | ||
|
||
if (s->common.busy) { | ||
qemu_coroutine_enter(s->common.co, NULL); | ||
} | ||
|
||
This has always been ugly because - unlike most places that reenter - it | ||
doesn't have a specific yield that it pairs with, but is more | ||
uncontrolled. What we really mean here is "reenter the coroutine if | ||
it's in one of the four explicit yields in mirror.c". | ||
|
||
This used to be equivalent with s->common.busy because neither | ||
mirror_run() nor mirror_iteration() call any function that could yield. | ||
However since commit dcfb3beb this doesn't hold true any more: | ||
bdrv_get_block_status_above() can yield. | ||
|
||
So what happens is that bdrv_get_block_status_above() wants to take a | ||
lock that is already held, so it adds itself to the queue of waiting | ||
coroutines and yields. Instead of being woken up by the unlock function, | ||
however, it gets woken up by mirror_iteration_done(), which is obviously | ||
wrong. | ||
|
||
In most cases the code actually happens to cope fairly well with such | ||
cases, but in this specific case, the unlock must already have scheduled | ||
the coroutine for wakeup when mirror_iteration_done() reentered it. And | ||
then the coroutine happened to process the scheduled restarts and tried | ||
to reenter itself recursively. | ||
|
||
This patch fixes the problem by pairing the reenter in | ||
mirror_iteration_done() with specific yields instead of abusing | ||
s->common.busy. | ||
|
||
Cc: [email protected] | ||
Signed-off-by: Kevin Wolf <[email protected]> | ||
Reviewed-by: Paolo Bonzini <[email protected]> | ||
Reviewed-by: Stefan Hajnoczi <[email protected]> | ||
Reviewed-by: Jeff Cody <[email protected]> | ||
Message-id: [email protected] | ||
Signed-off-by: Jeff Cody <[email protected]> | ||
--- | ||
block/mirror.c | 15 ++++++++++----- | ||
1 file changed, 10 insertions(+), 5 deletions(-) | ||
|
||
diff --git a/block/mirror.c b/block/mirror.c | ||
index 0841964..9474443 100644 | ||
--- a/block/mirror.c | ||
+++ b/block/mirror.c | ||
@@ -60,6 +60,7 @@ typedef struct MirrorBlockJob { | ||
int sectors_in_flight; | ||
int ret; | ||
bool unmap; | ||
+ bool waiting_for_io; | ||
} MirrorBlockJob; | ||
|
||
typedef struct MirrorOp { | ||
@@ -114,11 +115,7 @@ static void mirror_iteration_done(MirrorOp *op, int ret) | ||
qemu_iovec_destroy(&op->qiov); | ||
g_slice_free(MirrorOp, op); | ||
|
||
- /* Enter coroutine when it is not sleeping. The coroutine sleeps to | ||
- * rate-limit itself. The coroutine will eventually resume since there is | ||
- * a sleep timeout so don't wake it early. | ||
- */ | ||
- if (s->common.busy) { | ||
+ if (s->waiting_for_io) { | ||
qemu_coroutine_enter(s->common.co, NULL); | ||
} | ||
} | ||
@@ -203,7 +200,9 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
/* Wait for I/O to this cluster (from a previous iteration) to be done. */ | ||
while (test_bit(next_chunk, s->in_flight_bitmap)) { | ||
trace_mirror_yield_in_flight(s, sector_num, s->in_flight); | ||
+ s->waiting_for_io = true; | ||
qemu_coroutine_yield(); | ||
+ s->waiting_for_io = false; | ||
} | ||
|
||
do { | ||
@@ -239,7 +238,9 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) | ||
*/ | ||
while (nb_chunks == 0 && s->buf_free_count < added_chunks) { | ||
trace_mirror_yield_buf_busy(s, nb_chunks, s->in_flight); | ||
+ s->waiting_for_io = true; | ||
qemu_coroutine_yield(); | ||
+ s->waiting_for_io = false; | ||
} | ||
if (s->buf_free_count < nb_chunks + added_chunks) { | ||
trace_mirror_break_buf_busy(s, nb_chunks, s->in_flight); | ||
@@ -337,7 +338,9 @@ static void mirror_free_init(MirrorBlockJob *s) | ||
static void mirror_drain(MirrorBlockJob *s) | ||
{ | ||
while (s->in_flight > 0) { | ||
+ s->waiting_for_io = true; | ||
qemu_coroutine_yield(); | ||
+ s->waiting_for_io = false; | ||
} | ||
} | ||
|
||
@@ -510,7 +513,9 @@ static void coroutine_fn mirror_run(void *opaque) | ||
if (s->in_flight == MAX_IN_FLIGHT || s->buf_free_count == 0 || | ||
(cnt == 0 && s->in_flight > 0)) { | ||
trace_mirror_yield(s, s->in_flight, s->buf_free_count, cnt); | ||
+ s->waiting_for_io = true; | ||
qemu_coroutine_yield(); | ||
+ s->waiting_for_io = false; | ||
continue; | ||
} else if (cnt != 0) { | ||
delay_ns = mirror_iteration(s); | ||
-- | ||
2.5.0 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
https://bugs.gentoo.org/559656 | ||
|
||
https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg01199.html | ||
|
||
From: Stefan Hajnoczi <[email protected]> | ||
Subject: [PATCH] e1000: Avoid infinite loop in processing transmit descriptor | ||
Newsgroups: gmane.comp.emulators.qemu | ||
Date: 2015-09-04 16:21:06 GMT (2 days, 12 hours and 51 minutes ago) | ||
From: P J P <[email protected]> | ||
|
||
While processing transmit descriptors, it could lead to an infinite | ||
loop if 'bytes' was to become zero; Add a check to avoid it. | ||
|
||
[The guest can force 'bytes' to 0 by setting the hdr_len and mss | ||
descriptor fields to 0. | ||
--Stefan] | ||
|
||
Signed-off-by: P J P <[email protected]> | ||
Signed-off-by: Stefan Hajnoczi <[email protected]> | ||
--- | ||
hw/net/e1000.c | 3 ++- | ||
1 file changed, 2 insertions(+), 1 deletion(-) | ||
|
||
diff --git a/hw/net/e1000.c b/hw/net/e1000.c | ||
index 5c6bcd0..09c9e9d 100644 | ||
--- a/hw/net/e1000.c | ||
+++ b/hw/net/e1000.c | ||
@@ -740,7 +740,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) | ||
memmove(tp->data, tp->header, tp->hdr_len); | ||
tp->size = tp->hdr_len; | ||
} | ||
- } while (split_size -= bytes); | ||
+ split_size -= bytes; | ||
+ } while (bytes && split_size); | ||
} else if (!tp->tse && tp->cptse) { | ||
// context descriptor TSE is not set, while data descriptor TSE is set | ||
DBGOUT(TXERR, "TCP segmentation error\n"); | ||
-- | ||
2.4.3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters