crobinso pushed to qemu (f21). "Qemu: PRDT overflow from guest to host (bz #1204919, bz #1205322) (..more)"
notifications at fedoraproject.org
notifications at fedoraproject.org
Fri Mar 27 18:41:17 UTC 2015
>From 29e31e320f42ace6782d16ddf552d3540b28a9c3 Mon Sep 17 00:00:00 2001
From: Cole Robinson <crobinso at redhat.com>
Date: Fri, 27 Mar 2015 14:40:27 -0400
Subject: Qemu: PRDT overflow from guest to host (bz #1204919, bz #1205322)
CVE-2014-8106: cirrus: insufficient blit region checks (bz #1170612, bz
#1169454) Fix .vdi disk corruption (bz #1199400) Don't install ksm services
as executable (bz #1192720)
diff --git a/0002-aarch64-Allow-kernel-option-to-take-a-gzip-compresse.patch b/0002-aarch64-Allow-kernel-option-to-take-a-gzip-compresse.patch
index 637fa3c..4dfed3f 100644
--- a/0002-aarch64-Allow-kernel-option-to-take-a-gzip-compresse.patch
+++ b/0002-aarch64-Allow-kernel-option-to-take-a-gzip-compresse.patch
@@ -1,7 +1,6 @@
-From e96a3d72b1f869ee3bf0bdbb4a3ca8f9ae4de144 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Tue, 19 Aug 2014 18:56:28 +0100
-Subject: [PATCH 02/11] aarch64: Allow -kernel option to take a gzip-compressed
+Subject: [PATCH] aarch64: Allow -kernel option to take a gzip-compressed
kernel.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
@@ -52,6 +51,3 @@ index 50b6c5c..4bad4e6 100644
if (kernel_size < 0) {
entry = info->loader_start + kernel_load_offset;
kernel_size = load_image_targphys(info->kernel_filename, entry,
---
-2.1.0
-
diff --git a/0003-block.curl-adding-timeout-option.patch b/0003-block.curl-adding-timeout-option.patch
index d05e3d2..b003edf 100644
--- a/0003-block.curl-adding-timeout-option.patch
+++ b/0003-block.curl-adding-timeout-option.patch
@@ -1,7 +1,6 @@
-From 799d9c41ae5fd105e1467863dd912f8fd4e970bf Mon Sep 17 00:00:00 2001
From: Daniel Henrique Barboza <danielhb at linux.vnet.ibm.com>
Date: Wed, 13 Aug 2014 12:44:27 -0300
-Subject: [PATCH 03/11] block.curl: adding 'timeout' option
+Subject: [PATCH] block.curl: adding 'timeout' option
The curl hardcoded timeout (5 seconds) sometimes is not long
enough depending on the remote server configuration and network
@@ -111,6 +110,3 @@ index 1549625..dcb008b 100644
qemu-system-x86_64 -drive file=/tmp/test.qcow2
@end example
---
-2.1.0
-
diff --git a/0004-curl-Allow-a-cookie-or-cookies-to-be-sent-with-http-.patch b/0004-curl-Allow-a-cookie-or-cookies-to-be-sent-with-http-.patch
index 7a4d76a..e58b6e4 100644
--- a/0004-curl-Allow-a-cookie-or-cookies-to-be-sent-with-http-.patch
+++ b/0004-curl-Allow-a-cookie-or-cookies-to-be-sent-with-http-.patch
@@ -1,8 +1,7 @@
-From db1048a84b2cbf57809a5fcaebd567e8e9a209e4 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Fri, 29 Aug 2014 16:03:12 +0100
-Subject: [PATCH 04/11] curl: Allow a cookie or cookies to be sent with
- http/https requests.
+Subject: [PATCH] curl: Allow a cookie or cookies to be sent with http/https
+ requests.
In order to access VMware ESX efficiently, we need to send a session
cookie. This patch is very simple and just allows you to send that
@@ -122,6 +121,3 @@ index dcb008b..53b6171 100644
@item timeout
Set the timeout in seconds of the CURL connection. This timeout is the time
that CURL waits for a response from the remote server to get the size of the
---
-2.1.0
-
diff --git a/0005-curl-Don-t-deref-NULL-pointer-in-call-to-aio_poll.patch b/0005-curl-Don-t-deref-NULL-pointer-in-call-to-aio_poll.patch
index dd0a1e0..b00a751 100644
--- a/0005-curl-Don-t-deref-NULL-pointer-in-call-to-aio_poll.patch
+++ b/0005-curl-Don-t-deref-NULL-pointer-in-call-to-aio_poll.patch
@@ -1,7 +1,6 @@
-From 61fa004b207d01de98cd2aac6fe7b553da6fe079 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Thu, 28 Aug 2014 09:04:21 +0100
-Subject: [PATCH 05/11] curl: Don't deref NULL pointer in call to aio_poll.
+Subject: [PATCH] curl: Don't deref NULL pointer in call to aio_poll.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@@ -75,6 +74,3 @@ index 537e257..d28b701 100644
if (!state) {
acb->common.cb(acb->common.opaque, -EIO);
qemu_aio_release(acb);
---
-2.1.0
-
diff --git a/0006-virtio-pci-fix-migration-for-pci-bus-master.patch b/0006-virtio-pci-fix-migration-for-pci-bus-master.patch
index 38b7fb0..98b050f 100644
--- a/0006-virtio-pci-fix-migration-for-pci-bus-master.patch
+++ b/0006-virtio-pci-fix-migration-for-pci-bus-master.patch
@@ -1,7 +1,6 @@
-From 5c8a5868a03d062a25a0345dc8c97358fd7ad6f9 Mon Sep 17 00:00:00 2001
From: "Michael S. Tsirkin" <mst at redhat.com>
Date: Thu, 11 Sep 2014 18:34:29 +0300
-Subject: [PATCH 06/11] virtio-pci: fix migration for pci bus master
+Subject: [PATCH] virtio-pci: fix migration for pci bus master
Current support for bus master (clearing OK bit)
together with the need to support guests which do not
@@ -115,6 +114,3 @@ index ba675fe..ec582fe 100644
}
static Property virtio_pci_properties[] = {
---
-2.1.0
-
diff --git a/0007-Revert-virtio-pci-fix-migration-for-pci-bus-master.patch b/0007-Revert-virtio-pci-fix-migration-for-pci-bus-master.patch
index 0227afa..1993a96 100644
--- a/0007-Revert-virtio-pci-fix-migration-for-pci-bus-master.patch
+++ b/0007-Revert-virtio-pci-fix-migration-for-pci-bus-master.patch
@@ -1,7 +1,6 @@
-From ff681d852d37fe9f1ac64076fc18ecc1b9b698da Mon Sep 17 00:00:00 2001
From: "Michael S. Tsirkin" <mst at redhat.com>
Date: Mon, 29 Sep 2014 11:27:32 +0300
-Subject: [PATCH 07/11] Revert "virtio-pci: fix migration for pci bus master"
+Subject: [PATCH] Revert "virtio-pci: fix migration for pci bus master"
This reverts commit 4d43d3f3c8147ade184df9a1e9e82826edd39e19.
@@ -96,6 +95,3 @@ index ec582fe..ba675fe 100644
}
static Property virtio_pci_properties[] = {
---
-2.1.0
-
diff --git a/0008-block-raw-posix-Fix-disk-corruption-in-try_fiemap.patch b/0008-block-raw-posix-Fix-disk-corruption-in-try_fiemap.patch
index 14bb69e..49e4de3 100644
--- a/0008-block-raw-posix-Fix-disk-corruption-in-try_fiemap.patch
+++ b/0008-block-raw-posix-Fix-disk-corruption-in-try_fiemap.patch
@@ -1,7 +1,6 @@
-From af316039d3f1818463e8d5f8f4e5eaf19a2c7b55 Mon Sep 17 00:00:00 2001
From: Tony Breeds <tony at bakeyournoodle.com>
Date: Fri, 26 Sep 2014 09:14:11 +1000
-Subject: [PATCH 08/11] block/raw-posix: Fix disk corruption in try_fiemap
+Subject: [PATCH] block/raw-posix: Fix disk corruption in try_fiemap
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@@ -40,6 +39,3 @@ index efa5686..8f6c923 100644
f.fm.fm_extent_count = 1;
f.fm.fm_reserved = 0;
if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
---
-2.1.0
-
diff --git a/0009-block-raw-posix-use-seek_hole-ahead-of-fiemap.patch b/0009-block-raw-posix-use-seek_hole-ahead-of-fiemap.patch
index 57664a7..b8be43f 100644
--- a/0009-block-raw-posix-use-seek_hole-ahead-of-fiemap.patch
+++ b/0009-block-raw-posix-use-seek_hole-ahead-of-fiemap.patch
@@ -1,7 +1,6 @@
-From 1b66fe241d9609fed79ee1583e6425833a1d7d9e Mon Sep 17 00:00:00 2001
From: Tony Breeds <tony at bakeyournoodle.com>
Date: Fri, 26 Sep 2014 09:14:12 +1000
-Subject: [PATCH 09/11] block/raw-posix: use seek_hole ahead of fiemap
+Subject: [PATCH] block/raw-posix: use seek_hole ahead of fiemap
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@@ -45,6 +44,3 @@ index 8f6c923..50d29e7 100644
if (ret < 0) {
/* Assume everything is allocated. */
data = 0;
---
-2.1.0
-
diff --git a/0010-usb-host-fix-usb_host_speed_compat-tyops.patch b/0010-usb-host-fix-usb_host_speed_compat-tyops.patch
index 801306b..37ea3d3 100644
--- a/0010-usb-host-fix-usb_host_speed_compat-tyops.patch
+++ b/0010-usb-host-fix-usb_host_speed_compat-tyops.patch
@@ -1,7 +1,6 @@
-From 05c1cce68ef4eea1337f5d415f3b98a2f2283931 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon, 10 Nov 2014 12:14:22 +0100
-Subject: [PATCH 10/11] usb-host: fix usb_host_speed_compat tyops
+Subject: [PATCH] usb-host: fix usb_host_speed_compat tyops
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Reviewed-by: Gonglei <arei.gonglei at huawei.com>
@@ -31,6 +30,3 @@ index c189147..69213e9 100644
}
}
---
-2.1.0
-
diff --git a/0011-block-Fix-max-nb_sectors-in-bdrv_make_zero.patch b/0011-block-Fix-max-nb_sectors-in-bdrv_make_zero.patch
deleted file mode 100644
index 3eedd00..0000000
--- a/0011-block-Fix-max-nb_sectors-in-bdrv_make_zero.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From a7cb55181edfc1e328027916e54d873c7eb85421 Mon Sep 17 00:00:00 2001
-From: Fam Zheng <famz at redhat.com>
-Date: Mon, 10 Nov 2014 15:07:44 +0800
-Subject: [PATCH 11/11] block: Fix max nb_sectors in bdrv_make_zero
-
-In bdrv_rw_co we report -EINVAL for nb_sectors > INT_MAX /
-BDRV_SECTOR_SIZE, so a caller shouldn't exceed it.
-
-Signed-off-by: Fam Zheng <famz at redhat.com>
-Reviewed-by: Markus Armbruster <armbru at redhat.com>
-Message-id: 1415603264-21497-1-git-send-email-famz at redhat.com
-Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
----
- block.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/block.c b/block.c
-index ed87b7e..8dc841c 100644
---- a/block.c
-+++ b/block.c
-@@ -2834,8 +2834,8 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
- if (nb_sectors <= 0) {
- return 0;
- }
-- if (nb_sectors > INT_MAX) {
-- nb_sectors = INT_MAX;
-+ if (nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
-+ nb_sectors = INT_MAX / BDRV_SECTOR_SIZE;
- }
- ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n);
- if (ret < 0) {
---
-2.1.0
-
diff --git a/0011-ide-Correct-handling-of-malformed-short-PRDTs.patch b/0011-ide-Correct-handling-of-malformed-short-PRDTs.patch
new file mode 100644
index 0000000..6f9a295
--- /dev/null
+++ b/0011-ide-Correct-handling-of-malformed-short-PRDTs.patch
@@ -0,0 +1,335 @@
+From: John Snow <jsnow at redhat.com>
+Date: Fri, 31 Oct 2014 16:03:39 -0400
+Subject: [PATCH] ide: Correct handling of malformed/short PRDTs
+
+This impacts both BMDMA and AHCI HBA interfaces for IDE.
+Currently, we confuse the difference between a PRDT having
+"0 bytes" and a PRDT having "0 complete sectors."
+
+When we receive an incomplete sector, inconsistent error checking
+leads to an infinite loop wherein the call succeeds, but it
+didn't give us enough bytes -- leading us to re-call the
+DMA chain over and over again. This leads to, in the BMDMA case,
+leaked memory for short PRDTs, and infinite loops and resource
+usage in the AHCI case.
+
+The .prepare_buf() callback is reworked to return the number of
+bytes that it successfully prepared. 0 is a valid, non-error
+answer that means the table was empty and described no bytes.
+-1 indicates an error.
+
+Our current implementation uses the io_buffer in IDEState to
+ultimately describe the size of a prepared scatter-gather list.
+Even though the AHCI PRDT/SGList can be as large as 256GiB, the
+AHCI command header limits transactions to just 4GiB. ATA8-ACS3,
+however, defines the largest transaction to be an LBA48 command
+that transfers 65,536 sectors. With a 512 byte sector size, this
+is just 32MiB.
+
+Since our current state structures use the int type to describe
+the size of the buffer, and this state is migrated as int32, we
+are limited to describing 2GiB buffer sizes unless we change the
+migration protocol.
+
+For this reason, this patch begins to unify the assertions in the
+IDE pathways that the scatter-gather list provided by either the
+AHCI PRDT or the PCI BMDMA PRDs can only describe, at a maximum,
+2GiB. This should be resilient enough unless we need a sector
+size that exceeds 32KiB.
+
+Further, the likelihood of any guest operating system actually
+attempting to transfer this much data in a single operation is
+very slim.
+
+To this end, the IDEState variables have been updated to more
+explicitly clarify our maximum supported size. Callers to the
+prepare_buf callback have been reworked to understand the new
+return code, and all versions of the prepare_buf callback have
+been adjusted accordingly.
+
+Lastly, the ahci_populate_sglist helper, relied upon by the
+AHCI implementation of .prepare_buf() as well as the PCI
+implementation of the callback have had overflow assertions
+added to help make clear the reasonings behind the various
+type changes.
+
+[Added %d -> %"PRId64" fix John sent because off_pos changed from int to
+int64_t.
+--Stefan]
+
+Signed-off-by: John Snow <jsnow at redhat.com>
+Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
+Message-id: 1414785819-26209-4-git-send-email-jsnow at redhat.com
+Signed-off-by: Stefan Hajnoczi <stefanha at redhat.com>
+(cherry picked from commit 3251bdcf1c67427d964517053c3d185b46e618e8)
+---
+ hw/ide/ahci.c | 33 ++++++++++++++++++++++++++-------
+ hw/ide/core.c | 10 ++++++++--
+ hw/ide/internal.h | 13 +++++++------
+ hw/ide/macio.c | 7 ++++++-
+ hw/ide/pci.c | 27 +++++++++++++++++++++------
+ 5 files changed, 68 insertions(+), 22 deletions(-)
+
+diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
+index 604152a..9674f5f 100644
+--- a/hw/ide/ahci.c
++++ b/hw/ide/ahci.c
+@@ -645,7 +645,8 @@ static int prdt_tbl_entry_size(const AHCI_SG *tbl)
+ return (le32_to_cpu(tbl->flags_size) & AHCI_PRDT_SIZE_MASK) + 1;
+ }
+
+-static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
++static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
++ int32_t offset)
+ {
+ AHCICmdHdr *cmd = ad->cur_cmd;
+ uint32_t opts = le32_to_cpu(cmd->opts);
+@@ -656,13 +657,21 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
+ uint8_t *prdt;
+ int i;
+ int r = 0;
+- int sum = 0;
++ uint64_t sum = 0;
+ int off_idx = -1;
+- int off_pos = -1;
++ int64_t off_pos = -1;
+ int tbl_entry_size;
+ IDEBus *bus = &ad->port;
+ BusState *qbus = BUS(bus);
+
++ /*
++ * Note: AHCI PRDT can describe up to 256GiB. SATA/ATA only support
++ * transactions of up to 32MiB as of ATA8-ACS3 rev 1b, assuming a
++ * 512 byte sector size. We limit the PRDT in this implementation to
++ * a reasonably large 2GiB, which can accommodate the maximum transfer
++ * request for sector sizes up to 32K.
++ */
++
+ if (!sglist_alloc_hint) {
+ DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
+ return -1;
+@@ -697,7 +706,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
+ }
+ if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {
+ DPRINTF(ad->port_no, "%s: Incorrect offset! "
+- "off_idx: %d, off_pos: %d\n",
++ "off_idx: %d, off_pos: %"PRId64"\n",
+ __func__, off_idx, off_pos);
+ r = -1;
+ goto out;
+@@ -712,6 +721,13 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
+ /* flags_size is zero-based */
+ qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
+ prdt_tbl_entry_size(&tbl[i]));
++ if (sglist->size > INT32_MAX) {
++ error_report("AHCI Physical Region Descriptor Table describes "
++ "more than 2 GiB.\n");
++ qemu_sglist_destroy(sglist);
++ r = -1;
++ goto out;
++ }
+ }
+ }
+
+@@ -1056,16 +1072,19 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s,
+ dma_cb(s, 0);
+ }
+
+-static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
++static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
+ {
+ AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+ IDEState *s = &ad->port.ifs[0];
+
+- ahci_populate_sglist(ad, &s->sg, 0);
++ if (ahci_populate_sglist(ad, &s->sg, 0) == -1) {
++ DPRINTF(ad->port_no, "ahci_dma_prepare_buf failed.\n");
++ return -1;
++ }
+ s->io_buffer_size = s->sg.size;
+
+ DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
+- return s->io_buffer_size != 0;
++ return s->io_buffer_size;
+ }
+
+ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
+diff --git a/hw/ide/core.c b/hw/ide/core.c
+index fa4cafa..50691fc 100644
+--- a/hw/ide/core.c
++++ b/hw/ide/core.c
+@@ -676,10 +676,11 @@ void ide_dma_cb(void *opaque, int ret)
+ n = s->nsector;
+ s->io_buffer_index = 0;
+ s->io_buffer_size = n * 512;
+- if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) {
++ if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) < 512) {
+ /* The PRDs were too short. Reset the Active bit, but don't raise an
+ * interrupt. */
+ s->status = READY_STAT | SEEK_STAT;
++ dma_buf_commit(s);
+ goto eot;
+ }
+
+@@ -2212,6 +2213,11 @@ static int ide_nop_int(IDEDMA *dma, int x)
+ return 0;
+ }
+
++static int32_t ide_nop_int32(IDEDMA *dma, int x)
++{
++ return 0;
++}
++
+ static void ide_nop_restart(void *opaque, int x, RunState y)
+ {
+ }
+@@ -2219,7 +2225,7 @@ static void ide_nop_restart(void *opaque, int x, RunState y)
+ static const IDEDMAOps ide_dma_nop_ops = {
+ .start_dma = ide_nop_start,
+ .start_transfer = ide_nop,
+- .prepare_buf = ide_nop_int,
++ .prepare_buf = ide_nop_int32,
+ .rw_buf = ide_nop_int,
+ .set_unit = ide_nop_int,
+ .add_status = ide_nop_int,
+diff --git a/hw/ide/internal.h b/hw/ide/internal.h
+index 0567a52..b03045b 100644
+--- a/hw/ide/internal.h
++++ b/hw/ide/internal.h
+@@ -322,6 +322,7 @@ typedef void EndTransferFunc(IDEState *);
+ typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockDriverCompletionFunc *);
+ typedef int DMAFunc(IDEDMA *);
+ typedef int DMAIntFunc(IDEDMA *, int);
++typedef int32_t DMAInt32Func(IDEDMA *, int);
+ typedef void DMARestartFunc(void *, int, RunState);
+
+ struct unreported_events {
+@@ -383,7 +384,7 @@ struct IDEState {
+ uint8_t cdrom_changed;
+ int packet_transfer_size;
+ int elementary_transfer_size;
+- int io_buffer_index;
++ int32_t io_buffer_index;
+ int lba;
+ int cd_sector_size;
+ int atapi_dma; /* true if dma is requested for the packet cmd */
+@@ -392,8 +393,8 @@ struct IDEState {
+ struct iovec iov;
+ QEMUIOVector qiov;
+ /* ATA DMA state */
+- int io_buffer_offset;
+- int io_buffer_size;
++ int32_t io_buffer_offset;
++ int32_t io_buffer_size;
+ QEMUSGList sg;
+ /* PIO transfer handling */
+ int req_nb_sectors; /* number of sectors per interrupt */
+@@ -403,8 +404,8 @@ struct IDEState {
+ uint8_t *io_buffer;
+ /* PIO save/restore */
+ int32_t io_buffer_total_len;
+- int cur_io_buffer_offset;
+- int cur_io_buffer_len;
++ int32_t cur_io_buffer_offset;
++ int32_t cur_io_buffer_len;
+ uint8_t end_transfer_fn_idx;
+ QEMUTimer *sector_write_timer; /* only used for win2k install hack */
+ uint32_t irq_count; /* counts IRQs when using win2k install hack */
+@@ -428,7 +429,7 @@ struct IDEState {
+ struct IDEDMAOps {
+ DMAStartFunc *start_dma;
+ DMAFunc *start_transfer;
+- DMAIntFunc *prepare_buf;
++ DMAInt32Func *prepare_buf;
+ DMAIntFunc *rw_buf;
+ DMAIntFunc *set_unit;
+ DMAIntFunc *add_status;
+diff --git a/hw/ide/macio.c b/hw/ide/macio.c
+index c14a1dd..68d88ac 100644
+--- a/hw/ide/macio.c
++++ b/hw/ide/macio.c
+@@ -555,6 +555,11 @@ static int ide_nop_int(IDEDMA *dma, int x)
+ return 0;
+ }
+
++static int32_t ide_nop_int32(IDEDMA *dma, int x)
++{
++ return 0;
++}
++
+ static void ide_nop_restart(void *opaque, int x, RunState y)
+ {
+ }
+@@ -572,7 +577,7 @@ static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
+ static const IDEDMAOps dbdma_ops = {
+ .start_dma = ide_dbdma_start,
+ .start_transfer = ide_nop,
+- .prepare_buf = ide_nop_int,
++ .prepare_buf = ide_nop_int32,
+ .rw_buf = ide_nop_int,
+ .set_unit = ide_nop_int,
+ .add_status = ide_nop_int,
+diff --git a/hw/ide/pci.c b/hw/ide/pci.c
+index 6257a21..6591246 100644
+--- a/hw/ide/pci.c
++++ b/hw/ide/pci.c
+@@ -28,7 +28,7 @@
+ #include <hw/isa/isa.h>
+ #include "block/block.h"
+ #include "sysemu/dma.h"
+-
++#include "qemu/error-report.h"
+ #include <hw/ide/pci.h>
+
+ #define BMDMA_PAGE_SIZE 4096
+@@ -51,8 +51,11 @@ static void bmdma_start_dma(IDEDMA *dma, IDEState *s,
+ }
+ }
+
+-/* return 0 if buffer completed */
+-static int bmdma_prepare_buf(IDEDMA *dma, int is_write)
++/**
++ * Return the number of bytes successfully prepared.
++ * -1 on error.
++ */
++static int32_t bmdma_prepare_buf(IDEDMA *dma, int is_write)
+ {
+ BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+ IDEState *s = bmdma_active_if(bm);
+@@ -70,8 +73,9 @@ static int bmdma_prepare_buf(IDEDMA *dma, int is_write)
+ if (bm->cur_prd_len == 0) {
+ /* end of table (with a fail safe of one page) */
+ if (bm->cur_prd_last ||
+- (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE)
+- return s->io_buffer_size != 0;
++ (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) {
++ return s->io_buffer_size;
++ }
+ pci_dma_read(pci_dev, bm->cur_addr, &prd, 8);
+ bm->cur_addr += 8;
+ prd.addr = le32_to_cpu(prd.addr);
+@@ -86,12 +90,23 @@ static int bmdma_prepare_buf(IDEDMA *dma, int is_write)
+ l = bm->cur_prd_len;
+ if (l > 0) {
+ qemu_sglist_add(&s->sg, bm->cur_prd_addr, l);
++
++ /* Note: We limit the max transfer to be 2GiB.
++ * This should accommodate the largest ATA transaction
++ * for LBA48 (65,536 sectors) and 32K sector sizes. */
++ if (s->sg.size > INT32_MAX) {
++ error_report("IDE: sglist describes more than 2GiB.\n");
++ break;
++ }
+ bm->cur_prd_addr += l;
+ bm->cur_prd_len -= l;
+ s->io_buffer_size += l;
+ }
+ }
+- return 1;
++
++ qemu_sglist_destroy(&s->sg);
++ s->io_buffer_size = 0;
++ return -1;
+ }
+
+ /* return 0 if buffer completed */
diff --git a/0012-cirrus-fix-blit-region-check.patch b/0012-cirrus-fix-blit-region-check.patch
new file mode 100644
index 0000000..8b88e39
--- /dev/null
+++ b/0012-cirrus-fix-blit-region-check.patch
@@ -0,0 +1,122 @@
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 19 Nov 2014 11:37:42 +0100
+Subject: [PATCH] cirrus: fix blit region check
+
+Issues:
+ * Doesn't check pitches correctly in case it is negative.
+ * Doesn't check width at all.
+
+Turn macro into functions while being at it, also factor out the check
+for one region which we then can simply call twice for src + dst.
+
+This is CVE-2014-8106.
+
+Reported-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
+(cherry picked from commit d3532a0db02296e687711b8cdc7791924efccea0)
+---
+ hw/display/cirrus_vga.c | 61 +++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 44 insertions(+), 17 deletions(-)
+
+diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
+index db330e9..44b2b7c 100644
+--- a/hw/display/cirrus_vga.c
++++ b/hw/display/cirrus_vga.c
+@@ -172,20 +172,6 @@
+
+ #define CIRRUS_PNPMMIO_SIZE 0x1000
+
+-#define BLTUNSAFE(s) \
+- ( \
+- ( /* check dst is within bounds */ \
+- (s)->cirrus_blt_height * ABS((s)->cirrus_blt_dstpitch) \
+- + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \
+- (s)->vga.vram_size \
+- ) || \
+- ( /* check src is within bounds */ \
+- (s)->cirrus_blt_height * ABS((s)->cirrus_blt_srcpitch) \
+- + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \
+- (s)->vga.vram_size \
+- ) \
+- )
+-
+ struct CirrusVGAState;
+ typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
+ uint8_t * dst, const uint8_t * src,
+@@ -278,6 +264,46 @@ static void cirrus_update_memory_access(CirrusVGAState *s);
+ *
+ ***************************************/
+
++static bool blit_region_is_unsafe(struct CirrusVGAState *s,
++ int32_t pitch, int32_t addr)
++{
++ if (pitch < 0) {
++ int64_t min = addr
++ + ((int64_t)s->cirrus_blt_height-1) * pitch;
++ int32_t max = addr
++ + s->cirrus_blt_width;
++ if (min < 0 || max >= s->vga.vram_size) {
++ return true;
++ }
++ } else {
++ int64_t max = addr
++ + ((int64_t)s->cirrus_blt_height-1) * pitch
++ + s->cirrus_blt_width;
++ if (max >= s->vga.vram_size) {
++ return true;
++ }
++ }
++ return false;
++}
++
++static bool blit_is_unsafe(struct CirrusVGAState *s)
++{
++ /* should be the case, see cirrus_bitblt_start */
++ assert(s->cirrus_blt_width > 0);
++ assert(s->cirrus_blt_height > 0);
++
++ if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
++ s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
++ return true;
++ }
++ if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
++ s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
++ return true;
++ }
++
++ return false;
++}
++
+ static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
+ uint8_t *dst,const uint8_t *src,
+ int dstpitch,int srcpitch,
+@@ -635,7 +661,7 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
+
+ dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
+
+- if (BLTUNSAFE(s))
++ if (blit_is_unsafe(s))
+ return 0;
+
+ (*s->cirrus_rop) (s, dst, src,
+@@ -653,8 +679,9 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
+ {
+ cirrus_fill_t rop_func;
+
+- if (BLTUNSAFE(s))
++ if (blit_is_unsafe(s)) {
+ return 0;
++ }
+ rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+ rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
+ s->cirrus_blt_dstpitch,
+@@ -751,7 +778,7 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
+
+ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
+ {
+- if (BLTUNSAFE(s))
++ if (blit_is_unsafe(s))
+ return 0;
+
+ cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
diff --git a/0013-cirrus-don-t-overflow-CirrusVGAState-cirrus_bltbuf.patch b/0013-cirrus-don-t-overflow-CirrusVGAState-cirrus_bltbuf.patch
new file mode 100644
index 0000000..ff8301b
--- /dev/null
+++ b/0013-cirrus-don-t-overflow-CirrusVGAState-cirrus_bltbuf.patch
@@ -0,0 +1,27 @@
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 19 Nov 2014 13:27:28 +0100
+Subject: [PATCH] cirrus: don't overflow CirrusVGAState->cirrus_bltbuf
+
+This is CVE-2014-8106.
+
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+(cherry picked from commit bf25983345ca44aec3dd92c57142be45452bd38a)
+---
+ hw/display/cirrus_vga.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
+index 44b2b7c..efa0969 100644
+--- a/hw/display/cirrus_vga.c
++++ b/hw/display/cirrus_vga.c
+@@ -292,6 +292,10 @@ static bool blit_is_unsafe(struct CirrusVGAState *s)
+ assert(s->cirrus_blt_width > 0);
+ assert(s->cirrus_blt_height > 0);
+
++ if (s->cirrus_blt_width > CIRRUS_BLTBUFSIZE) {
++ return true;
++ }
++
+ if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
+ s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
+ return true;
diff --git a/0014-block-vdi-Add-locking-for-parallel-requests.patch b/0014-block-vdi-Add-locking-for-parallel-requests.patch
new file mode 100644
index 0000000..168d816
--- /dev/null
+++ b/0014-block-vdi-Add-locking-for-parallel-requests.patch
@@ -0,0 +1,84 @@
+From: Max Reitz <mreitz at redhat.com>
+Date: Fri, 27 Feb 2015 14:54:39 -0500
+Subject: [PATCH] block/vdi: Add locking for parallel requests
+
+When allocating a new cluster, the first write to it must be the one
+doing the allocation, because that one pads its write request to the
+cluster size; if another write to that cluster is executed before it,
+that write will be overwritten due to the padding.
+
+See https://bugs.launchpad.net/qemu/+bug/1422307 for what can go wrong
+without this patch.
+
+Cc: qemu-stable <qemu-stable at nongnu.org>
+Signed-off-by: Max Reitz <mreitz at redhat.com>
+Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com>
+Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Kevin Wolf <kwolf at redhat.com>
+(cherry picked from commit f0ab6f109630940146cbaf47d0cd99993ddba824)
+---
+ block/vdi.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+diff --git a/block/vdi.c b/block/vdi.c
+index 197bd77..4bfb510 100644
+--- a/block/vdi.c
++++ b/block/vdi.c
+@@ -53,6 +53,7 @@
+ #include "block/block_int.h"
+ #include "qemu/module.h"
+ #include "migration/migration.h"
++#include "block/coroutine.h"
+ #ifdef __linux__
+ #include <linux/fs.h>
+ #include <sys/ioctl.h>
+@@ -191,6 +192,8 @@ typedef struct {
+ /* VDI header (converted to host endianness). */
+ VdiHeader header;
+
++ CoMutex write_lock;
++
+ Error *migration_blocker;
+ } BDRVVdiState;
+
+@@ -490,6 +493,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
+ "vdi", bs->device_name, "live migration");
+ migrate_add_blocker(s->migration_blocker);
+
++ qemu_co_mutex_init(&s->write_lock);
++
+ return 0;
+
+ fail_free_bmap:
+@@ -625,11 +630,31 @@ static int vdi_co_write(BlockDriverState *bs,
+ buf, n_sectors * SECTOR_SIZE);
+ memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
+ (s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
++
++ /* Note that this coroutine does not yield anywhere from reading the
++ * bmap entry until here, so in regards to all the coroutines trying
++ * to write to this cluster, the one doing the allocation will
++ * always be the first to try to acquire the lock.
++ * Therefore, it is also the first that will actually be able to
++ * acquire the lock and thus the padded cluster is written before
++ * the other coroutines can write to the affected area. */
++ qemu_co_mutex_lock(&s->write_lock);
+ ret = bdrv_write(bs->file, offset, block, s->block_sectors);
++ qemu_co_mutex_unlock(&s->write_lock);
+ } else {
+ uint64_t offset = s->header.offset_data / SECTOR_SIZE +
+ (uint64_t)bmap_entry * s->block_sectors +
+ sector_in_block;
++ qemu_co_mutex_lock(&s->write_lock);
++ /* This lock is only used to make sure the following write operation
++ * is executed after the write issued by the coroutine allocating
++ * this cluster, therefore we do not need to keep it locked.
++ * As stated above, the allocating coroutine will always try to lock
++ * the mutex before all the other concurrent accesses to that
++ * cluster, therefore at this point we can be absolutely certain
++ * that that write operation has returned (there may be other writes
++ * in flight, but they do not concern this very operation). */
++ qemu_co_mutex_unlock(&s->write_lock);
+ ret = bdrv_write(bs->file, offset, buf, n_sectors);
+ }
+
diff --git a/qemu.spec b/qemu.spec
index cdd30d5..3d1de4c 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -152,7 +152,7 @@
Summary: QEMU is a FAST! processor emulator
Name: qemu
Version: 2.1.3
-Release: 3%{?dist}
+Release: 4%{?dist}
Epoch: 2
License: GPLv2+ and LGPLv2+ and BSD
Group: Development/Tools
@@ -207,8 +207,14 @@ Patch0008: 0008-block-raw-posix-Fix-disk-corruption-in-try_fiemap.patch
Patch0009: 0009-block-raw-posix-use-seek_hole-ahead-of-fiemap.patch
# Fix USB host assignment (bz #1187749)
Patch0010: 0010-usb-host-fix-usb_host_speed_compat-tyops.patch
-# Fix qemu-img error (bz #1200043)
-Patch0011: 0011-block-Fix-max-nb_sectors-in-bdrv_make_zero.patch
+# Qemu: PRDT overflow from guest to host (bz #1204919, bz #1205322)
+Patch0011: 0011-ide-Correct-handling-of-malformed-short-PRDTs.patch
+# CVE-2014-8106: cirrus: insufficient blit region checks (bz #1170612,
+# bz #1169454)
+Patch0012: 0012-cirrus-fix-blit-region-check.patch
+Patch0013: 0013-cirrus-don-t-overflow-CirrusVGAState-cirrus_bltbuf.patch
+# Fix .vdi disk corruption (bz #1199400)
+Patch0014: 0014-block-vdi-Add-locking-for-parallel-requests.patch
BuildRequires: SDL2-devel
BuildRequires: zlib-devel
@@ -750,8 +756,14 @@ CAC emulation development files.
%patch0009 -p1
# Fix USB host assignment (bz #1187749)
%patch0010 -p1
-# Fix qemu-img error (bz #1200043)
+# Qemu: PRDT overflow from guest to host (bz #1204919, bz #1205322)
%patch0011 -p1
+# CVE-2014-8106: cirrus: insufficient blit region checks (bz #1170612,
+# bz #1169454)
+%patch0012 -p1
+%patch0013 -p1
+# Fix .vdi disk corruption (bz #1199400)
+%patch0014 -p1
%build
@@ -864,11 +876,11 @@ if [ -x "$b" ]; then "$b" -help; fi
%define _udevdir /lib/udev/rules.d
-install -D -p -m 0744 %{SOURCE4} $RPM_BUILD_ROOT/lib/systemd/system/ksm.service
+install -D -p -m 0644 %{SOURCE4} $RPM_BUILD_ROOT/lib/systemd/system/ksm.service
install -D -p -m 0644 %{SOURCE5} $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/ksm
install -D -p -m 0755 ksmctl $RPM_BUILD_ROOT/lib/systemd/ksmctl
-install -D -p -m 0744 %{SOURCE7} $RPM_BUILD_ROOT/lib/systemd/system/ksmtuned.service
+install -D -p -m 0644 %{SOURCE7} $RPM_BUILD_ROOT/lib/systemd/system/ksmtuned.service
install -D -p -m 0755 %{SOURCE8} $RPM_BUILD_ROOT%{_sbindir}/ksmtuned
install -D -p -m 0644 %{SOURCE9} $RPM_BUILD_ROOT%{_sysconfdir}/ksmtuned.conf
@@ -1532,6 +1544,13 @@ getent passwd qemu >/dev/null || \
%endif
%changelog
+* Fri Mar 27 2015 Cole Robinson <crobinso at redhat.com> - 2:2.1.3-4
+- Qemu: PRDT overflow from guest to host (bz #1204919, bz #1205322)
+- CVE-2014-8106: cirrus: insufficient blit region checks (bz #1170612, bz
+ #1169454)
+- Fix .vdi disk corruption (bz #1199400)
+- Don't install ksm services as executable (bz #1192720)
+
* Tue Mar 10 2015 Haïkel Guémar <hguemar at fedoraproject.org> - 2:2.1.3-3
- Backport upstream patch fixing some qemu-img conversion errors (RHBZ#1200043)
--
cgit v0.10.2
http://pkgs.fedoraproject.org/cgit/qemu.git/commit/?h=f21&id=29e31e320f42ace6782d16ddf552d3540b28a9c3
More information about the scm-commits
mailing list