From fec667228a95981586716b7d25004c4d706943e2 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 7 Sep 2015 01:47:32 -0400 Subject: [PATCH] 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. --- .../qemu/files/qemu-2.4.0-CVE-2015-5225.patch | 86 ++++++++++++ .../files/qemu-2.4.0-block-mirror-crash.patch | 124 ++++++++++++++++++ .../qemu/files/qemu-2.4.0-e1000-loop.patch | 39 ++++++ ...qemu-2.4.0.ebuild => qemu-2.4.0-r1.ebuild} | 31 ++++- 4 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 app-emulation/qemu/files/qemu-2.4.0-CVE-2015-5225.patch create mode 100644 app-emulation/qemu/files/qemu-2.4.0-block-mirror-crash.patch create mode 100644 app-emulation/qemu/files/qemu-2.4.0-e1000-loop.patch rename app-emulation/qemu/{qemu-2.4.0.ebuild => qemu-2.4.0-r1.ebuild} (95%) diff --git a/app-emulation/qemu/files/qemu-2.4.0-CVE-2015-5225.patch b/app-emulation/qemu/files/qemu-2.4.0-CVE-2015-5225.patch new file mode 100644 index 000000000000..de7090d01a4d --- /dev/null +++ b/app-emulation/qemu/files/qemu-2.4.0-CVE-2015-5225.patch @@ -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 +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: 范祚至(库特) +Reviewed-by: P J P +Signed-off-by: Gerd Hoffmann +--- + 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 + diff --git a/app-emulation/qemu/files/qemu-2.4.0-block-mirror-crash.patch b/app-emulation/qemu/files/qemu-2.4.0-block-mirror-crash.patch new file mode 100644 index 000000000000..ad4051e22c94 --- /dev/null +++ b/app-emulation/qemu/files/qemu-2.4.0-block-mirror-crash.patch @@ -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 +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: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Paolo Bonzini +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Jeff Cody +Message-id: 1439455310-11263-1-git-send-email-kwolf@redhat.com +Signed-off-by: Jeff Cody +--- + 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 + diff --git a/app-emulation/qemu/files/qemu-2.4.0-e1000-loop.patch b/app-emulation/qemu/files/qemu-2.4.0-e1000-loop.patch new file mode 100644 index 000000000000..f2538a723d15 --- /dev/null +++ b/app-emulation/qemu/files/qemu-2.4.0-e1000-loop.patch @@ -0,0 +1,39 @@ +https://bugs.gentoo.org/559656 + +https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg01199.html + +From: Stefan Hajnoczi +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 + +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 +Signed-off-by: Stefan Hajnoczi +--- + 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 diff --git a/app-emulation/qemu/qemu-2.4.0.ebuild b/app-emulation/qemu/qemu-2.4.0-r1.ebuild similarity index 95% rename from app-emulation/qemu/qemu-2.4.0.ebuild rename to app-emulation/qemu/qemu-2.4.0-r1.ebuild index 0dfa27f069fb..13c15adbaad3 100644 --- a/app-emulation/qemu/qemu-2.4.0.ebuild +++ b/app-emulation/qemu/qemu-2.4.0-r1.ebuild @@ -39,8 +39,8 @@ virtfs +vnc vte xattr xen xfs" COMMON_TARGETS="aarch64 alpha arm cris i386 m68k microblaze microblazeel mips mips64 mips64el mipsel or32 ppc ppc64 s390x sh4 sh4eb sparc sparc64 unicore32 x86_64" -IUSE_SOFTMMU_TARGETS="${COMMON_TARGETS} lm32 moxie ppcemb xtensa xtensaeb" -IUSE_USER_TARGETS="${COMMON_TARGETS} armeb mipsn32 mipsn32el ppc64abi32 sparc32plus" +IUSE_SOFTMMU_TARGETS="${COMMON_TARGETS} lm32 moxie ppcemb tricore xtensa xtensaeb" +IUSE_USER_TARGETS="${COMMON_TARGETS} armeb mipsn32 mipsn32el ppc64abi32 ppc64le sparc32plus" use_softmmu_targets=$(printf ' qemu_softmmu_targets_%s' ${IUSE_SOFTMMU_TARGETS}) use_user_targets=$(printf ' qemu_user_targets_%s' ${IUSE_USER_TARGETS}) @@ -134,7 +134,7 @@ USER_LIB_DEPEND="${COMMON_LIB_DEPEND}" X86_FIRMWARE_DEPEND=" >=sys-firmware/ipxe-1.0.0_p20130624 pin-upstream-blobs? ( - ~sys-firmware/seabios-1.7.5 + ~sys-firmware/seabios-1.8.2 ~sys-firmware/sgabios-0.1_pre8 ~sys-firmware/vgabios-0.7a ) @@ -268,7 +268,29 @@ pkg_setup() { enewgroup kvm 78 } +# Sanity check to make sure target lists are kept up-to-date. +check_targets() { + local var=$1 mak=$2 + local detected sorted + + pushd "${S}"/default-configs >/dev/null || die + + detected=$(echo $(printf '%s\n' *-${mak}.mak | sed "s:-${mak}.mak::" | sort -u)) + sorted=$(echo $(printf '%s\n' ${!var} | sort -u)) + if [[ ${sorted} != "${detected}" ]] ; then + eerror "The ebuild needs to be kept in sync." + eerror "${var}: ${sorted}" + eerror "$(printf '%-*s' ${#var} configure): ${detected}" + die "sync ${var} to the list of targets" + fi + + popd >/dev/null +} + src_prepare() { + check_targets IUSE_SOFTMMU_TARGETS softmmu + check_targets IUSE_USER_TARGETS linux-user + # Alter target makefiles to accept CFLAGS set via flag-o sed -i -r \ -e 's/^(C|OP_C|HELPER_C)FLAGS=/\1FLAGS+=/' \ @@ -278,6 +300,9 @@ src_prepare() { use nls || rm -f po/*.po epatch "${FILESDIR}"/qemu-1.7.0-cflags.patch + epatch "${FILESDIR}"/${P}-block-mirror-crash.patch #558396 + epatch "${FILESDIR}"/${P}-CVE-2015-5225.patch #558416 + epatch "${FILESDIR}"/${PN}-2.4.0-e1000-loop.patch #559656 [[ -n ${BACKPORTS} ]] && \ EPATCH_FORCE=yes EPATCH_SUFFIX="patch" EPATCH_SOURCE="${S}/patches" \ epatch -- 2.26.2