Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a48950cf39 | ||
|
a1c144d276 | ||
|
c700dd0ffc | ||
|
f4055dd206 | ||
|
7925752085 | ||
|
56715e285b | ||
|
1369de9828 | ||
|
87dd0b268a | ||
|
d9094d4c0b | ||
|
f182f276c2 | ||
|
f602c82d48 | ||
|
e976b467c3 | ||
|
7452f5d212 | ||
|
0d3567f1ae | ||
|
f3a92caa76 | ||
|
2e55f16ca5 | ||
|
05010a02f4 | ||
|
3fa1863e91 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -24,3 +24,4 @@ qemu-kvm-0.13.0-25fdf4a.tar.gz
|
||||
/qemu-1.5.2.tar.bz2
|
||||
/qemu-1.6.0.tar.bz2
|
||||
/qemu-1.6.1.tar.bz2
|
||||
/qemu-1.6.2.tar.bz2
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 2196426a9b081cb99f4bdefb854aaa206bdd0392 Mon Sep 17 00:00:00 2001
|
||||
From: Cole Robinson <crobinso@redhat.com>
|
||||
Date: Fri, 16 Aug 2013 12:14:51 -0400
|
||||
Subject: [PATCH] Fix migration from qemu-kvm
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 85a924af30f31a4f701ee6f18d84dd27aa02f47b Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Tue, 13 Aug 2013 00:02:18 +0200
|
||||
Subject: [PATCH] isapc: disable kvmvapic
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 07873f45017c04994496d8dc3f7acb60358bba49 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Thu, 2 May 2013 11:38:37 +0200
|
||||
Subject: [PATCH] pci: do not export pci_bus_reset
|
||||
@ -19,10 +18,10 @@ Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
3 files changed, 3 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
|
||||
index 4c004f5..0389375 100644
|
||||
index dc5b788..3a0c4a7 100644
|
||||
--- a/hw/pci/pci.c
|
||||
+++ b/hw/pci/pci.c
|
||||
@@ -210,8 +210,9 @@ void pci_device_reset(PCIDevice *dev)
|
||||
@@ -212,8 +212,9 @@ void pci_device_reset(PCIDevice *dev)
|
||||
* Trigger pci bus reset under a given bus.
|
||||
* To be called on RST# assert.
|
||||
*/
|
||||
@ -33,7 +32,7 @@ index 4c004f5..0389375 100644
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bus->nirq; i++) {
|
||||
@@ -222,11 +223,6 @@ void pci_bus_reset(PCIBus *bus)
|
||||
@@ -224,11 +225,6 @@ void pci_bus_reset(PCIBus *bus)
|
||||
pci_device_reset(bus->devices[i]);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
From cf09bc533d82f2b16d1e9f4888c1afd977ca256d Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Thu, 2 May 2013 11:38:38 +0200
|
||||
Subject: [PATCH] qdev: allow both pre- and post-order vists in qdev walking
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 41a2077cea8ce006dbef885bcb0778af05a0b159 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Thu, 2 May 2013 11:38:39 +0200
|
||||
Subject: [PATCH] qdev: switch reset to post-order
|
||||
@ -59,7 +58,7 @@ index 842804f..87d7e1e 100644
|
||||
|
||||
void qbus_reset_all_fn(void *opaque)
|
||||
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
|
||||
index 0389375..bbca696 100644
|
||||
index 3a0c4a7..129cdb7 100644
|
||||
--- a/hw/pci/pci.c
|
||||
+++ b/hw/pci/pci.c
|
||||
@@ -46,7 +46,7 @@
|
||||
@ -68,10 +67,10 @@ index 0389375..bbca696 100644
|
||||
static char *pcibus_get_fw_dev_path(DeviceState *dev);
|
||||
-static int pcibus_reset(BusState *qbus);
|
||||
+static void pcibus_reset(BusState *qbus);
|
||||
static void pci_bus_finalize(Object *obj);
|
||||
|
||||
static Property pci_props[] = {
|
||||
DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
|
||||
@@ -165,16 +165,10 @@ void pci_device_deassert_intx(PCIDevice *dev)
|
||||
@@ -167,16 +167,10 @@ void pci_device_deassert_intx(PCIDevice *dev)
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +88,7 @@ index 0389375..bbca696 100644
|
||||
dev->irq_state = 0;
|
||||
pci_update_irq_status(dev);
|
||||
pci_device_deassert_intx(dev);
|
||||
@@ -207,10 +201,21 @@ void pci_device_reset(PCIDevice *dev)
|
||||
@@ -209,10 +203,21 @@ void pci_device_reset(PCIDevice *dev)
|
||||
}
|
||||
|
||||
/*
|
||||
@ -113,7 +112,7 @@ index 0389375..bbca696 100644
|
||||
{
|
||||
PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus);
|
||||
int i;
|
||||
@@ -220,13 +225,9 @@ static int pcibus_reset(BusState *qbus)
|
||||
@@ -222,13 +227,9 @@ static int pcibus_reset(BusState *qbus)
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
|
||||
if (bus->devices[i]) {
|
||||
|
@ -1,4 +1,3 @@
|
||||
From ed35f9edcc420b4f8c1f909bc7cfb002a54f437b Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:57:50 +0200
|
||||
Subject: [PATCH] virtio-bus: remove vdev field
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 1d388b4fda2c4c9d00dc6ae91aaf35eb9fc04c26 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:57:51 +0200
|
||||
Subject: [PATCH] virtio-pci: remove vdev field
|
||||
|
@ -1,4 +1,3 @@
|
||||
From a9b1f1aeba8167ae90aecea9b8ca223faf33ae90 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:57:52 +0200
|
||||
Subject: [PATCH] virtio-ccw: remove vdev field
|
||||
|
@ -1,4 +1,3 @@
|
||||
From fe02fcc2b929e6a678ec783cb80890b79b7dca78 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:57:53 +0200
|
||||
Subject: [PATCH] virtio-bus: cleanup plug/unplug interface
|
||||
|
@ -1,4 +1,3 @@
|
||||
From aa75555e6fb5cae0e495cb5f7d9f3511ad5ac6ce Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:57:54 +0200
|
||||
Subject: [PATCH] virtio-blk: switch exit callback to VirtioDeviceClass
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 811b51426d9e7819e6498d4dad0d6ac744a8e5d0 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:57:55 +0200
|
||||
Subject: [PATCH] virtio-serial: switch exit callback to VirtioDeviceClass
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 1582699fb9f748f9f91b015ef311f93bf5a95f5d Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:57:56 +0200
|
||||
Subject: [PATCH] virtio-net: switch exit callback to VirtioDeviceClass
|
||||
@ -12,7 +11,7 @@ Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
1 file changed, 4 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
|
||||
index aa1880c..46a4d8c 100644
|
||||
index 5320aab..060b900 100644
|
||||
--- a/hw/net/virtio-net.c
|
||||
+++ b/hw/net/virtio-net.c
|
||||
@@ -1568,16 +1568,15 @@ static int virtio_net_device_init(VirtIODevice *vdev)
|
||||
|
@ -1,4 +1,3 @@
|
||||
From df750f462929ba85a61dbdd6a4020cb4b2ee68d0 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:57:57 +0200
|
||||
Subject: [PATCH] virtio-scsi: switch exit callback to VirtioDeviceClass
|
||||
|
@ -1,4 +1,3 @@
|
||||
From d42ac36363ef9e3d3963c2c31fa7122492dbaf0e Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:57:58 +0200
|
||||
Subject: [PATCH] virtio-balloon: switch exit callback to VirtioDeviceClass
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 2bb10b85ffa655f91a4777da4f7a5534ee4c266c Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:57:59 +0200
|
||||
Subject: [PATCH] virtio-rng: switch exit callback to VirtioDeviceClass
|
||||
|
@ -1,4 +1,3 @@
|
||||
From cb2282d55ee34d04a67d74111d69ab098f765680 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Fri, 20 Sep 2013 16:58:00 +0200
|
||||
Subject: [PATCH] virtio-pci: add device_unplugged callback
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 411a7e4ad457f7f3c9f1d02ef9f726ce13a35f08 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Fri, 6 Sep 2013 12:32:25 +0200
|
||||
Subject: [PATCH] qcow2: Pass discard type to qcow2_discard_clusters()
|
||||
@ -14,10 +13,10 @@ Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
3 files changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
|
||||
index cca76d4..8c3185d 100644
|
||||
index b558eb0..09abbf0 100644
|
||||
--- a/block/qcow2-cluster.c
|
||||
+++ b/block/qcow2-cluster.c
|
||||
@@ -1317,7 +1317,7 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
||||
@@ -1320,7 +1320,7 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
||||
* clusters.
|
||||
*/
|
||||
static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
@ -26,7 +25,7 @@ index cca76d4..8c3185d 100644
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t *l2_table;
|
||||
@@ -1346,7 +1346,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
@@ -1349,7 +1349,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
l2_table[l2_index + i] = cpu_to_be64(0);
|
||||
|
||||
/* Then decrease the refcount */
|
||||
@ -35,7 +34,7 @@ index cca76d4..8c3185d 100644
|
||||
}
|
||||
|
||||
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||
@@ -1358,7 +1358,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
@@ -1361,7 +1361,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
}
|
||||
|
||||
int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
||||
@ -44,7 +43,7 @@ index cca76d4..8c3185d 100644
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t end_offset;
|
||||
@@ -1381,7 +1381,7 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
||||
@@ -1384,7 +1384,7 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
/* Each L2 table is handled by its own loop iteration */
|
||||
while (nb_clusters > 0) {
|
||||
@ -54,10 +53,10 @@ index cca76d4..8c3185d 100644
|
||||
goto fail;
|
||||
}
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index 7f7282e..16e45a0 100644
|
||||
index 3bf932b..f87e6e3 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -1506,7 +1506,7 @@ static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
|
||||
@@ -1510,7 +1510,7 @@ static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
|
||||
|
||||
qemu_co_mutex_lock(&s->lock);
|
||||
ret = qcow2_discard_clusters(bs, sector_num << BDRV_SECTOR_BITS,
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 16d78f7cd9e1455ebb0599706ba5badfa3ee4fdc Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Fri, 6 Sep 2013 12:32:26 +0200
|
||||
Subject: [PATCH] qcow2: Discard VM state in active L1 after creating snapshot
|
||||
@ -40,10 +39,10 @@ index 0caac90..ae33b45 100644
|
||||
{
|
||||
BdrvCheckResult result = {0};
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index 16e45a0..f63c2cb 100644
|
||||
index f87e6e3..44161b2 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -1666,11 +1666,6 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
|
||||
@@ -1670,11 +1670,6 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
From 6f7e1d2bddb5a0a1c65f6f02467460d6edbcc901 Mon Sep 17 00:00:00 2001
|
||||
From: "Daniel P. Berrange" <berrange@redhat.com>
|
||||
Date: Tue, 1 Oct 2013 12:28:17 +0100
|
||||
Subject: [PATCH] hw/9pfs: Fix errno value for xattr functions
|
||||
|
@ -1,203 +0,0 @@
|
||||
From 042c76790b1168766332b1aafa4429c265d35ed0 Mon Sep 17 00:00:00 2001
|
||||
From: Cole Robinson <crobinso@redhat.com>
|
||||
Date: Mon, 7 Oct 2013 16:32:24 -0400
|
||||
Subject: [PATCH] Fix pc migration from qemu <= 1.5
|
||||
|
||||
The following commit introduced a migration incompatibility:
|
||||
|
||||
commit 568f0690fd9aa4d39d84b04c1a5dbb53a915c3fe
|
||||
Author: David Gibson <david@gibson.dropbear.id.au>
|
||||
Date: Thu Jun 6 18:48:49 2013 +1000
|
||||
|
||||
pci: Replace pci_find_domain() with more general pci_root_bus_path()
|
||||
|
||||
The issue is that i440fx savevm idstr went from 0000:00:00.0/I440FX to
|
||||
0000:00.0/I440FX. Unfortunately we are stuck with the breakage for
|
||||
1.6 machine types.
|
||||
|
||||
Add a compat property to maintain the busted idstr for the 1.6 machine
|
||||
types, but revert to the old style format for 1.7+, and <= 1.5.
|
||||
|
||||
Tested with migration from qemu 1.5, qemu 1.6, and qemu.git.
|
||||
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Signed-off-by: Cole Robinson <crobinso@redhat.com>
|
||||
---
|
||||
hw/i386/pc_piix.c | 11 +++++++++++
|
||||
hw/i386/pc_q35.c | 11 +++++++++++
|
||||
hw/pci-host/piix.c | 9 ++++++++-
|
||||
hw/pci-host/q35.c | 10 ++++++++--
|
||||
include/hw/i386/pc.h | 20 ++++++++++++++++++++
|
||||
include/hw/pci-host/q35.h | 1 +
|
||||
6 files changed, 59 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
|
||||
index 2f2cb4d..10866f5 100644
|
||||
--- a/hw/i386/pc_piix.c
|
||||
+++ b/hw/i386/pc_piix.c
|
||||
@@ -341,6 +341,13 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
|
||||
}
|
||||
#endif
|
||||
|
||||
+#define PC_I440FX_MACHINE_OPTIONS \
|
||||
+ PC_DEFAULT_MACHINE_OPTIONS, \
|
||||
+ .desc = "Standard PC (i440FX + PIIX, 1996)", \
|
||||
+ .hot_add_cpu = pc_hot_add_cpu
|
||||
+
|
||||
+#define PC_I440FX_1_6_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
|
||||
+
|
||||
static QEMUMachine pc_i440fx_machine_v1_6 = {
|
||||
.name = "pc-i440fx-1.6",
|
||||
.alias = "pc",
|
||||
@@ -349,6 +356,10 @@ static QEMUMachine pc_i440fx_machine_v1_6 = {
|
||||
.hot_add_cpu = pc_hot_add_cpu,
|
||||
.max_cpus = 255,
|
||||
.is_default = 1,
|
||||
+ .compat_props = (GlobalProperty[]) {
|
||||
+ PC_COMPAT_1_6,
|
||||
+ { /* end of list */ }
|
||||
+ },
|
||||
DEFAULT_MACHINE_OPTIONS,
|
||||
};
|
||||
|
||||
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
|
||||
index dd13130..4998ed3 100644
|
||||
--- a/hw/i386/pc_q35.c
|
||||
+++ b/hw/i386/pc_q35.c
|
||||
@@ -243,6 +243,13 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
|
||||
pc_q35_init(args);
|
||||
}
|
||||
|
||||
+#define PC_Q35_MACHINE_OPTIONS \
|
||||
+ PC_DEFAULT_MACHINE_OPTIONS, \
|
||||
+ .desc = "Standard PC (Q35 + ICH9, 2009)", \
|
||||
+ .hot_add_cpu = pc_hot_add_cpu
|
||||
+
|
||||
+#define PC_Q35_1_6_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
|
||||
+
|
||||
static QEMUMachine pc_q35_machine_v1_6 = {
|
||||
.name = "pc-q35-1.6",
|
||||
.alias = "q35",
|
||||
@@ -250,6 +257,10 @@ static QEMUMachine pc_q35_machine_v1_6 = {
|
||||
.init = pc_q35_init_1_6,
|
||||
.hot_add_cpu = pc_hot_add_cpu,
|
||||
.max_cpus = 255,
|
||||
+ .compat_props = (GlobalProperty[]) {
|
||||
+ PC_COMPAT_1_6,
|
||||
+ { /* end of list */ }
|
||||
+ },
|
||||
DEFAULT_MACHINE_OPTIONS,
|
||||
};
|
||||
|
||||
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
|
||||
index 221d82b..967f949 100644
|
||||
--- a/hw/pci-host/piix.c
|
||||
+++ b/hw/pci-host/piix.c
|
||||
@@ -48,6 +48,7 @@ typedef struct I440FXState {
|
||||
PCIHostState parent_obj;
|
||||
PcPciInfo pci_info;
|
||||
uint64_t pci_hole64_size;
|
||||
+ uint32_t short_root_bus;
|
||||
} I440FXState;
|
||||
|
||||
#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */
|
||||
@@ -706,13 +707,19 @@ static const TypeInfo i440fx_info = {
|
||||
static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
|
||||
PCIBus *rootbus)
|
||||
{
|
||||
+ I440FXState *s = I440FX_PCI_HOST_BRIDGE(host_bridge);
|
||||
+
|
||||
/* For backwards compat with old device paths */
|
||||
- return "0000";
|
||||
+ if (s->short_root_bus) {
|
||||
+ return "0000";
|
||||
+ }
|
||||
+ return "0000:00";
|
||||
}
|
||||
|
||||
static Property i440fx_props[] = {
|
||||
DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, I440FXState,
|
||||
pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE),
|
||||
+ DEFINE_PROP_UINT32("short_root_bus", I440FXState, short_root_bus, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
|
||||
index 4febd24..f762053 100644
|
||||
--- a/hw/pci-host/q35.c
|
||||
+++ b/hw/pci-host/q35.c
|
||||
@@ -61,8 +61,13 @@ static void q35_host_realize(DeviceState *dev, Error **errp)
|
||||
static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
|
||||
PCIBus *rootbus)
|
||||
{
|
||||
- /* For backwards compat with old device paths */
|
||||
- return "0000";
|
||||
+ Q35PCIHost *s = Q35_HOST_DEVICE(host_bridge);
|
||||
+
|
||||
+ /* For backwards compat with old device paths */
|
||||
+ if (s->mch.short_root_bus) {
|
||||
+ return "0000";
|
||||
+ }
|
||||
+ return "0000:00";
|
||||
}
|
||||
|
||||
static void q35_host_get_pci_hole_start(Object *obj, Visitor *v,
|
||||
@@ -108,6 +113,7 @@ static Property mch_props[] = {
|
||||
MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
|
||||
DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, Q35PCIHost,
|
||||
mch.pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE),
|
||||
+ DEFINE_PROP_UINT32("short_root_bus", Q35PCIHost, mch.short_root_bus, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
|
||||
index 475ba9e..6e2b839 100644
|
||||
--- a/include/hw/i386/pc.h
|
||||
+++ b/include/hw/i386/pc.h
|
||||
@@ -225,7 +225,19 @@ void pvpanic_init(ISABus *bus);
|
||||
|
||||
int e820_add_entry(uint64_t, uint64_t, uint32_t);
|
||||
|
||||
+#define PC_COMPAT_1_6 \
|
||||
+ {\
|
||||
+ .driver = "i440FX-pcihost",\
|
||||
+ .property = "short_root_bus",\
|
||||
+ .value = stringify(1),\
|
||||
+ },{\
|
||||
+ .driver = "q35-pcihost",\
|
||||
+ .property = "short_root_bus",\
|
||||
+ .value = stringify(1),\
|
||||
+ }
|
||||
+
|
||||
#define PC_COMPAT_1_5 \
|
||||
+ PC_COMPAT_1_6, \
|
||||
{\
|
||||
.driver = "Conroe-" TYPE_X86_CPU,\
|
||||
.property = "model",\
|
||||
@@ -258,6 +270,14 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
|
||||
.driver = TYPE_X86_CPU,\
|
||||
.property = "pmu",\
|
||||
.value = "on",\
|
||||
+ },{\
|
||||
+ .driver = "i440FX-pcihost",\
|
||||
+ .property = "short_root_bus",\
|
||||
+ .value = stringify(0),\
|
||||
+ },{\
|
||||
+ .driver = "q35-pcihost",\
|
||||
+ .property = "short_root_bus",\
|
||||
+ .value = stringify(0),\
|
||||
}
|
||||
|
||||
#define PC_COMPAT_1_4 \
|
||||
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
|
||||
index 6eb7ab6..95a3cc2 100644
|
||||
--- a/include/hw/pci-host/q35.h
|
||||
+++ b/include/hw/pci-host/q35.h
|
||||
@@ -61,6 +61,7 @@ typedef struct MCHPCIState {
|
||||
ram_addr_t above_4g_mem_size;
|
||||
uint64_t pci_hole64_size;
|
||||
PcGuestInfo *guest_info;
|
||||
+ uint32_t short_root_bus;
|
||||
} MCHPCIState;
|
||||
|
||||
typedef struct Q35PCIHost {
|
@ -1,4 +1,3 @@
|
||||
From dd733d7097c126ee3b8ee8a0f4c38b8ccac76504 Mon Sep 17 00:00:00 2001
|
||||
From: Amos Kong <akong@redhat.com>
|
||||
Date: Fri, 15 Nov 2013 18:53:14 +0100
|
||||
Subject: [PATCH] qmp: access the local QemuOptsLists for drive option
|
@ -1,42 +0,0 @@
|
||||
From 6b7ac46a461482c06c5ccdf54815e94205bc7d95 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Wed, 9 Oct 2013 21:33:44 +0200
|
||||
Subject: [PATCH] audio: honor QEMU_AUDIO_TIMER_PERIOD instead of waking up
|
||||
every *nano* second
|
||||
|
||||
Now that we no longer have MIN_REARM_TIMER_NS a bug in the audio subsys has
|
||||
clearly shown it self by trying to make a timer fire every nano second.
|
||||
|
||||
Note we have a similar problem in 1.6, 1.5 and older but there
|
||||
MIN_REARM_TIMER_NS limits the wakeups caused by audio being active to
|
||||
4000 times / second. This still causes a host cpu load of 50 % for simply
|
||||
playing audio, where as with this patch git master is at 13%, so we should
|
||||
backport this to 1.5 and 1.6 too.
|
||||
|
||||
Note this will not apply to 1.5 and 1.6 as is.
|
||||
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
(cherry picked from commit b4350deed67b95651896ddb60cf9f765093a4848)
|
||||
|
||||
Conflicts:
|
||||
audio/audio.c
|
||||
---
|
||||
audio/audio.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/audio/audio.c b/audio/audio.c
|
||||
index 02bb886..f9b3e95 100644
|
||||
--- a/audio/audio.c
|
||||
+++ b/audio/audio.c
|
||||
@@ -1124,7 +1124,8 @@ static int audio_is_timer_needed (void)
|
||||
static void audio_reset_timer (AudioState *s)
|
||||
{
|
||||
if (audio_is_timer_needed ()) {
|
||||
- qemu_mod_timer (s->ts, qemu_get_clock_ns (vm_clock) + 1);
|
||||
+ qemu_mod_timer (s->ts,
|
||||
+ qemu_get_clock_ns (vm_clock) + conf.period.ticks);
|
||||
}
|
||||
else {
|
||||
qemu_del_timer (s->ts);
|
@ -1,4 +1,3 @@
|
||||
From aafda3de0ce3589fa69472bd4a1782c65c8c7ade Mon Sep 17 00:00:00 2001
|
||||
From: Eduardo Otubo <otubo@linux.vnet.ibm.com>
|
||||
Date: Tue, 24 Sep 2013 14:50:44 -0300
|
||||
Subject: [PATCH] seccomp: fine tuning whitelist by adding times()
|
||||
@ -15,7 +14,7 @@ Acked-by: Paul Moore <pmoore@redhat.com>
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/qemu-seccomp.c b/qemu-seccomp.c
|
||||
index 37d38f8..69cee44 100644
|
||||
index fb3cbfd..cf07869 100644
|
||||
--- a/qemu-seccomp.c
|
||||
+++ b/qemu-seccomp.c
|
||||
@@ -90,6 +90,7 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = {
|
32
0106-spice-flip-streaming-video-mode-to-off-by-default.patch
Normal file
32
0106-spice-flip-streaming-video-mode-to-off-by-default.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Mon, 2 Dec 2013 11:17:04 +0100
|
||||
Subject: [PATCH] spice: flip streaming video mode to off by default
|
||||
|
||||
Video streaming detection heuristics in spice-server have problems
|
||||
keeping modern desktop animations (as done by gnome shell) and real
|
||||
video playback apart. This leads to jpeg compression artefacts on
|
||||
your desktop, due to spice using mjpeg to send what it thinks is
|
||||
a video stream.
|
||||
|
||||
Turn off video detection by default to avoid these artifacts.
|
||||
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Reviewed-by: Alon Levy <alevy@redhat.com>
|
||||
(cherry picked from commit f1d3e586f069e17f83b669842bc02d60d509daca)
|
||||
---
|
||||
ui/spice-core.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/ui/spice-core.c b/ui/spice-core.c
|
||||
index bd7a248..3960fa0 100644
|
||||
--- a/ui/spice-core.c
|
||||
+++ b/ui/spice-core.c
|
||||
@@ -778,6 +778,8 @@ void qemu_spice_init(void)
|
||||
if (str) {
|
||||
int streaming_video = parse_stream_video(str);
|
||||
spice_server_set_streaming_video(spice_server, streaming_video);
|
||||
+ } else {
|
||||
+ spice_server_set_streaming_video(spice_server, SPICE_STREAM_VIDEO_OFF);
|
||||
}
|
||||
|
||||
spice_server_set_agent_mouse
|
@ -0,0 +1,58 @@
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Thu, 28 Nov 2013 11:01:13 +0100
|
||||
Subject: [PATCH] scsi-bus: fix transfer length and direction for VERIFY
|
||||
command
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The amount of bytes to transfer depends on the BYTCHK field.
|
||||
If any data is transferred, it is sent to the device.
|
||||
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Tested-by: Hervé Poussineau <hpoussin@reactos.org>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
(cherry picked from commit d12ad44cc4cc9142179e64295608611f118b8ad8)
|
||||
---
|
||||
hw/scsi/scsi-bus.c | 14 +++++++++++++-
|
||||
1 file changed, 13 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
|
||||
index d352da7..e2fcd60 100644
|
||||
--- a/hw/scsi/scsi-bus.c
|
||||
+++ b/hw/scsi/scsi-bus.c
|
||||
@@ -886,7 +886,6 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case RELEASE:
|
||||
case ERASE:
|
||||
case ALLOW_MEDIUM_REMOVAL:
|
||||
- case VERIFY_10:
|
||||
case SEEK_10:
|
||||
case SYNCHRONIZE_CACHE:
|
||||
case SYNCHRONIZE_CACHE_16:
|
||||
@@ -903,6 +902,16 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
||||
case ALLOW_OVERWRITE:
|
||||
cmd->xfer = 0;
|
||||
break;
|
||||
+ case VERIFY_10:
|
||||
+ case VERIFY_12:
|
||||
+ case VERIFY_16:
|
||||
+ if ((buf[1] & 2) == 0) {
|
||||
+ cmd->xfer = 0;
|
||||
+ } else if ((buf[1] & 4) == 1) {
|
||||
+ cmd->xfer = 1;
|
||||
+ }
|
||||
+ cmd->xfer *= dev->blocksize;
|
||||
+ break;
|
||||
case MODE_SENSE:
|
||||
break;
|
||||
case WRITE_SAME_10:
|
||||
@@ -1100,6 +1109,9 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
|
||||
case WRITE_VERIFY_12:
|
||||
case WRITE_16:
|
||||
case WRITE_VERIFY_16:
|
||||
+ case VERIFY_10:
|
||||
+ case VERIFY_12:
|
||||
+ case VERIFY_16:
|
||||
case COPY:
|
||||
case COPY_VERIFY:
|
||||
case COMPARE:
|
89
0108-scsi-disk-fix-VERIFY-emulation.patch
Normal file
89
0108-scsi-disk-fix-VERIFY-emulation.patch
Normal file
@ -0,0 +1,89 @@
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Thu, 28 Nov 2013 11:18:56 +0100
|
||||
Subject: [PATCH] scsi-disk: fix VERIFY emulation
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
VERIFY emulation was completely botched (and remained botched through
|
||||
all the refactorings). The command must be emulated both in check-medium
|
||||
mode (BYTCHK=00, which we implement by doing nothing) and in check-bytes
|
||||
mode (which we do not implement yet). Unlike WRITE AND VERIFY (which we
|
||||
treat simply as WRITE with FUA bit set), VERIFY cannot be handled like
|
||||
READ. In fact the device is _receiving_ data for VERIFY, not _sending_
|
||||
it like READ.
|
||||
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Tested-by: Hervé Poussineau <hpoussin@reactos.org>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
(cherry picked from commit d97e7730816094a71cd1f19a56d7a73f77cdbf96)
|
||||
|
||||
Conflicts:
|
||||
hw/scsi/scsi-disk.c
|
||||
---
|
||||
hw/scsi/scsi-disk.c | 26 +++++++++++++++++++-------
|
||||
1 file changed, 19 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
|
||||
index 74e6a14..1fd1c26 100644
|
||||
--- a/hw/scsi/scsi-disk.c
|
||||
+++ b/hw/scsi/scsi-disk.c
|
||||
@@ -1597,6 +1597,14 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
|
||||
scsi_disk_emulate_unmap(r, r->iov.iov_base);
|
||||
break;
|
||||
|
||||
+ case VERIFY_10:
|
||||
+ case VERIFY_12:
|
||||
+ case VERIFY_16:
|
||||
+ if (r->req.status == -1) {
|
||||
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@@ -1837,6 +1845,14 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
||||
case UNMAP:
|
||||
DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
|
||||
break;
|
||||
+ case VERIFY_10:
|
||||
+ case VERIFY_12:
|
||||
+ case VERIFY_16:
|
||||
+ DPRINTF("Verify (bytchk %lu)\n", (r->req.buf[1] >> 1) & 3);
|
||||
+ if (req->cmd.buf[1] & 6) {
|
||||
+ goto illegal_request;
|
||||
+ }
|
||||
+ break;
|
||||
case WRITE_SAME_10:
|
||||
case WRITE_SAME_16:
|
||||
nb_sectors = scsi_data_cdb_length(r->req.cmd.buf);
|
||||
@@ -1936,10 +1952,6 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
|
||||
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
|
||||
return 0;
|
||||
}
|
||||
- /* fallthrough */
|
||||
- case VERIFY_10:
|
||||
- case VERIFY_12:
|
||||
- case VERIFY_16:
|
||||
DPRINTF("Write %s(sector %" PRId64 ", count %u)\n",
|
||||
(command & 0xe) == 0xe ? "And Verify " : "",
|
||||
r->req.cmd.lba, len);
|
||||
@@ -2207,14 +2219,14 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
|
||||
[UNMAP] = &scsi_disk_emulate_reqops,
|
||||
[WRITE_SAME_10] = &scsi_disk_emulate_reqops,
|
||||
[WRITE_SAME_16] = &scsi_disk_emulate_reqops,
|
||||
+ [VERIFY_10] = &scsi_disk_emulate_reqops,
|
||||
+ [VERIFY_12] = &scsi_disk_emulate_reqops,
|
||||
+ [VERIFY_16] = &scsi_disk_emulate_reqops,
|
||||
|
||||
[READ_6] = &scsi_disk_dma_reqops,
|
||||
[READ_10] = &scsi_disk_dma_reqops,
|
||||
[READ_12] = &scsi_disk_dma_reqops,
|
||||
[READ_16] = &scsi_disk_dma_reqops,
|
||||
- [VERIFY_10] = &scsi_disk_dma_reqops,
|
||||
- [VERIFY_12] = &scsi_disk_dma_reqops,
|
||||
- [VERIFY_16] = &scsi_disk_dma_reqops,
|
||||
[WRITE_6] = &scsi_disk_dma_reqops,
|
||||
[WRITE_10] = &scsi_disk_dma_reqops,
|
||||
[WRITE_12] = &scsi_disk_dma_reqops,
|
@ -0,0 +1,46 @@
|
||||
From: Peter Lieven <pl@kamp.de>
|
||||
Date: Thu, 24 Oct 2013 09:21:29 +0200
|
||||
Subject: [PATCH] migration: drop MADVISE_DONT_NEED for incoming zero pages
|
||||
|
||||
The madvise for zeroed out pages was introduced when every transferred
|
||||
zero page was memset to zero and thus allocated. Since commit
|
||||
211ea740 we check for zeroness of a target page before we memset
|
||||
it to zero. Additionally we memmap target memory so it is essentially
|
||||
zero initialized (except for e.g. option roms and bios which are loaded
|
||||
into target memory although they shouldn't).
|
||||
|
||||
It was reported recently that this madvise causes a performance degradation
|
||||
in some situations. As the madvise should only be called rarely and if it's called
|
||||
it is likely on a busy page (it was non-zero and changed to zero during migration)
|
||||
drop it completely.
|
||||
|
||||
Reported-By: Zhang Haoyu <haoyu.zhang@huawei.com>
|
||||
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Signed-off-by: Peter Lieven <pl@kamp.de>
|
||||
Signed-off-by: Juan Quintela <quintela@redhat.com>
|
||||
(cherry picked from commit fc1c4a5d32e15a4c40c47945da85ef9c1e0c1b54)
|
||||
|
||||
Conflicts:
|
||||
arch_init.c
|
||||
---
|
||||
arch_init.c | 7 -------
|
||||
1 file changed, 7 deletions(-)
|
||||
|
||||
diff --git a/arch_init.c b/arch_init.c
|
||||
index 68a7ab7..23151b3 100644
|
||||
--- a/arch_init.c
|
||||
+++ b/arch_init.c
|
||||
@@ -845,13 +845,6 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size)
|
||||
{
|
||||
if (ch != 0 || !is_zero_page(host)) {
|
||||
memset(host, ch, size);
|
||||
-#ifndef _WIN32
|
||||
- if (ch == 0 &&
|
||||
- (!kvm_enabled() || kvm_has_sync_mmu()) &&
|
||||
- getpagesize() <= TARGET_PAGE_SIZE) {
|
||||
- qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED);
|
||||
- }
|
||||
-#endif
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
From: Christophe Fergeau <cfergeau@redhat.com>
|
||||
Date: Thu, 30 Jan 2014 14:56:49 +0100
|
||||
Subject: [PATCH] libcacard: Don't link with all libraries QEMU links to
|
||||
|
||||
As described in https://bugzilla.redhat.com/show_bug.cgi?id=987441 ,
|
||||
libcacard currently links to all the libraries QEMU is linking to,
|
||||
including glusterfs libraries, libiscsi, ... libcacard does not need all of
|
||||
these. This patch ensures it's only linked with the libraries it needs.
|
||||
|
||||
Signed-off-by: Christophe Fergeau <cfergeau@redhat.com>
|
||||
Signed-off-by: Alon Levy <alevy@redhat.com>
|
||||
(cherry picked from commit 73db416ae7941f8ffeabc060ec87402b97314b6d)
|
||||
---
|
||||
libcacard/Makefile | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libcacard/Makefile b/libcacard/Makefile
|
||||
index 47827a0..9fa297c 100644
|
||||
--- a/libcacard/Makefile
|
||||
+++ b/libcacard/Makefile
|
||||
@@ -24,7 +24,7 @@ vscclient$(EXESUF): libcacard/vscclient.o libcacard.la
|
||||
|
||||
libcacard.la: LDFLAGS += -rpath $(libdir) -no-undefined \
|
||||
-export-syms $(SRC_PATH)/libcacard/libcacard.syms
|
||||
-libcacard.la: LIBS += $(libcacard_libs)
|
||||
+libcacard.la: LIBS = $(libcacard_libs)
|
||||
libcacard.la: $(libcacard-lobj-y)
|
||||
$(call LINK,$^)
|
||||
|
32
0111-gtk-Fix-mouse-warping-with-gtk3.patch
Normal file
32
0111-gtk-Fix-mouse-warping-with-gtk3.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From: Cole Robinson <crobinso@redhat.com>
|
||||
Date: Thu, 13 Mar 2014 15:30:23 -0400
|
||||
Subject: [PATCH] gtk: Fix mouse warping with gtk3
|
||||
|
||||
We were using the wrong coordinates, this fixes things to match the
|
||||
original gtk2 implementation.
|
||||
|
||||
You can see this error in action by using -vga qxl, however even after this
|
||||
patch the mouse warps in small increments up and to the left, -7x and -3y
|
||||
pixels at a time, until the pointer is warped off the widget. I think it's
|
||||
a qxl bug, but the next patch covers it up.
|
||||
|
||||
Signed-off-by: Cole Robinson <crobinso@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
(cherry picked from commit 298526fe92d0b35ea343f8ddcc3a1d54cb422494)
|
||||
---
|
||||
ui/gtk.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ui/gtk.c b/ui/gtk.c
|
||||
index c38146f..6c9d90a 100644
|
||||
--- a/ui/gtk.c
|
||||
+++ b/ui/gtk.c
|
||||
@@ -355,7 +355,7 @@ static void gd_mouse_set(DisplayChangeListener *dcl,
|
||||
x, y, &x_root, &y_root);
|
||||
gdk_device_warp(gdk_device_manager_get_client_pointer(mgr),
|
||||
gtk_widget_get_screen(s->drawing_area),
|
||||
- x, y);
|
||||
+ x_root, y_root);
|
||||
}
|
||||
#else
|
||||
static void gd_mouse_set(DisplayChangeListener *dcl,
|
41
0112-gtk-Don-t-warp-absolute-pointer.patch
Normal file
41
0112-gtk-Don-t-warp-absolute-pointer.patch
Normal file
@ -0,0 +1,41 @@
|
||||
From: Cole Robinson <crobinso@redhat.com>
|
||||
Date: Thu, 13 Mar 2014 15:30:24 -0400
|
||||
Subject: [PATCH] gtk: Don't warp absolute pointer
|
||||
|
||||
This matches the behavior of SDL, and makes the mouse usable when
|
||||
using -display gtk -vga qxl
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1051724
|
||||
Signed-off-by: Cole Robinson <crobinso@redhat.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
(cherry picked from commit 2bda66028b4962c36d4eabe2995edab12df93691)
|
||||
---
|
||||
ui/gtk.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/ui/gtk.c b/ui/gtk.c
|
||||
index 6c9d90a..6ce9694 100644
|
||||
--- a/ui/gtk.c
|
||||
+++ b/ui/gtk.c
|
||||
@@ -349,6 +349,10 @@ static void gd_mouse_set(DisplayChangeListener *dcl,
|
||||
GdkDeviceManager *mgr;
|
||||
gint x_root, y_root;
|
||||
|
||||
+ if (kbd_mouse_is_absolute()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
dpy = gtk_widget_get_display(s->drawing_area);
|
||||
mgr = gdk_display_get_device_manager(dpy);
|
||||
gdk_window_get_root_coords(gtk_widget_get_window(s->drawing_area),
|
||||
@@ -364,6 +368,10 @@ static void gd_mouse_set(DisplayChangeListener *dcl,
|
||||
GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl);
|
||||
gint x_root, y_root;
|
||||
|
||||
+ if (kbd_mouse_is_absolute()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
gdk_window_get_root_coords(gtk_widget_get_window(s->drawing_area),
|
||||
x, y, &x_root, &y_root);
|
||||
gdk_display_warp_pointer(gtk_widget_get_display(s->drawing_area),
|
@ -0,0 +1,36 @@
|
||||
From: Cole Robinson <crobinso@redhat.com>
|
||||
Date: Wed, 19 Mar 2014 14:57:27 -0400
|
||||
Subject: [PATCH] Change gtk quit accelerator to ctrl+shift+q (bz 1062393)
|
||||
|
||||
Similar patches queued for 2.1
|
||||
---
|
||||
ui/gtk.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/ui/gtk.c b/ui/gtk.c
|
||||
index 6ce9694..8bc667d 100644
|
||||
--- a/ui/gtk.c
|
||||
+++ b/ui/gtk.c
|
||||
@@ -1310,7 +1310,6 @@ static GtkWidget *gd_create_menu_machine(GtkDisplayState *s, GtkAccelGroup *acce
|
||||
{
|
||||
GtkWidget *machine_menu;
|
||||
GtkWidget *separator;
|
||||
- GtkStockItem item;
|
||||
|
||||
machine_menu = gtk_menu_new();
|
||||
gtk_menu_set_accel_group(GTK_MENU(machine_menu), accel_group);
|
||||
@@ -1330,11 +1329,11 @@ static GtkWidget *gd_create_menu_machine(GtkDisplayState *s, GtkAccelGroup *acce
|
||||
separator = gtk_separator_menu_item_new();
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), separator);
|
||||
|
||||
- s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
|
||||
- gtk_stock_lookup(GTK_STOCK_QUIT, &item);
|
||||
+ s->quit_item = gtk_menu_item_new_with_mnemonic(_("_Quit"));
|
||||
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item),
|
||||
"<QEMU>/Machine/Quit");
|
||||
- gtk_accel_map_add_entry("<QEMU>/Machine/Quit", item.keyval, item.modifier);
|
||||
+ gtk_accel_map_add_entry("<QEMU>/Machine/Quit",
|
||||
+ GDK_KEY_q, HOTKEY_MODIFIERS);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(machine_menu), s->quit_item);
|
||||
|
||||
return machine_menu;
|
@ -0,0 +1,30 @@
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Wed, 15 Jan 2014 10:35:36 +0100
|
||||
Subject: [PATCH] scsi: Assign cancel_io vector for scsi_disk_emulate_ops
|
||||
|
||||
Some emulated disk operations (MODE SELECT, UNMAP, WRITE SAME)
|
||||
can trigger asynchronous I/Os. Provide the cancel_io callback
|
||||
to ensure that AIOCBs are properly cleaned up.
|
||||
|
||||
Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com>
|
||||
Cc: qemu-stable@nongnu.org
|
||||
[Tweak commit message. - Paolo]
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
|
||||
(cherry picked from commit 33325a53f15ab5370e1917b2a11cadffc77c5a52)
|
||||
---
|
||||
hw/scsi/scsi-disk.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
|
||||
index 1fd1c26..ade5d4a 100644
|
||||
--- a/hw/scsi/scsi-disk.c
|
||||
+++ b/hw/scsi/scsi-disk.c
|
||||
@@ -2181,6 +2181,7 @@ static const SCSIReqOps scsi_disk_emulate_reqops = {
|
||||
.send_command = scsi_disk_emulate_command,
|
||||
.read_data = scsi_disk_emulate_read_data,
|
||||
.write_data = scsi_disk_emulate_write_data,
|
||||
+ .cancel_io = scsi_cancel_io,
|
||||
.get_buf = scsi_get_buf,
|
||||
};
|
||||
|
38
0115-virtio-scsi-Cleanup-of-I-Os-that-never-started.patch
Normal file
38
0115-virtio-scsi-Cleanup-of-I-Os-that-never-started.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From: Eric Farman <farman@linux.vnet.ibm.com>
|
||||
Date: Tue, 14 Jan 2014 14:16:25 -0500
|
||||
Subject: [PATCH] virtio-scsi: Cleanup of I/Os that never started
|
||||
|
||||
There is still a small window that occurs when a cancel I/O affects
|
||||
an asynchronous I/O operation that hasn't started. In other words,
|
||||
when the residual data length equals the expected data length.
|
||||
|
||||
Today, the routine virtio_scsi_command_complete fails because the
|
||||
VirtIOSCSIReq pointer (from the hba_private field in SCSIRequest)
|
||||
was cleared earlier when virtio_scsi_complete_req was called by
|
||||
the virtio_scsi_request_cancelled routine. As a result, the
|
||||
virtio_scsi_command_complete routine needs to simply return when
|
||||
it is processing a SCSIRequest block that was marked canceled.
|
||||
|
||||
Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com>
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
(cherry picked from commit e9c0f0f58ad0a41c3c4b19e1911cfe095afc09ca)
|
||||
---
|
||||
hw/scsi/virtio-scsi.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
|
||||
index 5545993..110827c 100644
|
||||
--- a/hw/scsi/virtio-scsi.c
|
||||
+++ b/hw/scsi/virtio-scsi.c
|
||||
@@ -306,6 +306,10 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
|
||||
VirtIOSCSIReq *req = r->hba_private;
|
||||
uint32_t sense_len;
|
||||
|
||||
+ if (r->io_canceled) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
req->resp.cmd->response = VIRTIO_SCSI_S_OK;
|
||||
req->resp.cmd->status = status;
|
||||
if (req->resp.cmd->status == GOOD) {
|
29
0116-virtio-scsi-Prevent-assertion-on-missed-events.patch
Normal file
29
0116-virtio-scsi-Prevent-assertion-on-missed-events.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From: Eric Farman <farman@linux.vnet.ibm.com>
|
||||
Date: Tue, 14 Jan 2014 14:16:26 -0500
|
||||
Subject: [PATCH] virtio-scsi: Prevent assertion on missed events
|
||||
|
||||
In some cases, an unplug can cause events to be dropped, which
|
||||
leads to an assertion failure when preparing to notify the guest
|
||||
kernel.
|
||||
|
||||
Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com>
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
(cherry picked from commit 49fb65c7f985baa56d2964e0a85c1f098e3e2a9d)
|
||||
---
|
||||
hw/scsi/virtio-scsi.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
|
||||
index 110827c..15e40d9 100644
|
||||
--- a/hw/scsi/virtio-scsi.c
|
||||
+++ b/hw/scsi/virtio-scsi.c
|
||||
@@ -520,7 +520,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
|
||||
evt->event = event;
|
||||
evt->reason = reason;
|
||||
if (!dev) {
|
||||
- assert(event == VIRTIO_SCSI_T_NO_EVENT);
|
||||
+ assert(event == VIRTIO_SCSI_T_EVENTS_MISSED);
|
||||
} else {
|
||||
evt->lun[0] = 1;
|
||||
evt->lun[1] = dev->id;
|
@ -0,0 +1,65 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:25 +0100
|
||||
Subject: [PATCH] block/cloop: validate block_size header field (CVE-2014-0144)
|
||||
|
||||
Avoid unbounded s->uncompressed_block memory allocation by checking that
|
||||
the block_size header field has a reasonable value. Also enforce the
|
||||
assumption that the value is a non-zero multiple of 512.
|
||||
|
||||
These constraints conform to cloop 2.639's code so we accept existing
|
||||
image files.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit d65f97a82c4ed48374a764c769d4ba1ea9724e97)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/075
|
||||
tests/qemu-iotests/075.out
|
||||
---
|
||||
block/cloop.c | 23 +++++++++++++++++++++++
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
diff --git a/block/cloop.c b/block/cloop.c
|
||||
index 6ea7cf4..c2441b0 100644
|
||||
--- a/block/cloop.c
|
||||
+++ b/block/cloop.c
|
||||
@@ -26,6 +26,9 @@
|
||||
#include "qemu/module.h"
|
||||
#include <zlib.h>
|
||||
|
||||
+/* Maximum compressed block size */
|
||||
+#define MAX_BLOCK_SIZE (64 * 1024 * 1024)
|
||||
+
|
||||
typedef struct BDRVCloopState {
|
||||
CoMutex lock;
|
||||
uint32_t block_size;
|
||||
@@ -67,6 +70,26 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
return ret;
|
||||
}
|
||||
s->block_size = be32_to_cpu(s->block_size);
|
||||
+ if (s->block_size % 512) {
|
||||
+ fprintf(stderr, "block_size %u must be a multiple of 512",
|
||||
+ s->block_size);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (s->block_size == 0) {
|
||||
+ fprintf(stderr, "block_size cannot be zero");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* cloop's create_compressed_fs.c warns about block sizes beyond 256 KB but
|
||||
+ * we can accept more. Prevent ridiculous values like 4 GB - 1 since we
|
||||
+ * need a buffer this big.
|
||||
+ */
|
||||
+ if (s->block_size > MAX_BLOCK_SIZE) {
|
||||
+ fprintf(stderr, "block_size %u must be %u MB or less",
|
||||
+ s->block_size,
|
||||
+ MAX_BLOCK_SIZE / (1024 * 1024));
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
|
||||
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
|
||||
if (ret < 0) {
|
@ -0,0 +1,62 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:26 +0100
|
||||
Subject: [PATCH] block/cloop: prevent offsets_size integer overflow
|
||||
(CVE-2014-0143)
|
||||
|
||||
The following integer overflow in offsets_size can lead to out-of-bounds
|
||||
memory stores when n_blocks has a huge value:
|
||||
|
||||
uint32_t n_blocks, offsets_size;
|
||||
[...]
|
||||
ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
|
||||
[...]
|
||||
s->n_blocks = be32_to_cpu(s->n_blocks);
|
||||
|
||||
/* read offsets */
|
||||
offsets_size = s->n_blocks * sizeof(uint64_t);
|
||||
s->offsets = g_malloc(offsets_size);
|
||||
|
||||
[...]
|
||||
|
||||
for(i=0;i<s->n_blocks;i++) {
|
||||
s->offsets[i] = be64_to_cpu(s->offsets[i]);
|
||||
|
||||
offsets_size can be smaller than n_blocks due to integer overflow.
|
||||
Therefore s->offsets[] is too small when the for loop byteswaps offsets.
|
||||
|
||||
This patch refuses to open files if offsets_size would overflow.
|
||||
|
||||
Note that changing the type of offsets_size is not a fix since 32-bit
|
||||
hosts still only have 32-bit size_t.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 509a41bab5306181044b5fff02eadf96d9c8676a)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/075
|
||||
tests/qemu-iotests/075.out
|
||||
---
|
||||
block/cloop.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/block/cloop.c b/block/cloop.c
|
||||
index c2441b0..e20d0d8 100644
|
||||
--- a/block/cloop.c
|
||||
+++ b/block/cloop.c
|
||||
@@ -98,6 +98,13 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
s->n_blocks = be32_to_cpu(s->n_blocks);
|
||||
|
||||
/* read offsets */
|
||||
+ if (s->n_blocks > UINT32_MAX / sizeof(uint64_t)) {
|
||||
+ /* Prevent integer overflow */
|
||||
+ fprintf(stderr, "n_blocks %u must be %zu or less",
|
||||
+ s->n_blocks,
|
||||
+ UINT32_MAX / sizeof(uint64_t));
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
offsets_size = s->n_blocks * sizeof(uint64_t);
|
||||
s->offsets = g_malloc(offsets_size);
|
||||
|
@ -0,0 +1,46 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:27 +0100
|
||||
Subject: [PATCH] block/cloop: refuse images with huge offsets arrays
|
||||
(CVE-2014-0144)
|
||||
|
||||
Limit offsets_size to 512 MB so that:
|
||||
|
||||
1. g_malloc() does not abort due to an unreasonable size argument.
|
||||
|
||||
2. offsets_size does not overflow the bdrv_pread() int size argument.
|
||||
|
||||
This limit imposes a maximum image size of 16 TB at 256 KB block size.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 7b103b36d6ef3b11827c203d3a793bf7da50ecd6)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/075
|
||||
tests/qemu-iotests/075.out
|
||||
---
|
||||
block/cloop.c | 9 +++++++++
|
||||
1 file changed, 9 insertions(+)
|
||||
|
||||
diff --git a/block/cloop.c b/block/cloop.c
|
||||
index e20d0d8..cf81c61 100644
|
||||
--- a/block/cloop.c
|
||||
+++ b/block/cloop.c
|
||||
@@ -106,6 +106,15 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
return -EINVAL;
|
||||
}
|
||||
offsets_size = s->n_blocks * sizeof(uint64_t);
|
||||
+ if (offsets_size > 512 * 1024 * 1024) {
|
||||
+ /* Prevent ridiculous offsets_size which causes memory allocation to
|
||||
+ * fail or overflows bdrv_pread() size. In practice the 512 MB
|
||||
+ * offsets[] limit supports 16 TB images at 256 KB block size.
|
||||
+ */
|
||||
+ fprintf(stderr, "image requires too many offsets, "
|
||||
+ "try increasing block size");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
s->offsets = g_malloc(offsets_size);
|
||||
|
||||
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
|
@ -0,0 +1,70 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:28 +0100
|
||||
Subject: [PATCH] block/cloop: refuse images with bogus offsets (CVE-2014-0144)
|
||||
|
||||
The offsets[] array allows efficient seeking and tells us the maximum
|
||||
compressed data size. If the offsets are bogus the maximum compressed
|
||||
data size will be unrealistic.
|
||||
|
||||
This could cause g_malloc() to abort and bogus offsets mean the image is
|
||||
broken anyway. Therefore we should refuse such images.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit f56b9bc3ae20fc93815b34aa022be919941406ce)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/075
|
||||
tests/qemu-iotests/075.out
|
||||
---
|
||||
block/cloop.c | 34 +++++++++++++++++++++++++++++-----
|
||||
1 file changed, 29 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/block/cloop.c b/block/cloop.c
|
||||
index cf81c61..5c9c085 100644
|
||||
--- a/block/cloop.c
|
||||
+++ b/block/cloop.c
|
||||
@@ -123,12 +123,36 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
}
|
||||
|
||||
for(i=0;i<s->n_blocks;i++) {
|
||||
+ uint64_t size;
|
||||
+
|
||||
s->offsets[i] = be64_to_cpu(s->offsets[i]);
|
||||
- if (i > 0) {
|
||||
- uint32_t size = s->offsets[i] - s->offsets[i - 1];
|
||||
- if (size > max_compressed_block_size) {
|
||||
- max_compressed_block_size = size;
|
||||
- }
|
||||
+ if (i == 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (s->offsets[i] < s->offsets[i - 1]) {
|
||||
+ fprintf(stderr, "offsets not monotonically increasing at "
|
||||
+ "index %u, image file is corrupt", i);
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ size = s->offsets[i] - s->offsets[i - 1];
|
||||
+
|
||||
+ /* Compressed blocks should be smaller than the uncompressed block size
|
||||
+ * but maybe compression performed poorly so the compressed block is
|
||||
+ * actually bigger. Clamp down on unrealistic values to prevent
|
||||
+ * ridiculous s->compressed_block allocation.
|
||||
+ */
|
||||
+ if (size > 2 * MAX_BLOCK_SIZE) {
|
||||
+ fprintf(stderr, "invalid compressed block size at index %u, "
|
||||
+ "image file is corrupt", i);
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ if (size > max_compressed_block_size) {
|
||||
+ max_compressed_block_size = size;
|
||||
}
|
||||
}
|
||||
|
74
0121-block-cloop-fix-offsets-size-off-by-one.patch
Normal file
74
0121-block-cloop-fix-offsets-size-off-by-one.patch
Normal file
@ -0,0 +1,74 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:29 +0100
|
||||
Subject: [PATCH] block/cloop: fix offsets[] size off-by-one
|
||||
|
||||
cloop stores the number of compressed blocks in the n_blocks header
|
||||
field. The file actually contains n_blocks + 1 offsets, where the extra
|
||||
offset is the end-of-file offset.
|
||||
|
||||
The following line in cloop_read_block() results in an out-of-bounds
|
||||
offsets[] access:
|
||||
|
||||
uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
|
||||
|
||||
This patch allocates and loads the extra offset so that
|
||||
cloop_read_block() works correctly when the last block is accessed.
|
||||
|
||||
Notice that we must free s->offsets[] unconditionally now since there is
|
||||
always an end-of-file offset.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 42d43d35d907579179a39c924d169da924786f65)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/075
|
||||
tests/qemu-iotests/075.out
|
||||
---
|
||||
block/cloop.c | 12 +++++-------
|
||||
1 file changed, 5 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/block/cloop.c b/block/cloop.c
|
||||
index 5c9c085..b28aae1 100644
|
||||
--- a/block/cloop.c
|
||||
+++ b/block/cloop.c
|
||||
@@ -98,14 +98,14 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
s->n_blocks = be32_to_cpu(s->n_blocks);
|
||||
|
||||
/* read offsets */
|
||||
- if (s->n_blocks > UINT32_MAX / sizeof(uint64_t)) {
|
||||
+ if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
|
||||
/* Prevent integer overflow */
|
||||
fprintf(stderr, "n_blocks %u must be %zu or less",
|
||||
s->n_blocks,
|
||||
- UINT32_MAX / sizeof(uint64_t));
|
||||
+ (UINT32_MAX - 1) / sizeof(uint64_t));
|
||||
return -EINVAL;
|
||||
}
|
||||
- offsets_size = s->n_blocks * sizeof(uint64_t);
|
||||
+ offsets_size = (s->n_blocks + 1) * sizeof(uint64_t);
|
||||
if (offsets_size > 512 * 1024 * 1024) {
|
||||
/* Prevent ridiculous offsets_size which causes memory allocation to
|
||||
* fail or overflows bdrv_pread() size. In practice the 512 MB
|
||||
@@ -122,7 +122,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- for(i=0;i<s->n_blocks;i++) {
|
||||
+ for (i = 0; i < s->n_blocks + 1; i++) {
|
||||
uint64_t size;
|
||||
|
||||
s->offsets[i] = be64_to_cpu(s->offsets[i]);
|
||||
@@ -242,9 +242,7 @@ static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num,
|
||||
static void cloop_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVCloopState *s = bs->opaque;
|
||||
- if (s->n_blocks > 0) {
|
||||
- g_free(s->offsets);
|
||||
- }
|
||||
+ g_free(s->offsets);
|
||||
g_free(s->compressed_block);
|
||||
g_free(s->uncompressed_block);
|
||||
inflateEnd(&s->zstream);
|
133
0122-bochs-Unify-header-structs-and-make-them-QEMU_PACKED.patch
Normal file
133
0122-bochs-Unify-header-structs-and-make-them-QEMU_PACKED.patch
Normal file
@ -0,0 +1,133 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:31 +0100
|
||||
Subject: [PATCH] bochs: Unify header structs and make them QEMU_PACKED
|
||||
|
||||
This is an on-disk structure, so offsets must be accurate.
|
||||
|
||||
Before this patch, sizeof(bochs) != sizeof(header_v1), which makes the
|
||||
memcpy() between both invalid. We're lucky enough that the destination
|
||||
buffer happened to be the larger one, and the memcpy size to be taken
|
||||
from the smaller one, so we didn't get a buffer overflow in practice.
|
||||
|
||||
This patch unifies the both structures, eliminating the need to do a
|
||||
memcpy in the first place. The common fields are extracted to the top
|
||||
level of the struct and the actually differing part gets a union of the
|
||||
two versions.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 3dd8a6763bcc50dfc3de8da9279b741c0dea9fb1)
|
||||
---
|
||||
block/bochs.c | 67 ++++++++++++++++++++++-------------------------------------
|
||||
1 file changed, 25 insertions(+), 42 deletions(-)
|
||||
|
||||
diff --git a/block/bochs.c b/block/bochs.c
|
||||
index d7078c0..d550ce1 100644
|
||||
--- a/block/bochs.c
|
||||
+++ b/block/bochs.c
|
||||
@@ -39,45 +39,30 @@
|
||||
// not allocated: 0xffffffff
|
||||
|
||||
// always little-endian
|
||||
-struct bochs_header_v1 {
|
||||
- char magic[32]; // "Bochs Virtual HD Image"
|
||||
- char type[16]; // "Redolog"
|
||||
- char subtype[16]; // "Undoable" / "Volatile" / "Growing"
|
||||
- uint32_t version;
|
||||
- uint32_t header; // size of header
|
||||
-
|
||||
- union {
|
||||
- struct {
|
||||
- uint32_t catalog; // num of entries
|
||||
- uint32_t bitmap; // bitmap size
|
||||
- uint32_t extent; // extent size
|
||||
- uint64_t disk; // disk size
|
||||
- char padding[HEADER_SIZE - 64 - 8 - 20];
|
||||
- } redolog;
|
||||
- char padding[HEADER_SIZE - 64 - 8];
|
||||
- } extra;
|
||||
-};
|
||||
-
|
||||
-// always little-endian
|
||||
struct bochs_header {
|
||||
- char magic[32]; // "Bochs Virtual HD Image"
|
||||
- char type[16]; // "Redolog"
|
||||
- char subtype[16]; // "Undoable" / "Volatile" / "Growing"
|
||||
+ char magic[32]; /* "Bochs Virtual HD Image" */
|
||||
+ char type[16]; /* "Redolog" */
|
||||
+ char subtype[16]; /* "Undoable" / "Volatile" / "Growing" */
|
||||
uint32_t version;
|
||||
- uint32_t header; // size of header
|
||||
+ uint32_t header; /* size of header */
|
||||
+
|
||||
+ uint32_t catalog; /* num of entries */
|
||||
+ uint32_t bitmap; /* bitmap size */
|
||||
+ uint32_t extent; /* extent size */
|
||||
|
||||
union {
|
||||
- struct {
|
||||
- uint32_t catalog; // num of entries
|
||||
- uint32_t bitmap; // bitmap size
|
||||
- uint32_t extent; // extent size
|
||||
- uint32_t reserved; // for ???
|
||||
- uint64_t disk; // disk size
|
||||
- char padding[HEADER_SIZE - 64 - 8 - 24];
|
||||
- } redolog;
|
||||
- char padding[HEADER_SIZE - 64 - 8];
|
||||
+ struct {
|
||||
+ uint32_t reserved; /* for ??? */
|
||||
+ uint64_t disk; /* disk size */
|
||||
+ char padding[HEADER_SIZE - 64 - 20 - 12];
|
||||
+ } QEMU_PACKED redolog;
|
||||
+ struct {
|
||||
+ uint64_t disk; /* disk size */
|
||||
+ char padding[HEADER_SIZE - 64 - 20 - 8];
|
||||
+ } QEMU_PACKED redolog_v1;
|
||||
+ char padding[HEADER_SIZE - 64 - 20];
|
||||
} extra;
|
||||
-};
|
||||
+} QEMU_PACKED;
|
||||
|
||||
typedef struct BDRVBochsState {
|
||||
CoMutex lock;
|
||||
@@ -113,7 +98,6 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
int i;
|
||||
struct bochs_header bochs;
|
||||
- struct bochs_header_v1 header_v1;
|
||||
int ret;
|
||||
|
||||
bs->read_only = 1; // no write support yet
|
||||
@@ -132,13 +116,12 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
}
|
||||
|
||||
if (le32_to_cpu(bochs.version) == HEADER_V1) {
|
||||
- memcpy(&header_v1, &bochs, sizeof(bochs));
|
||||
- bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
|
||||
+ bs->total_sectors = le64_to_cpu(bochs.extra.redolog_v1.disk) / 512;
|
||||
} else {
|
||||
- bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
||||
+ bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
||||
}
|
||||
|
||||
- s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
|
||||
+ s->catalog_size = le32_to_cpu(bochs.catalog);
|
||||
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
||||
|
||||
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
|
||||
@@ -152,10 +135,10 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
|
||||
s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
|
||||
|
||||
- s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
|
||||
- s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
|
||||
+ s->bitmap_blocks = 1 + (le32_to_cpu(bochs.bitmap) - 1) / 512;
|
||||
+ s->extent_blocks = 1 + (le32_to_cpu(bochs.extent) - 1) / 512;
|
||||
|
||||
- s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
|
||||
+ s->extent_size = le32_to_cpu(bochs.extent);
|
||||
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
return 0;
|
@ -0,0 +1,64 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:32 +0100
|
||||
Subject: [PATCH] bochs: Use unsigned variables for offsets and sizes
|
||||
(CVE-2014-0147)
|
||||
|
||||
Gets us rid of integer overflows resulting in negative sizes which
|
||||
aren't correctly checked.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 246f65838d19db6db55bfb41117c35645a2c4789)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/078
|
||||
tests/qemu-iotests/078.out
|
||||
---
|
||||
block/bochs.c | 16 ++++++++--------
|
||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/block/bochs.c b/block/bochs.c
|
||||
index d550ce1..750cec0 100644
|
||||
--- a/block/bochs.c
|
||||
+++ b/block/bochs.c
|
||||
@@ -67,13 +67,13 @@ struct bochs_header {
|
||||
typedef struct BDRVBochsState {
|
||||
CoMutex lock;
|
||||
uint32_t *catalog_bitmap;
|
||||
- int catalog_size;
|
||||
+ uint32_t catalog_size;
|
||||
|
||||
- int data_offset;
|
||||
+ uint32_t data_offset;
|
||||
|
||||
- int bitmap_blocks;
|
||||
- int extent_blocks;
|
||||
- int extent_size;
|
||||
+ uint32_t bitmap_blocks;
|
||||
+ uint32_t extent_blocks;
|
||||
+ uint32_t extent_size;
|
||||
} BDRVBochsState;
|
||||
|
||||
static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
@@ -96,7 +96,7 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
static int bochs_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
- int i;
|
||||
+ uint32_t i;
|
||||
struct bochs_header bochs;
|
||||
int ret;
|
||||
|
||||
@@ -151,8 +151,8 @@ fail:
|
||||
static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
{
|
||||
BDRVBochsState *s = bs->opaque;
|
||||
- int64_t offset = sector_num * 512;
|
||||
- int64_t extent_index, extent_offset, bitmap_offset;
|
||||
+ uint64_t offset = sector_num * 512;
|
||||
+ uint64_t extent_index, extent_offset, bitmap_offset;
|
||||
char bitmap_entry;
|
||||
|
||||
// seek to sector
|
@ -0,0 +1,53 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:33 +0100
|
||||
Subject: [PATCH] bochs: Check catalog_size header field (CVE-2014-0143)
|
||||
|
||||
It should neither become negative nor allow unbounded memory
|
||||
allocations. This fixes aborts in g_malloc() and an s->catalog_bitmap
|
||||
buffer overflow on big endian hosts.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit e3737b820b45e54b059656dc3f914f895ac7a88b)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/078
|
||||
tests/qemu-iotests/078.out
|
||||
---
|
||||
block/bochs.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/block/bochs.c b/block/bochs.c
|
||||
index 750cec0..4393ecc 100644
|
||||
--- a/block/bochs.c
|
||||
+++ b/block/bochs.c
|
||||
@@ -121,7 +121,14 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
|
||||
}
|
||||
|
||||
+ /* Limit to 1M entries to avoid unbounded allocation. This is what is
|
||||
+ * needed for the largest image that bximage can create (~8 TB). */
|
||||
s->catalog_size = le32_to_cpu(bochs.catalog);
|
||||
+ if (s->catalog_size > 0x100000) {
|
||||
+ fprintf(stderr, "Catalog size is too large");
|
||||
+ return -EFBIG;
|
||||
+ }
|
||||
+
|
||||
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
||||
|
||||
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
|
||||
@@ -140,6 +147,12 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
|
||||
s->extent_size = le32_to_cpu(bochs.extent);
|
||||
|
||||
+ if (s->catalog_size < bs->total_sectors / s->extent_size) {
|
||||
+ fprintf(stderr, "Catalog size is too small for this disk size");
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
return 0;
|
||||
|
@ -0,0 +1,39 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:34 +0100
|
||||
Subject: [PATCH] bochs: Check extent_size header field (CVE-2014-0142)
|
||||
|
||||
This fixes two possible division by zero crashes: In bochs_open() and in
|
||||
seek_to_sector().
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 8e53abbc20d08ae3ec30c2054e1161314ad9501d)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/078
|
||||
tests/qemu-iotests/078.out
|
||||
---
|
||||
block/bochs.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/block/bochs.c b/block/bochs.c
|
||||
index 4393ecc..10fbd39 100644
|
||||
--- a/block/bochs.c
|
||||
+++ b/block/bochs.c
|
||||
@@ -146,6 +146,14 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
s->extent_blocks = 1 + (le32_to_cpu(bochs.extent) - 1) / 512;
|
||||
|
||||
s->extent_size = le32_to_cpu(bochs.extent);
|
||||
+ if (s->extent_size == 0) {
|
||||
+ fprintf(stderr, "Extent size may not be zero");
|
||||
+ return -EINVAL;
|
||||
+ } else if (s->extent_size > 0x800000) {
|
||||
+ fprintf(stderr, "Extent size %" PRIu32 " is too large",
|
||||
+ s->extent_size);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
|
||||
if (s->catalog_size < bs->total_sectors / s->extent_size) {
|
||||
fprintf(stderr, "Catalog size is too small for this disk size");
|
31
0126-bochs-Fix-bitmap-offset-calculation.patch
Normal file
31
0126-bochs-Fix-bitmap-offset-calculation.patch
Normal file
@ -0,0 +1,31 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:35 +0100
|
||||
Subject: [PATCH] bochs: Fix bitmap offset calculation
|
||||
|
||||
32 bit truncation could let us access the wrong offset in the image.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit a9ba36a45dfac645a810c31ce15ab393b69d820a)
|
||||
---
|
||||
block/bochs.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/block/bochs.c b/block/bochs.c
|
||||
index 10fbd39..6749a61 100644
|
||||
--- a/block/bochs.c
|
||||
+++ b/block/bochs.c
|
||||
@@ -184,8 +184,9 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
return -1; /* not allocated */
|
||||
}
|
||||
|
||||
- bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
|
||||
- (s->extent_blocks + s->bitmap_blocks));
|
||||
+ bitmap_offset = s->data_offset +
|
||||
+ (512 * (uint64_t) s->catalog_bitmap[extent_index] *
|
||||
+ (s->extent_blocks + s->bitmap_blocks));
|
||||
|
||||
/* read in bitmap for current extent */
|
||||
if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
@ -0,0 +1,96 @@
|
||||
From: Jeff Cody <jcody@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:36 +0100
|
||||
Subject: [PATCH] vpc/vhd: add bounds check for max_table_entries and
|
||||
block_size (CVE-2014-0144)
|
||||
|
||||
This adds checks to make sure that max_table_entries and block_size
|
||||
are in sane ranges. Memory is allocated based on max_table_entries,
|
||||
and block_size is used to calculate indices into that allocated
|
||||
memory, so if these values are incorrect that can lead to potential
|
||||
unbounded memory allocation, or invalid memory accesses.
|
||||
|
||||
Also, the allocation of the pagetable is changed from g_malloc0()
|
||||
to qemu_blockalign().
|
||||
|
||||
Signed-off-by: Jeff Cody <jcody@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 97f1c45c6f456572e5b504b8614e4a69e23b8e3a)
|
||||
---
|
||||
block/vpc.c | 27 +++++++++++++++++++++++----
|
||||
1 file changed, 23 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/block/vpc.c b/block/vpc.c
|
||||
index fe4f311..16c5acf 100644
|
||||
--- a/block/vpc.c
|
||||
+++ b/block/vpc.c
|
||||
@@ -45,6 +45,8 @@ enum vhd_type {
|
||||
// Seconds since Jan 1, 2000 0:00:00 (UTC)
|
||||
#define VHD_TIMESTAMP_BASE 946684800
|
||||
|
||||
+#define VHD_MAX_SECTORS (65535LL * 255 * 255)
|
||||
+
|
||||
// always big-endian
|
||||
struct vhd_footer {
|
||||
char creator[8]; // "conectix"
|
||||
@@ -163,6 +165,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
struct vhd_dyndisk_header* dyndisk_header;
|
||||
uint8_t buf[HEADER_SIZE];
|
||||
uint32_t checksum;
|
||||
+ uint64_t computed_size;
|
||||
int disk_type = VHD_DYNAMIC;
|
||||
int ret;
|
||||
|
||||
@@ -211,7 +214,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
|
||||
|
||||
/* Allow a maximum disk size of approximately 2 TB */
|
||||
- if (bs->total_sectors >= 65535LL * 255 * 255) {
|
||||
+ if (bs->total_sectors >= VHD_MAX_SECTORS) {
|
||||
ret = -EFBIG;
|
||||
goto fail;
|
||||
}
|
||||
@@ -234,7 +237,23 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
|
||||
|
||||
s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
|
||||
- s->pagetable = g_malloc(s->max_table_entries * 4);
|
||||
+
|
||||
+ if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) {
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if (s->max_table_entries > (VHD_MAX_SECTORS * 512) / s->block_size) {
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ computed_size = (uint64_t) s->max_table_entries * s->block_size;
|
||||
+ if (computed_size < bs->total_sectors * 512) {
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ s->pagetable = qemu_blockalign(bs, s->max_table_entries * 4);
|
||||
|
||||
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
||||
|
||||
@@ -280,7 +299,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
- g_free(s->pagetable);
|
||||
+ qemu_vfree(s->pagetable);
|
||||
#ifdef CACHE
|
||||
g_free(s->pageentry_u8);
|
||||
#endif
|
||||
@@ -801,7 +820,7 @@ static int vpc_has_zero_init(BlockDriverState *bs)
|
||||
static void vpc_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
- g_free(s->pagetable);
|
||||
+ qemu_vfree(s->pagetable);
|
||||
#ifdef CACHE
|
||||
g_free(s->pageentry_u8);
|
||||
#endif
|
33
0128-vpc-Validate-block-size-CVE-2014-0142.patch
Normal file
33
0128-vpc-Validate-block-size-CVE-2014-0142.patch
Normal file
@ -0,0 +1,33 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:37 +0100
|
||||
Subject: [PATCH] vpc: Validate block size (CVE-2014-0142)
|
||||
|
||||
This fixes some cases of division by zero crashes.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 5e71dfad763d67bb64be79e20e93411c0c30ad25)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/group
|
||||
---
|
||||
block/vpc.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/block/vpc.c b/block/vpc.c
|
||||
index 16c5acf..a41a0ab 100644
|
||||
--- a/block/vpc.c
|
||||
+++ b/block/vpc.c
|
||||
@@ -234,6 +234,11 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
}
|
||||
|
||||
s->block_size = be32_to_cpu(dyndisk_header->block_size);
|
||||
+ if (!is_power_of_2(s->block_size) || s->block_size < BDRV_SECTOR_SIZE) {
|
||||
+ fprintf(stderr, "Invalid block size %" PRIu32, s->block_size);
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
|
||||
|
||||
s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
|
110
0129-vdi-add-bounds-checks-for-blocks_in_image-and-disk_s.patch
Normal file
110
0129-vdi-add-bounds-checks-for-blocks_in_image-and-disk_s.patch
Normal file
@ -0,0 +1,110 @@
|
||||
From: Jeff Cody <jcody@redhat.com>
|
||||
Date: Fri, 28 Mar 2014 11:42:24 -0400
|
||||
Subject: [PATCH] vdi: add bounds checks for blocks_in_image and disk_size
|
||||
header fields (CVE-2014-0144)
|
||||
|
||||
The maximum blocks_in_image is 0xffffffff / 4, which also limits the
|
||||
maximum disk_size for a VDI image to 1024TB. Note that this is the maximum
|
||||
size that QEMU will currently support with this driver, not necessarily the
|
||||
maximum size allowed by the image format.
|
||||
|
||||
This also fixes an incorrect error message, a bug introduced by commit
|
||||
5b7aa9b56d1bfc79916262f380c3fc7961becb50 (Reported by Stefan Weil)
|
||||
|
||||
Signed-off-by: Jeff Cody <jcody@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 63fa06dc978f3669dbfd9443b33cde9e2a7f4b41)
|
||||
|
||||
Conflicts:
|
||||
block/vdi.c
|
||||
---
|
||||
block/vdi.c | 35 +++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 33 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/block/vdi.c b/block/vdi.c
|
||||
index 8a91525..63d509e 100644
|
||||
--- a/block/vdi.c
|
||||
+++ b/block/vdi.c
|
||||
@@ -120,6 +120,11 @@ typedef unsigned char uuid_t[16];
|
||||
|
||||
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
|
||||
|
||||
+/* max blocks in image is (0xffffffff / 4) */
|
||||
+#define VDI_BLOCKS_IN_IMAGE_MAX 0x3fffffff
|
||||
+#define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \
|
||||
+ (uint64_t)DEFAULT_CLUSTER_SIZE)
|
||||
+
|
||||
#if !defined(CONFIG_UUID)
|
||||
static inline void uuid_generate(uuid_t out)
|
||||
{
|
||||
@@ -383,6 +388,14 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
vdi_header_print(&header);
|
||||
#endif
|
||||
|
||||
+ if (header.disk_size > VDI_DISK_SIZE_MAX) {
|
||||
+ fprintf(stderr, "Unsupported VDI image size (size is 0x%" PRIx64
|
||||
+ ", max supported is 0x%" PRIx64 ")",
|
||||
+ header.disk_size, VDI_DISK_SIZE_MAX);
|
||||
+ ret = -ENOTSUP;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
if (header.disk_size % SECTOR_SIZE != 0) {
|
||||
/* 'VBoxManage convertfromraw' can create images with odd disk sizes.
|
||||
We accept them but round the disk size to the next multiple of
|
||||
@@ -415,8 +428,10 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
logout("unsupported sector size %u B\n", header.sector_size);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
- } else if (header.block_size != 1 * MiB) {
|
||||
logout("unsupported block size %u B\n", header.block_size);
|
||||
+ } else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
|
||||
+ logout("unsupported VDI image (block size %u is not %u)",
|
||||
+ header.block_size, DEFAULT_CLUSTER_SIZE);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.disk_size >
|
||||
@@ -432,6 +447,12 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
logout("parent uuid != 0, unsupported\n");
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
+ } else if (header.blocks_in_image > VDI_BLOCKS_IN_IMAGE_MAX) {
|
||||
+ fprintf(stderr, "unsupported VDI image "
|
||||
+ "(too many blocks %u, max is %u)",
|
||||
+ header.blocks_in_image, VDI_BLOCKS_IN_IMAGE_MAX);
|
||||
+ ret = -ENOTSUP;
|
||||
+ goto fail;
|
||||
}
|
||||
|
||||
bs->total_sectors = header.disk_size / SECTOR_SIZE;
|
||||
@@ -668,11 +689,20 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
|
||||
options++;
|
||||
}
|
||||
|
||||
+ if (bytes > VDI_DISK_SIZE_MAX) {
|
||||
+ result = -ENOTSUP;
|
||||
+ fprintf(stderr, "Unsupported VDI image size (size is 0x%" PRIx64
|
||||
+ ", max supported is 0x%" PRIx64 ")",
|
||||
+ bytes, VDI_DISK_SIZE_MAX);
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
fd = qemu_open(filename,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
|
||||
0644);
|
||||
if (fd < 0) {
|
||||
- return -errno;
|
||||
+ result = -errno;
|
||||
+ goto exit;
|
||||
}
|
||||
|
||||
/* We need enough blocks to store the given disk size,
|
||||
@@ -733,6 +763,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
|
||||
result = -errno;
|
||||
}
|
||||
|
||||
+exit:
|
||||
return result;
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
From: Jeff Cody <jcody@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:39 +0100
|
||||
Subject: [PATCH] vhdx: Bounds checking for block_size and logical_sector_size
|
||||
(CVE-2014-0148)
|
||||
|
||||
Other variables (e.g. sectors_per_block) are calculated using these
|
||||
variables, and if not range-checked illegal values could be obtained
|
||||
causing infinite loops and other potential issues when calculating
|
||||
BAT entries.
|
||||
|
||||
The 1.00 VHDX spec requires BlockSize to be min 1MB, max 256MB.
|
||||
LogicalSectorSize is required to be either 512 or 4096 bytes.
|
||||
|
||||
Reported-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Signed-off-by: Jeff Cody <jcody@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 1d7678dec4761acdc43439da6ceda41a703ba1a6)
|
||||
---
|
||||
block/vhdx.c | 12 ++++++++++--
|
||||
block/vhdx.h | 4 ++++
|
||||
2 files changed, 14 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/block/vhdx.c b/block/vhdx.c
|
||||
index e9704b1..36fc06c 100644
|
||||
--- a/block/vhdx.c
|
||||
+++ b/block/vhdx.c
|
||||
@@ -627,12 +627,20 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
|
||||
le32_to_cpus(&s->logical_sector_size);
|
||||
le32_to_cpus(&s->physical_sector_size);
|
||||
|
||||
- if (s->logical_sector_size == 0 || s->params.block_size == 0) {
|
||||
+ if (s->params.block_size < VHDX_BLOCK_SIZE_MIN ||
|
||||
+ s->params.block_size > VHDX_BLOCK_SIZE_MAX) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
- /* both block_size and sector_size are guaranteed powers of 2 */
|
||||
+ /* only 2 supported sector sizes */
|
||||
+ if (s->logical_sector_size != 512 && s->logical_sector_size != 4096) {
|
||||
+ ret = -EINVAL;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ /* Both block_size and sector_size are guaranteed powers of 2, below.
|
||||
+ Due to range checks above, s->sectors_per_block can never be < 256 */
|
||||
s->sectors_per_block = s->params.block_size / s->logical_sector_size;
|
||||
s->chunk_ratio = (VHDX_MAX_SECTORS_PER_BLOCK) *
|
||||
(uint64_t)s->logical_sector_size /
|
||||
diff --git a/block/vhdx.h b/block/vhdx.h
|
||||
index fb687ed..227ac99 100644
|
||||
--- a/block/vhdx.h
|
||||
+++ b/block/vhdx.h
|
||||
@@ -280,6 +280,10 @@ typedef struct QEMU_PACKED VHDXPage83Data {
|
||||
support page 0x83 */
|
||||
} VHDXPage83Data;
|
||||
|
||||
+#define KiB (1 * 1024)
|
||||
+#define MiB (KiB * 1024)
|
||||
+#define VHDX_BLOCK_SIZE_MIN (1 * MiB)
|
||||
+#define VHDX_BLOCK_SIZE_MAX (256 * MiB)
|
||||
typedef struct QEMU_PACKED VHDXVirtualDiskLogicalSectorSize {
|
||||
uint32_t logical_sector_size; /* virtual disk sector size (in bytes).
|
||||
Can only be 512 or 4096 bytes */
|
@ -0,0 +1,36 @@
|
||||
From: Fam Zheng <famz@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:40 +0100
|
||||
Subject: [PATCH] curl: check data size before memcpy to local buffer.
|
||||
(CVE-2014-0144)
|
||||
|
||||
curl_read_cb is callback function for libcurl when data arrives. The
|
||||
data size passed in here is not guaranteed to be within the range of
|
||||
request we submitted, so we may overflow the guest IO buffer. Check the
|
||||
real size we have before memcpy to buffer to avoid overflow.
|
||||
|
||||
Signed-off-by: Fam Zheng <famz@redhat.com>
|
||||
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 6d4b9e55fc625514a38d27cff4b9933f617fa7dc)
|
||||
---
|
||||
block/curl.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/block/curl.c b/block/curl.c
|
||||
index 82d39ff..14ae7e5 100644
|
||||
--- a/block/curl.c
|
||||
+++ b/block/curl.c
|
||||
@@ -136,6 +136,11 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
if (!s || !s->orig_buf)
|
||||
goto read_end;
|
||||
|
||||
+ if (s->buf_off >= s->buf_len) {
|
||||
+ /* buffer full, read nothing */
|
||||
+ return 0;
|
||||
+ }
|
||||
+ realsize = MIN(realsize, s->buf_len - s->buf_off);
|
||||
memcpy(s->orig_buf + s->buf_off, ptr, realsize);
|
||||
s->buf_off += realsize;
|
||||
|
83
0132-qcow2-Check-header_length-CVE-2014-0144.patch
Normal file
83
0132-qcow2-Check-header_length-CVE-2014-0144.patch
Normal file
@ -0,0 +1,83 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:41 +0100
|
||||
Subject: [PATCH] qcow2: Check header_length (CVE-2014-0144)
|
||||
|
||||
This fixes an unbounded allocation for s->unknown_header_fields.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 24342f2cae47d03911e346fe1e520b00dc2818e0)
|
||||
|
||||
Conflicts:
|
||||
block/qcow2.c
|
||||
tests/qemu-iotests/group
|
||||
---
|
||||
block/qcow2.c | 33 +++++++++++++++++++++++++--------
|
||||
1 file changed, 25 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index 44161b2..40867a1 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -355,6 +355,18 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
|
||||
s->qcow_version = header.version;
|
||||
|
||||
+ /* Initialise cluster size */
|
||||
+ if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||
+ header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||
+ fprintf(stderr, "Unsupported cluster size: 2^%i", header.cluster_bits);
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ s->cluster_bits = header.cluster_bits;
|
||||
+ s->cluster_size = 1 << s->cluster_bits;
|
||||
+ s->cluster_sectors = 1 << (s->cluster_bits - 9);
|
||||
+
|
||||
/* Initialise version 3 header fields */
|
||||
if (header.version == 2) {
|
||||
header.incompatible_features = 0;
|
||||
@@ -368,6 +380,18 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
be64_to_cpus(&header.autoclear_features);
|
||||
be32_to_cpus(&header.refcount_order);
|
||||
be32_to_cpus(&header.header_length);
|
||||
+
|
||||
+ if (header.header_length < 104) {
|
||||
+ fprintf(stderr, "qcow2 header too short");
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (header.header_length > s->cluster_size) {
|
||||
+ fprintf(stderr, "qcow2 header exceeds cluster size");
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
}
|
||||
|
||||
if (header.header_length > sizeof(header)) {
|
||||
@@ -410,11 +434,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||
- header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||
- ret = -EINVAL;
|
||||
- goto fail;
|
||||
- }
|
||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
@@ -423,9 +442,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
if (s->crypt_method_header) {
|
||||
bs->encrypted = 1;
|
||||
}
|
||||
- s->cluster_bits = header.cluster_bits;
|
||||
- s->cluster_size = 1 << s->cluster_bits;
|
||||
- s->cluster_sectors = 1 << (s->cluster_bits - 9);
|
||||
+
|
||||
s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
|
||||
s->l2_size = 1 << s->l2_bits;
|
||||
bs->total_sectors = header.size / 512;
|
38
0133-qcow2-Check-backing_file_offset-CVE-2014-0144.patch
Normal file
38
0133-qcow2-Check-backing_file_offset-CVE-2014-0144.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:42 +0100
|
||||
Subject: [PATCH] qcow2: Check backing_file_offset (CVE-2014-0144)
|
||||
|
||||
Header, header extension and the backing file name must all be stored in
|
||||
the first cluster. Setting the backing file to a much higher value
|
||||
allowed header extensions to become much bigger than we want them to be
|
||||
(unbounded allocation).
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit a1b3955c9415b1e767c130a2f59fee6aa28e575b)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/080
|
||||
tests/qemu-iotests/080.out
|
||||
---
|
||||
block/qcow2.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index 40867a1..4392111 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -404,6 +404,12 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
+ if (header.backing_file_offset > s->cluster_size) {
|
||||
+ fprintf(stderr, "Invalid backing file offset");
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
if (header.backing_file_offset) {
|
||||
ext_end = header.backing_file_offset;
|
||||
} else {
|
61
0134-qcow2-Check-refcount-table-size-CVE-2014-0144.patch
Normal file
61
0134-qcow2-Check-refcount-table-size-CVE-2014-0144.patch
Normal file
@ -0,0 +1,61 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:43 +0100
|
||||
Subject: [PATCH] qcow2: Check refcount table size (CVE-2014-0144)
|
||||
|
||||
Limit the in-memory reference count table size to 8 MB, it's enough in
|
||||
practice. This fixes an unbounded allocation as well as a buffer
|
||||
overflow in qcow2_refcount_init().
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 5dab2faddc8eaa1fb1abdbe2f502001fc13a1b21)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/080
|
||||
tests/qemu-iotests/080.out
|
||||
---
|
||||
block/qcow2-refcount.c | 4 +++-
|
||||
block/qcow2.c | 9 +++++++++
|
||||
2 files changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
|
||||
index 1244693..cd641c9 100644
|
||||
--- a/block/qcow2-refcount.c
|
||||
+++ b/block/qcow2-refcount.c
|
||||
@@ -38,8 +38,10 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
int qcow2_refcount_init(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
- int ret, refcount_table_size2, i;
|
||||
+ unsigned int refcount_table_size2, i;
|
||||
+ int ret;
|
||||
|
||||
+ assert(s->refcount_table_size <= INT_MAX / sizeof(uint64_t));
|
||||
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
|
||||
s->refcount_table = g_malloc(refcount_table_size2);
|
||||
if (s->refcount_table_size > 0) {
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index 4392111..884262b 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -455,10 +455,19 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
s->csize_shift = (62 - (s->cluster_bits - 8));
|
||||
s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
|
||||
s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
|
||||
+
|
||||
s->refcount_table_offset = header.refcount_table_offset;
|
||||
s->refcount_table_size =
|
||||
header.refcount_table_clusters << (s->cluster_bits - 3);
|
||||
|
||||
+ if (header.refcount_table_clusters > (0x800000 >> s->cluster_bits)) {
|
||||
+ /* 8 MB refcount table is enough for 2 PB images at 64k cluster size
|
||||
+ * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||
+ fprintf(stderr, "Reference count table too large");
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
s->snapshots_offset = header.snapshots_offset;
|
||||
s->nb_snapshots = header.nb_snapshots;
|
||||
|
74
0135-qcow2-Validate-refcount-table-offset.patch
Normal file
74
0135-qcow2-Validate-refcount-table-offset.patch
Normal file
@ -0,0 +1,74 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:44 +0100
|
||||
Subject: [PATCH] qcow2: Validate refcount table offset
|
||||
|
||||
The end of the refcount table must not exceed INT64_MAX so that integer
|
||||
overflows are avoided.
|
||||
|
||||
Also check for misaligned refcount table. Such images are invalid and
|
||||
probably the result of data corruption. Error out to avoid further
|
||||
corruption.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 8c7de28305a514d7f879fdfc677ca11fbf60d2e9)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/080
|
||||
tests/qemu-iotests/080.out
|
||||
---
|
||||
block/qcow2.c | 33 +++++++++++++++++++++++++++++++++
|
||||
1 file changed, 33 insertions(+)
|
||||
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index 884262b..db35ffe 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -286,6 +286,32 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
|
||||
+ uint64_t entries, size_t entry_len)
|
||||
+{
|
||||
+ BDRVQcowState *s = bs->opaque;
|
||||
+ uint64_t size;
|
||||
+
|
||||
+ /* Use signed INT64_MAX as the maximum even for uint64_t header fields,
|
||||
+ * because values will be passed to qemu functions taking int64_t. */
|
||||
+ if (entries > INT64_MAX / entry_len) {
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ size = entries * entry_len;
|
||||
+
|
||||
+ if (INT64_MAX - size < offset) {
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* Tables must be cluster aligned */
|
||||
+ if (offset & (s->cluster_size - 1)) {
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static QemuOptsList qcow2_runtime_opts = {
|
||||
.name = "qcow2",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
|
||||
@@ -468,6 +494,13 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
+ ret = validate_table_offset(bs, s->refcount_table_offset,
|
||||
+ s->refcount_table_size, sizeof(uint64_t));
|
||||
+ if (ret < 0) {
|
||||
+ fprintf(stderr, "Invalid reference count table offset");
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
s->snapshots_offset = header.snapshots_offset;
|
||||
s->nb_snapshots = header.nb_snapshots;
|
||||
|
148
0136-qcow2-Validate-snapshot-table-offset-size-CVE-2014-0.patch
Normal file
148
0136-qcow2-Validate-snapshot-table-offset-size-CVE-2014-0.patch
Normal file
@ -0,0 +1,148 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:45 +0100
|
||||
Subject: [PATCH] qcow2: Validate snapshot table offset/size (CVE-2014-0144)
|
||||
|
||||
This avoid unbounded memory allocation and fixes a potential buffer
|
||||
overflow on 32 bit hosts.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit ce48f2f441ca98885267af6fd636a7cb804ee646)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/080
|
||||
tests/qemu-iotests/080.out
|
||||
---
|
||||
block/qcow2-snapshot.c | 29 ++++-------------------------
|
||||
block/qcow2.c | 15 +++++++++++++++
|
||||
block/qcow2.h | 29 ++++++++++++++++++++++++++++-
|
||||
3 files changed, 47 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
|
||||
index ae33b45..eb80438 100644
|
||||
--- a/block/qcow2-snapshot.c
|
||||
+++ b/block/qcow2-snapshot.c
|
||||
@@ -26,31 +26,6 @@
|
||||
#include "block/block_int.h"
|
||||
#include "block/qcow2.h"
|
||||
|
||||
-typedef struct QEMU_PACKED QCowSnapshotHeader {
|
||||
- /* header is 8 byte aligned */
|
||||
- uint64_t l1_table_offset;
|
||||
-
|
||||
- uint32_t l1_size;
|
||||
- uint16_t id_str_size;
|
||||
- uint16_t name_size;
|
||||
-
|
||||
- uint32_t date_sec;
|
||||
- uint32_t date_nsec;
|
||||
-
|
||||
- uint64_t vm_clock_nsec;
|
||||
-
|
||||
- uint32_t vm_state_size;
|
||||
- uint32_t extra_data_size; /* for extension */
|
||||
- /* extra data follows */
|
||||
- /* id_str follows */
|
||||
- /* name follows */
|
||||
-} QCowSnapshotHeader;
|
||||
-
|
||||
-typedef struct QEMU_PACKED QCowSnapshotExtraData {
|
||||
- uint64_t vm_state_size_large;
|
||||
- uint64_t disk_size;
|
||||
-} QCowSnapshotExtraData;
|
||||
-
|
||||
void qcow2_free_snapshots(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
@@ -326,6 +301,10 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
uint64_t *l1_table = NULL;
|
||||
int64_t l1_table_offset;
|
||||
|
||||
+ if (s->nb_snapshots >= QCOW_MAX_SNAPSHOTS) {
|
||||
+ return -EFBIG;
|
||||
+ }
|
||||
+
|
||||
memset(sn, 0, sizeof(*sn));
|
||||
|
||||
/* Generate an ID if it wasn't passed */
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index db35ffe..43e2db1 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -501,6 +501,21 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
+ /* Snapshot table offset/length */
|
||||
+ if (header.nb_snapshots > QCOW_MAX_SNAPSHOTS) {
|
||||
+ fprintf(stderr, "Too many snapshots");
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ ret = validate_table_offset(bs, header.snapshots_offset,
|
||||
+ header.nb_snapshots,
|
||||
+ sizeof(QCowSnapshotHeader));
|
||||
+ if (ret < 0) {
|
||||
+ fprintf(stderr, "Invalid snapshot table offset");
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
s->snapshots_offset = header.snapshots_offset;
|
||||
s->nb_snapshots = header.nb_snapshots;
|
||||
|
||||
diff --git a/block/qcow2.h b/block/qcow2.h
|
||||
index da61d18..1e1294c 100644
|
||||
--- a/block/qcow2.h
|
||||
+++ b/block/qcow2.h
|
||||
@@ -38,6 +38,7 @@
|
||||
#define QCOW_CRYPT_AES 1
|
||||
|
||||
#define QCOW_MAX_CRYPT_CLUSTERS 32
|
||||
+#define QCOW_MAX_SNAPSHOTS 65536
|
||||
|
||||
/* indicate that the refcount of the referenced cluster is exactly one. */
|
||||
#define QCOW_OFLAG_COPIED (1LL << 63)
|
||||
@@ -88,6 +89,32 @@ typedef struct QCowHeader {
|
||||
uint32_t header_length;
|
||||
} QCowHeader;
|
||||
|
||||
+typedef struct QEMU_PACKED QCowSnapshotHeader {
|
||||
+ /* header is 8 byte aligned */
|
||||
+ uint64_t l1_table_offset;
|
||||
+
|
||||
+ uint32_t l1_size;
|
||||
+ uint16_t id_str_size;
|
||||
+ uint16_t name_size;
|
||||
+
|
||||
+ uint32_t date_sec;
|
||||
+ uint32_t date_nsec;
|
||||
+
|
||||
+ uint64_t vm_clock_nsec;
|
||||
+
|
||||
+ uint32_t vm_state_size;
|
||||
+ uint32_t extra_data_size; /* for extension */
|
||||
+ /* extra data follows */
|
||||
+ /* id_str follows */
|
||||
+ /* name follows */
|
||||
+} QCowSnapshotHeader;
|
||||
+
|
||||
+typedef struct QEMU_PACKED QCowSnapshotExtraData {
|
||||
+ uint64_t vm_state_size_large;
|
||||
+ uint64_t disk_size;
|
||||
+} QCowSnapshotExtraData;
|
||||
+
|
||||
+
|
||||
typedef struct QCowSnapshot {
|
||||
uint64_t l1_table_offset;
|
||||
uint32_t l1_size;
|
||||
@@ -190,7 +217,7 @@ typedef struct BDRVQcowState {
|
||||
AES_KEY aes_decrypt_key;
|
||||
uint64_t snapshots_offset;
|
||||
int snapshots_size;
|
||||
- int nb_snapshots;
|
||||
+ unsigned int nb_snapshots;
|
||||
QCowSnapshot *snapshots;
|
||||
|
||||
int flags;
|
@ -0,0 +1,54 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:46 +0100
|
||||
Subject: [PATCH] qcow2: Validate active L1 table offset and size
|
||||
(CVE-2014-0144)
|
||||
|
||||
This avoids an unbounded allocation.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 2d51c32c4b511db8bb9e58208f1e2c25e4c06c85)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/080
|
||||
tests/qemu-iotests/080.out
|
||||
---
|
||||
block/qcow2.c | 16 ++++++++++++++++
|
||||
1 file changed, 16 insertions(+)
|
||||
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index 43e2db1..8dd285b 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -520,6 +520,13 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
s->nb_snapshots = header.nb_snapshots;
|
||||
|
||||
/* read the level 1 table */
|
||||
+ if (header.l1_size > 0x2000000) {
|
||||
+ /* 32 MB L1 table is enough for 2 PB images at 64k cluster size
|
||||
+ * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||
+ fprintf(stderr, "Active L1 table too large");
|
||||
+ ret = -EFBIG;
|
||||
+ goto fail;
|
||||
+ }
|
||||
s->l1_size = header.l1_size;
|
||||
|
||||
l1_vm_state_index = size_to_l1(s, header.size);
|
||||
@@ -535,7 +542,16 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
+
|
||||
+ ret = validate_table_offset(bs, header.l1_table_offset,
|
||||
+ header.l1_size, sizeof(uint64_t));
|
||||
+ if (ret < 0) {
|
||||
+ fprintf(stderr, "Invalid L1 table offset");
|
||||
+ goto fail;
|
||||
+ }
|
||||
s->l1_table_offset = header.l1_table_offset;
|
||||
+
|
||||
+
|
||||
if (s->l1_size > 0) {
|
||||
s->l1_table = g_malloc0(
|
||||
align_offset(s->l1_size * sizeof(uint64_t), 512));
|
50
0138-qcow2-Fix-backing-file-name-length-check.patch
Normal file
50
0138-qcow2-Fix-backing-file-name-length-check.patch
Normal file
@ -0,0 +1,50 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:47 +0100
|
||||
Subject: [PATCH] qcow2: Fix backing file name length check
|
||||
|
||||
len could become negative and would pass the check then. Nothing bad
|
||||
happened because bdrv_pread() happens to return an error for negative
|
||||
length values, but make variables for sizes unsigned anyway.
|
||||
|
||||
This patch also changes the behaviour to error out on invalid lengths
|
||||
instead of silently truncating it to 1023.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 6d33e8e7dc9d40ea105feed4b39caa3e641569e8)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/080
|
||||
tests/qemu-iotests/080.out
|
||||
---
|
||||
block/qcow2.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index 8dd285b..10bfaaf 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -344,7 +344,8 @@ static QemuOptsList qcow2_runtime_opts = {
|
||||
static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
- int len, i, ret = 0;
|
||||
+ unsigned int len, i;
|
||||
+ int ret = 0;
|
||||
QCowHeader header;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
@@ -593,8 +594,10 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
/* read the backing file name */
|
||||
if (header.backing_file_offset != 0) {
|
||||
len = header.backing_file_size;
|
||||
- if (len > 1023) {
|
||||
- len = 1023;
|
||||
+ if (len > MIN(1023, s->cluster_size - header.backing_file_offset)) {
|
||||
+ fprintf(stderr, "Backing file name too long");
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
}
|
||||
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
||||
bs->backing_file, len);
|
@ -0,0 +1,46 @@
|
||||
From: Hu Tao <hutao@cn.fujitsu.com>
|
||||
Date: Sun, 26 Jan 2014 11:12:38 +0800
|
||||
Subject: [PATCH] qcow2: fix offset overflow in qcow2_alloc_clusters_at()
|
||||
|
||||
When cluster size is big enough it can lead to an offset overflow
|
||||
in qcow2_alloc_clusters_at(). This patch fixes it.
|
||||
|
||||
The allocation is stopped each time at L2 table boundary
|
||||
(see handle_alloc()), so the possible maximum bytes could be
|
||||
|
||||
2^(cluster_bits - 3 + cluster_bits)
|
||||
|
||||
cluster_bits - 3 is used to compute the number of entry by L2
|
||||
and the additional cluster_bits is to take into account each
|
||||
clusters referenced by the L2 entries.
|
||||
|
||||
so int is safe for cluster_bits<=17, unsafe otherwise.
|
||||
|
||||
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Reviewed-by: Benoit Canet <benoit@irqsave.net>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
(cherry picked from commit 33304ec9fa484e765c6249673e09e1b7d49c5b85)
|
||||
---
|
||||
block/qcow2-refcount.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
|
||||
index cd641c9..1308151 100644
|
||||
--- a/block/qcow2-refcount.c
|
||||
+++ b/block/qcow2-refcount.c
|
||||
@@ -676,7 +676,13 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t cluster_index;
|
||||
uint64_t old_free_cluster_index;
|
||||
- int i, refcount, ret;
|
||||
+ uint64_t i;
|
||||
+ int refcount, ret;
|
||||
+
|
||||
+ assert(nb_clusters >= 0);
|
||||
+ if (nb_clusters == 0) {
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
/* Check how many clusters there are free */
|
||||
cluster_index = offset >> s->cluster_bits;
|
224
0140-qcow2-Don-t-rely-on-free_cluster_index-in-alloc_refc.patch
Normal file
224
0140-qcow2-Don-t-rely-on-free_cluster_index-in-alloc_refc.patch
Normal file
@ -0,0 +1,224 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Fri, 28 Mar 2014 18:06:31 +0100
|
||||
Subject: [PATCH] qcow2: Don't rely on free_cluster_index in
|
||||
alloc_refcount_block() (CVE-2014-0147)
|
||||
|
||||
free_cluster_index is only correct if update_refcount() was called from
|
||||
an allocation function, and even there it's brittle because it's used to
|
||||
protect unfinished allocations which still have a refcount of 0 - if it
|
||||
moves in the wrong place, the unfinished allocation can be corrupted.
|
||||
|
||||
So not using it any more seems to be a good idea. Instead, use the
|
||||
first requested cluster to do the calculations. Return -EAGAIN if
|
||||
unfinished allocations could become invalid and let the caller restart
|
||||
its search for some free clusters.
|
||||
|
||||
The context of creating a snapsnot is one situation where
|
||||
update_refcount() is called outside of a cluster allocation. For this
|
||||
case, the change fixes a buffer overflow if a cluster is referenced in
|
||||
an L2 table that cannot be represented by an existing refcount block.
|
||||
(new_table[refcount_table_index] was out of bounds)
|
||||
|
||||
[Bump the qemu-iotests 026 refblock_alloc.write leak count from 10 to
|
||||
11.
|
||||
--Stefan]
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit b106ad9185f35fc4ad669555ad0e79e276083bd7)
|
||||
|
||||
Conflicts:
|
||||
block/qcow2.c
|
||||
tests/qemu-iotests/080
|
||||
tests/qemu-iotests/080.out
|
||||
---
|
||||
block/qcow2-refcount.c | 72 ++++++++++++++++++++++++++------------------------
|
||||
block/qcow2.c | 11 ++++----
|
||||
2 files changed, 43 insertions(+), 40 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
|
||||
index 1308151..d784dd6 100644
|
||||
--- a/block/qcow2-refcount.c
|
||||
+++ b/block/qcow2-refcount.c
|
||||
@@ -191,10 +191,11 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
* they can describe them themselves.
|
||||
*
|
||||
* - We need to consider that at this point we are inside update_refcounts
|
||||
- * and doing the initial refcount increase. This means that some clusters
|
||||
- * have already been allocated by the caller, but their refcount isn't
|
||||
- * accurate yet. free_cluster_index tells us where this allocation ends
|
||||
- * as long as we don't overwrite it by freeing clusters.
|
||||
+ * and potentially doing an initial refcount increase. This means that
|
||||
+ * some clusters have already been allocated by the caller, but their
|
||||
+ * refcount isn't accurate yet. If we allocate clusters for metadata, we
|
||||
+ * need to return -EAGAIN to signal the caller that it needs to restart
|
||||
+ * the search for free clusters.
|
||||
*
|
||||
* - alloc_clusters_noref and qcow2_free_clusters may load a different
|
||||
* refcount block into the cache
|
||||
@@ -279,7 +280,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
s->refcount_table[refcount_table_index] = new_block;
|
||||
- return 0;
|
||||
+
|
||||
+ /* The new refcount block may be where the caller intended to put its
|
||||
+ * data, so let it restart the search. */
|
||||
+ return -EAGAIN;
|
||||
}
|
||||
|
||||
ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
|
||||
@@ -302,8 +306,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
|
||||
/* Calculate the number of refcount blocks needed so far */
|
||||
uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
|
||||
- uint64_t blocks_used = (s->free_cluster_index +
|
||||
- refcount_block_clusters - 1) / refcount_block_clusters;
|
||||
+ uint64_t blocks_used = DIV_ROUND_UP(cluster_index, refcount_block_clusters);
|
||||
|
||||
/* And now we need at least one block more for the new metadata */
|
||||
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
|
||||
@@ -336,8 +339,6 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
|
||||
uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
|
||||
|
||||
- assert(meta_offset >= (s->free_cluster_index * s->cluster_size));
|
||||
-
|
||||
/* Fill the new refcount table */
|
||||
memcpy(new_table, s->refcount_table,
|
||||
s->refcount_table_size * sizeof(uint64_t));
|
||||
@@ -400,18 +401,19 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
s->refcount_table_size = table_size;
|
||||
s->refcount_table_offset = table_offset;
|
||||
|
||||
- /* Free old table. Remember, we must not change free_cluster_index */
|
||||
- uint64_t old_free_cluster_index = s->free_cluster_index;
|
||||
+ /* Free old table. */
|
||||
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
|
||||
QCOW2_DISCARD_OTHER);
|
||||
- s->free_cluster_index = old_free_cluster_index;
|
||||
|
||||
ret = load_refcount_block(bs, new_block, (void**) refcount_block);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ /* If we were trying to do the initial refcount update for some cluster
|
||||
+ * allocation, we might have used the same clusters to store newly
|
||||
+ * allocated metadata. Make the caller search some new space. */
|
||||
+ return -EAGAIN;
|
||||
|
||||
fail_table:
|
||||
g_free(new_table);
|
||||
@@ -657,12 +659,15 @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
|
||||
int ret;
|
||||
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
|
||||
- offset = alloc_clusters_noref(bs, size);
|
||||
- if (offset < 0) {
|
||||
- return offset;
|
||||
- }
|
||||
+ do {
|
||||
+ offset = alloc_clusters_noref(bs, size);
|
||||
+ if (offset < 0) {
|
||||
+ return offset;
|
||||
+ }
|
||||
+
|
||||
+ ret = update_refcount(bs, offset, size, 1, QCOW2_DISCARD_NEVER);
|
||||
+ } while (ret == -EAGAIN);
|
||||
|
||||
- ret = update_refcount(bs, offset, size, 1, QCOW2_DISCARD_NEVER);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -675,7 +680,6 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t cluster_index;
|
||||
- uint64_t old_free_cluster_index;
|
||||
uint64_t i;
|
||||
int refcount, ret;
|
||||
|
||||
@@ -684,30 +688,28 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
- /* Check how many clusters there are free */
|
||||
- cluster_index = offset >> s->cluster_bits;
|
||||
- for(i = 0; i < nb_clusters; i++) {
|
||||
- refcount = get_refcount(bs, cluster_index++);
|
||||
+ do {
|
||||
+ /* Check how many clusters there are free */
|
||||
+ cluster_index = offset >> s->cluster_bits;
|
||||
+ for(i = 0; i < nb_clusters; i++) {
|
||||
+ refcount = get_refcount(bs, cluster_index++);
|
||||
|
||||
- if (refcount < 0) {
|
||||
- return refcount;
|
||||
- } else if (refcount != 0) {
|
||||
- break;
|
||||
+ if (refcount < 0) {
|
||||
+ return refcount;
|
||||
+ } else if (refcount != 0) {
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
- }
|
||||
|
||||
- /* And then allocate them */
|
||||
- old_free_cluster_index = s->free_cluster_index;
|
||||
- s->free_cluster_index = cluster_index + i;
|
||||
+ /* And then allocate them */
|
||||
+ ret = update_refcount(bs, offset, i << s->cluster_bits, 1,
|
||||
+ QCOW2_DISCARD_NEVER);
|
||||
+ } while (ret == -EAGAIN);
|
||||
|
||||
- ret = update_refcount(bs, offset, i << s->cluster_bits, 1,
|
||||
- QCOW2_DISCARD_NEVER);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
- s->free_cluster_index = old_free_cluster_index;
|
||||
-
|
||||
return i;
|
||||
}
|
||||
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index 10bfaaf..5d45036 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -1385,7 +1385,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
*/
|
||||
BlockDriverState* bs;
|
||||
QCowHeader *header;
|
||||
- uint8_t* refcount_table;
|
||||
+ uint64_t* refcount_table;
|
||||
int ret;
|
||||
|
||||
ret = bdrv_create_file(filename, options);
|
||||
@@ -1431,9 +1431,10 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- /* Write an empty refcount table */
|
||||
- refcount_table = g_malloc0(cluster_size);
|
||||
- ret = bdrv_pwrite(bs, cluster_size, refcount_table, cluster_size);
|
||||
+ /* Write a refcount table with one refcount block */
|
||||
+ refcount_table = g_malloc0(2 * cluster_size);
|
||||
+ refcount_table[0] = cpu_to_be64(2 * cluster_size);
|
||||
+ ret = bdrv_pwrite(bs, cluster_size, refcount_table, 2 * cluster_size);
|
||||
g_free(refcount_table);
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -1455,7 +1456,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- ret = qcow2_alloc_clusters(bs, 2 * cluster_size);
|
||||
+ ret = qcow2_alloc_clusters(bs, 3 * cluster_size);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
|
@ -0,0 +1,28 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:49 +0100
|
||||
Subject: [PATCH] qcow2: Avoid integer overflow in get_refcount (CVE-2014-0143)
|
||||
|
||||
This ensures that the checks catch all invalid cluster indexes
|
||||
instead of returning the refcount of a wrong cluster.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit db8a31d11d6a60f48d6817530640d75aa72a9a2f)
|
||||
---
|
||||
block/qcow2-refcount.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
|
||||
index d784dd6..3e473bd 100644
|
||||
--- a/block/qcow2-refcount.c
|
||||
+++ b/block/qcow2-refcount.c
|
||||
@@ -87,7 +87,7 @@ static int load_refcount_block(BlockDriverState *bs,
|
||||
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
- int refcount_table_index, block_index;
|
||||
+ uint64_t refcount_table_index, block_index;
|
||||
int64_t refcount_block_offset;
|
||||
int ret;
|
||||
uint16_t *refcount_block;
|
77
0142-qcow2-Check-new-refcount-table-size-on-growth.patch
Normal file
77
0142-qcow2-Check-new-refcount-table-size-on-growth.patch
Normal file
@ -0,0 +1,77 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:50 +0100
|
||||
Subject: [PATCH] qcow2: Check new refcount table size on growth
|
||||
|
||||
If the size becomes larger than what qcow2_open() would accept, fail the
|
||||
growing operation.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 2b5d5953eec0cc541857c3df812bdf8421596ab2)
|
||||
|
||||
Conflicts:
|
||||
block/qcow2.c
|
||||
---
|
||||
block/qcow2-refcount.c | 4 ++++
|
||||
block/qcow2.c | 4 +---
|
||||
block/qcow2.h | 9 +++++++++
|
||||
3 files changed, 14 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
|
||||
index 3e473bd..3cdcfb6 100644
|
||||
--- a/block/qcow2-refcount.c
|
||||
+++ b/block/qcow2-refcount.c
|
||||
@@ -308,6 +308,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
|
||||
uint64_t blocks_used = DIV_ROUND_UP(cluster_index, refcount_block_clusters);
|
||||
|
||||
+ if (blocks_used > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) {
|
||||
+ return -EFBIG;
|
||||
+ }
|
||||
+
|
||||
/* And now we need at least one block more for the new metadata */
|
||||
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
|
||||
uint64_t last_table_size;
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index 5d45036..af0a45c 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -487,9 +487,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
s->refcount_table_size =
|
||||
header.refcount_table_clusters << (s->cluster_bits - 3);
|
||||
|
||||
- if (header.refcount_table_clusters > (0x800000 >> s->cluster_bits)) {
|
||||
- /* 8 MB refcount table is enough for 2 PB images at 64k cluster size
|
||||
- * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||
+ if (header.refcount_table_clusters > qcow2_max_refcount_clusters(s)) {
|
||||
fprintf(stderr, "Reference count table too large");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
diff --git a/block/qcow2.h b/block/qcow2.h
|
||||
index 1e1294c..e802c55 100644
|
||||
--- a/block/qcow2.h
|
||||
+++ b/block/qcow2.h
|
||||
@@ -40,6 +40,10 @@
|
||||
#define QCOW_MAX_CRYPT_CLUSTERS 32
|
||||
#define QCOW_MAX_SNAPSHOTS 65536
|
||||
|
||||
+/* 8 MB refcount table is enough for 2 PB images at 64k cluster size
|
||||
+ * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||
+#define QCOW_MAX_REFTABLE_SIZE 0x800000
|
||||
+
|
||||
/* indicate that the refcount of the referenced cluster is exactly one. */
|
||||
#define QCOW_OFLAG_COPIED (1LL << 63)
|
||||
/* indicate that the cluster is compressed (they never have the copied flag) */
|
||||
@@ -356,6 +360,11 @@ static inline int64_t qcow2_vm_state_offset(BDRVQcowState *s)
|
||||
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
|
||||
}
|
||||
|
||||
+static inline uint64_t qcow2_max_refcount_clusters(BDRVQcowState *s)
|
||||
+{
|
||||
+ return QCOW_MAX_REFTABLE_SIZE >> s->cluster_bits;
|
||||
+}
|
||||
+
|
||||
static inline int qcow2_get_cluster_type(uint64_t l2_entry)
|
||||
{
|
||||
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
|
@ -0,0 +1,85 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:51 +0100
|
||||
Subject: [PATCH] qcow2: Fix types in qcow2_alloc_clusters and
|
||||
alloc_clusters_noref
|
||||
|
||||
In order to avoid integer overflows.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit bb572aefbdac290363bfa5ca0e810ccce0a14ed6)
|
||||
|
||||
Conflicts:
|
||||
block/qcow2.h
|
||||
---
|
||||
block/qcow2-refcount.c | 11 ++++++-----
|
||||
block/qcow2.h | 6 +++---
|
||||
2 files changed, 9 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
|
||||
index 3cdcfb6..d424c22 100644
|
||||
--- a/block/qcow2-refcount.c
|
||||
+++ b/block/qcow2-refcount.c
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "block/block_int.h"
|
||||
#include "block/qcow2.h"
|
||||
|
||||
-static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
|
||||
+static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size);
|
||||
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
int64_t offset, int64_t length,
|
||||
int addend, enum qcow2_discard_type type);
|
||||
@@ -632,15 +632,16 @@ static int update_cluster_refcount(BlockDriverState *bs,
|
||||
|
||||
|
||||
/* return < 0 if error */
|
||||
-static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
|
||||
+static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
- int i, nb_clusters, refcount;
|
||||
+ uint64_t i, nb_clusters;
|
||||
+ int refcount;
|
||||
|
||||
nb_clusters = size_to_clusters(s, size);
|
||||
retry:
|
||||
for(i = 0; i < nb_clusters; i++) {
|
||||
- int64_t next_cluster_index = s->free_cluster_index++;
|
||||
+ uint64_t next_cluster_index = s->free_cluster_index++;
|
||||
refcount = get_refcount(bs, next_cluster_index);
|
||||
|
||||
if (refcount < 0) {
|
||||
@@ -657,7 +658,7 @@ retry:
|
||||
return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
|
||||
}
|
||||
|
||||
-int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
|
||||
+int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
|
||||
{
|
||||
int64_t offset;
|
||||
int ret;
|
||||
diff --git a/block/qcow2.h b/block/qcow2.h
|
||||
index e802c55..baf62a0 100644
|
||||
--- a/block/qcow2.h
|
||||
+++ b/block/qcow2.h
|
||||
@@ -210,8 +210,8 @@ typedef struct BDRVQcowState {
|
||||
uint64_t *refcount_table;
|
||||
uint64_t refcount_table_offset;
|
||||
uint32_t refcount_table_size;
|
||||
- int64_t free_cluster_index;
|
||||
- int64_t free_byte_offset;
|
||||
+ uint64_t free_cluster_index;
|
||||
+ uint64_t free_byte_offset;
|
||||
|
||||
CoMutex lock;
|
||||
|
||||
@@ -408,7 +408,7 @@ int qcow2_update_header(BlockDriverState *bs);
|
||||
int qcow2_refcount_init(BlockDriverState *bs);
|
||||
void qcow2_refcount_close(BlockDriverState *bs);
|
||||
|
||||
-int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size);
|
||||
+int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
|
||||
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
int nb_clusters);
|
||||
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
|
@ -0,0 +1,61 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:52 +0100
|
||||
Subject: [PATCH] qcow2: Protect against some integer overflows in bdrv_check
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 0abe740f1de899737242bcba1fb4a9857f7a3087)
|
||||
---
|
||||
block/qcow2-refcount.c | 18 +++++++++---------
|
||||
1 file changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
|
||||
index d424c22..fc2d367 100644
|
||||
--- a/block/qcow2-refcount.c
|
||||
+++ b/block/qcow2-refcount.c
|
||||
@@ -997,8 +997,7 @@ static void inc_refcounts(BlockDriverState *bs,
|
||||
int64_t offset, int64_t size)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
- int64_t start, last, cluster_offset;
|
||||
- int k;
|
||||
+ uint64_t start, last, cluster_offset, k;
|
||||
|
||||
if (size <= 0)
|
||||
return;
|
||||
@@ -1008,11 +1007,7 @@ static void inc_refcounts(BlockDriverState *bs,
|
||||
for(cluster_offset = start; cluster_offset <= last;
|
||||
cluster_offset += s->cluster_size) {
|
||||
k = cluster_offset >> s->cluster_bits;
|
||||
- if (k < 0) {
|
||||
- fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
|
||||
- cluster_offset);
|
||||
- res->corruptions++;
|
||||
- } else if (k >= refcount_table_size) {
|
||||
+ if (k >= refcount_table_size) {
|
||||
fprintf(stderr, "Warning: cluster offset=0x%" PRIx64 " is after "
|
||||
"the end of the image file, can't properly check refcounts.\n",
|
||||
cluster_offset);
|
||||
@@ -1253,14 +1248,19 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
BdrvCheckMode fix)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
- int64_t size, i, highest_cluster;
|
||||
- int nb_clusters, refcount1, refcount2;
|
||||
+ int64_t size, i, highest_cluster, nb_clusters;
|
||||
+ int refcount1, refcount2;
|
||||
QCowSnapshot *sn;
|
||||
uint16_t *refcount_table;
|
||||
int ret;
|
||||
|
||||
size = bdrv_getlength(bs->file);
|
||||
nb_clusters = size_to_clusters(s, size);
|
||||
+ if (nb_clusters > INT_MAX) {
|
||||
+ res->check_errors++;
|
||||
+ return -EFBIG;
|
||||
+ }
|
||||
+
|
||||
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
|
||||
|
||||
res->bfi.total_clusters =
|
28
0145-qcow2-Fix-new-L1-table-size-check-CVE-2014-0143.patch
Normal file
28
0145-qcow2-Fix-new-L1-table-size-check-CVE-2014-0143.patch
Normal file
@ -0,0 +1,28 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:53 +0100
|
||||
Subject: [PATCH] qcow2: Fix new L1 table size check (CVE-2014-0143)
|
||||
|
||||
The size in bytes is assigned to an int later, so check that instead of
|
||||
the number of entries.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit cab60de930684c33f67d4e32c7509b567f8c445b)
|
||||
---
|
||||
block/qcow2-cluster.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
|
||||
index 09abbf0..06e3e14 100644
|
||||
--- a/block/qcow2-cluster.c
|
||||
+++ b/block/qcow2-cluster.c
|
||||
@@ -54,7 +54,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||
}
|
||||
}
|
||||
|
||||
- if (new_l1_size > INT_MAX) {
|
||||
+ if (new_l1_size > INT_MAX / sizeof(uint64_t)) {
|
||||
return -EFBIG;
|
||||
}
|
||||
|
321
0146-dmg-coding-style-and-indentation-cleanup.patch
Normal file
321
0146-dmg-coding-style-and-indentation-cleanup.patch
Normal file
@ -0,0 +1,321 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:54 +0100
|
||||
Subject: [PATCH] dmg: coding style and indentation cleanup
|
||||
|
||||
Clean up the mix of tabs and spaces, as well as the coding style
|
||||
violations in block/dmg.c. There are no semantic changes since this
|
||||
patch simply reformats the code.
|
||||
|
||||
This patch is necessary before we can make meaningful changes to this
|
||||
file, due to the inconsistent formatting and confusing indentation.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 2c1885adcf0312da80c7317b09f9adad97fa0fc6)
|
||||
---
|
||||
block/dmg.c | 224 ++++++++++++++++++++++++++++++++----------------------------
|
||||
1 file changed, 120 insertions(+), 104 deletions(-)
|
||||
|
||||
diff --git a/block/dmg.c b/block/dmg.c
|
||||
index 3141cb5..e8b88dc 100644
|
||||
--- a/block/dmg.c
|
||||
+++ b/block/dmg.c
|
||||
@@ -95,9 +95,9 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
|
||||
static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
- uint64_t info_begin,info_end,last_in_offset,last_out_offset;
|
||||
+ uint64_t info_begin, info_end, last_in_offset, last_out_offset;
|
||||
uint32_t count, tmp;
|
||||
- uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
|
||||
+ uint32_t max_compressed_size = 1, max_sectors_per_chunk = 1, i;
|
||||
int64_t offset;
|
||||
int ret;
|
||||
|
||||
@@ -159,37 +159,39 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- if (type == 0x6d697368 && count >= 244) {
|
||||
- int new_size, chunk_count;
|
||||
+ if (type == 0x6d697368 && count >= 244) {
|
||||
+ int new_size, chunk_count;
|
||||
|
||||
offset += 4;
|
||||
offset += 200;
|
||||
|
||||
- chunk_count = (count-204)/40;
|
||||
- new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
||||
- s->types = g_realloc(s->types, new_size/2);
|
||||
- s->offsets = g_realloc(s->offsets, new_size);
|
||||
- s->lengths = g_realloc(s->lengths, new_size);
|
||||
- s->sectors = g_realloc(s->sectors, new_size);
|
||||
- s->sectorcounts = g_realloc(s->sectorcounts, new_size);
|
||||
+ chunk_count = (count - 204) / 40;
|
||||
+ new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
|
||||
+ s->types = g_realloc(s->types, new_size / 2);
|
||||
+ s->offsets = g_realloc(s->offsets, new_size);
|
||||
+ s->lengths = g_realloc(s->lengths, new_size);
|
||||
+ s->sectors = g_realloc(s->sectors, new_size);
|
||||
+ s->sectorcounts = g_realloc(s->sectorcounts, new_size);
|
||||
|
||||
for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) {
|
||||
ret = read_uint32(bs, offset, &s->types[i]);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
- offset += 4;
|
||||
- if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
|
||||
- if(s->types[i]==0xffffffff) {
|
||||
- last_in_offset = s->offsets[i-1]+s->lengths[i-1];
|
||||
- last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1];
|
||||
- }
|
||||
- chunk_count--;
|
||||
- i--;
|
||||
- offset += 36;
|
||||
- continue;
|
||||
- }
|
||||
- offset += 4;
|
||||
+ offset += 4;
|
||||
+ if (s->types[i] != 0x80000005 && s->types[i] != 1 &&
|
||||
+ s->types[i] != 2) {
|
||||
+ if (s->types[i] == 0xffffffff) {
|
||||
+ last_in_offset = s->offsets[i - 1] + s->lengths[i - 1];
|
||||
+ last_out_offset = s->sectors[i - 1] +
|
||||
+ s->sectorcounts[i - 1];
|
||||
+ }
|
||||
+ chunk_count--;
|
||||
+ i--;
|
||||
+ offset += 36;
|
||||
+ continue;
|
||||
+ }
|
||||
+ offset += 4;
|
||||
|
||||
ret = read_uint64(bs, offset, &s->sectors[i]);
|
||||
if (ret < 0) {
|
||||
@@ -217,19 +219,21 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
}
|
||||
offset += 8;
|
||||
|
||||
- if(s->lengths[i]>max_compressed_size)
|
||||
- max_compressed_size = s->lengths[i];
|
||||
- if(s->sectorcounts[i]>max_sectors_per_chunk)
|
||||
- max_sectors_per_chunk = s->sectorcounts[i];
|
||||
- }
|
||||
- s->n_chunks+=chunk_count;
|
||||
- }
|
||||
+ if (s->lengths[i] > max_compressed_size) {
|
||||
+ max_compressed_size = s->lengths[i];
|
||||
+ }
|
||||
+ if (s->sectorcounts[i] > max_sectors_per_chunk) {
|
||||
+ max_sectors_per_chunk = s->sectorcounts[i];
|
||||
+ }
|
||||
+ }
|
||||
+ s->n_chunks += chunk_count;
|
||||
+ }
|
||||
}
|
||||
|
||||
/* initialize zlib engine */
|
||||
- s->compressed_chunk = g_malloc(max_compressed_size+1);
|
||||
- s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk);
|
||||
- if(inflateInit(&s->zstream) != Z_OK) {
|
||||
+ s->compressed_chunk = g_malloc(max_compressed_size + 1);
|
||||
+ s->uncompressed_chunk = g_malloc(512 * max_sectors_per_chunk);
|
||||
+ if (inflateInit(&s->zstream) != Z_OK) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
@@ -251,27 +255,29 @@ fail:
|
||||
}
|
||||
|
||||
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
||||
- uint32_t chunk_num,int sector_num)
|
||||
+ uint32_t chunk_num, int sector_num)
|
||||
{
|
||||
- if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num ||
|
||||
- s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num)
|
||||
- return 0;
|
||||
- else
|
||||
- return -1;
|
||||
+ if (chunk_num >= s->n_chunks || s->sectors[chunk_num] > sector_num ||
|
||||
+ s->sectors[chunk_num] + s->sectorcounts[chunk_num] <= sector_num) {
|
||||
+ return 0;
|
||||
+ } else {
|
||||
+ return -1;
|
||||
+ }
|
||||
}
|
||||
|
||||
-static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
|
||||
+static inline uint32_t search_chunk(BDRVDMGState *s, int sector_num)
|
||||
{
|
||||
/* binary search */
|
||||
- uint32_t chunk1=0,chunk2=s->n_chunks,chunk3;
|
||||
- while(chunk1!=chunk2) {
|
||||
- chunk3 = (chunk1+chunk2)/2;
|
||||
- if(s->sectors[chunk3]>sector_num)
|
||||
- chunk2 = chunk3;
|
||||
- else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num)
|
||||
- return chunk3;
|
||||
- else
|
||||
- chunk1 = chunk3;
|
||||
+ uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3;
|
||||
+ while (chunk1 != chunk2) {
|
||||
+ chunk3 = (chunk1 + chunk2) / 2;
|
||||
+ if (s->sectors[chunk3] > sector_num) {
|
||||
+ chunk2 = chunk3;
|
||||
+ } else if (s->sectors[chunk3] + s->sectorcounts[chunk3] > sector_num) {
|
||||
+ return chunk3;
|
||||
+ } else {
|
||||
+ chunk1 = chunk3;
|
||||
+ }
|
||||
}
|
||||
return s->n_chunks; /* error */
|
||||
}
|
||||
@@ -280,54 +286,62 @@ static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
|
||||
- if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
|
||||
- int ret;
|
||||
- uint32_t chunk = search_chunk(s,sector_num);
|
||||
+ if (!is_sector_in_chunk(s, s->current_chunk, sector_num)) {
|
||||
+ int ret;
|
||||
+ uint32_t chunk = search_chunk(s, sector_num);
|
||||
|
||||
- if(chunk>=s->n_chunks)
|
||||
- return -1;
|
||||
+ if (chunk >= s->n_chunks) {
|
||||
+ return -1;
|
||||
+ }
|
||||
|
||||
- s->current_chunk = s->n_chunks;
|
||||
- switch(s->types[chunk]) {
|
||||
- case 0x80000005: { /* zlib compressed */
|
||||
- int i;
|
||||
+ s->current_chunk = s->n_chunks;
|
||||
+ switch (s->types[chunk]) {
|
||||
+ case 0x80000005: { /* zlib compressed */
|
||||
+ int i;
|
||||
|
||||
- /* we need to buffer, because only the chunk as whole can be
|
||||
- * inflated. */
|
||||
- i=0;
|
||||
- do {
|
||||
+ /* we need to buffer, because only the chunk as whole can be
|
||||
+ * inflated. */
|
||||
+ i = 0;
|
||||
+ do {
|
||||
ret = bdrv_pread(bs->file, s->offsets[chunk] + i,
|
||||
- s->compressed_chunk+i, s->lengths[chunk]-i);
|
||||
- if(ret<0 && errno==EINTR)
|
||||
- ret=0;
|
||||
- i+=ret;
|
||||
- } while(ret>=0 && ret+i<s->lengths[chunk]);
|
||||
-
|
||||
- if (ret != s->lengths[chunk])
|
||||
- return -1;
|
||||
-
|
||||
- s->zstream.next_in = s->compressed_chunk;
|
||||
- s->zstream.avail_in = s->lengths[chunk];
|
||||
- s->zstream.next_out = s->uncompressed_chunk;
|
||||
- s->zstream.avail_out = 512*s->sectorcounts[chunk];
|
||||
- ret = inflateReset(&s->zstream);
|
||||
- if(ret != Z_OK)
|
||||
- return -1;
|
||||
- ret = inflate(&s->zstream, Z_FINISH);
|
||||
- if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk])
|
||||
- return -1;
|
||||
- break; }
|
||||
- case 1: /* copy */
|
||||
- ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||
+ s->compressed_chunk + i,
|
||||
+ s->lengths[chunk] - i);
|
||||
+ if (ret < 0 && errno == EINTR) {
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ i += ret;
|
||||
+ } while (ret >= 0 && ret + i < s->lengths[chunk]);
|
||||
+
|
||||
+ if (ret != s->lengths[chunk]) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ s->zstream.next_in = s->compressed_chunk;
|
||||
+ s->zstream.avail_in = s->lengths[chunk];
|
||||
+ s->zstream.next_out = s->uncompressed_chunk;
|
||||
+ s->zstream.avail_out = 512 * s->sectorcounts[chunk];
|
||||
+ ret = inflateReset(&s->zstream);
|
||||
+ if (ret != Z_OK) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+ ret = inflate(&s->zstream, Z_FINISH);
|
||||
+ if (ret != Z_STREAM_END ||
|
||||
+ s->zstream.total_out != 512 * s->sectorcounts[chunk]) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+ break; }
|
||||
+ case 1: /* copy */
|
||||
+ ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||
s->uncompressed_chunk, s->lengths[chunk]);
|
||||
- if (ret != s->lengths[chunk])
|
||||
- return -1;
|
||||
- break;
|
||||
- case 2: /* zero */
|
||||
- memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]);
|
||||
- break;
|
||||
- }
|
||||
- s->current_chunk = chunk;
|
||||
+ if (ret != s->lengths[chunk]) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+ break;
|
||||
+ case 2: /* zero */
|
||||
+ memset(s->uncompressed_chunk, 0, 512 * s->sectorcounts[chunk]);
|
||||
+ break;
|
||||
+ }
|
||||
+ s->current_chunk = chunk;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -338,12 +352,14 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num,
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
int i;
|
||||
|
||||
- for(i=0;i<nb_sectors;i++) {
|
||||
- uint32_t sector_offset_in_chunk;
|
||||
- if(dmg_read_chunk(bs, sector_num+i) != 0)
|
||||
- return -1;
|
||||
- sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
|
||||
- memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
|
||||
+ for (i = 0; i < nb_sectors; i++) {
|
||||
+ uint32_t sector_offset_in_chunk;
|
||||
+ if (dmg_read_chunk(bs, sector_num + i) != 0) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+ sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk];
|
||||
+ memcpy(buf + i * 512,
|
||||
+ s->uncompressed_chunk + sector_offset_in_chunk * 512, 512);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -375,12 +391,12 @@ static void dmg_close(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_dmg = {
|
||||
- .format_name = "dmg",
|
||||
- .instance_size = sizeof(BDRVDMGState),
|
||||
- .bdrv_probe = dmg_probe,
|
||||
- .bdrv_open = dmg_open,
|
||||
- .bdrv_read = dmg_co_read,
|
||||
- .bdrv_close = dmg_close,
|
||||
+ .format_name = "dmg",
|
||||
+ .instance_size = sizeof(BDRVDMGState),
|
||||
+ .bdrv_probe = dmg_probe,
|
||||
+ .bdrv_open = dmg_open,
|
||||
+ .bdrv_read = dmg_co_read,
|
||||
+ .bdrv_close = dmg_close,
|
||||
};
|
||||
|
||||
static void bdrv_dmg_init(void)
|
@ -0,0 +1,33 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:55 +0100
|
||||
Subject: [PATCH] dmg: prevent out-of-bounds array access on terminator
|
||||
|
||||
When a terminator is reached the base for offsets and sectors is stored.
|
||||
The following records that are processed will use this base value.
|
||||
|
||||
If the first record we encounter is a terminator, then calculating the
|
||||
base values would result in out-of-bounds array accesses. Don't do
|
||||
that.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 73ed27ec28a1dbebdd2ae792284151f029950fbe)
|
||||
---
|
||||
block/dmg.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/dmg.c b/block/dmg.c
|
||||
index e8b88dc..cb4060c 100644
|
||||
--- a/block/dmg.c
|
||||
+++ b/block/dmg.c
|
||||
@@ -181,7 +181,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
offset += 4;
|
||||
if (s->types[i] != 0x80000005 && s->types[i] != 1 &&
|
||||
s->types[i] != 2) {
|
||||
- if (s->types[i] == 0xffffffff) {
|
||||
+ if (s->types[i] == 0xffffffff && i > 0) {
|
||||
last_in_offset = s->offsets[i - 1] + s->lengths[i - 1];
|
||||
last_out_offset = s->sectors[i - 1] +
|
||||
s->sectorcounts[i - 1];
|
56
0148-dmg-drop-broken-bdrv_pread-loop.patch
Normal file
56
0148-dmg-drop-broken-bdrv_pread-loop.patch
Normal file
@ -0,0 +1,56 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:56 +0100
|
||||
Subject: [PATCH] dmg: drop broken bdrv_pread() loop
|
||||
|
||||
It is not necessary to check errno for EINTR and the block layer does
|
||||
not produce short reads. Therefore we can drop the loop that attempts
|
||||
to read a compressed chunk.
|
||||
|
||||
The loop is buggy because it incorrectly adds the transferred bytes
|
||||
twice:
|
||||
|
||||
do {
|
||||
ret = bdrv_pread(...);
|
||||
i += ret;
|
||||
} while (ret >= 0 && ret + i < s->lengths[chunk]);
|
||||
|
||||
Luckily we can drop the loop completely and perform a single
|
||||
bdrv_pread().
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit b404bf854217dbe8a5649449eb3ad33777f7d900)
|
||||
---
|
||||
block/dmg.c | 15 ++-------------
|
||||
1 file changed, 2 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/block/dmg.c b/block/dmg.c
|
||||
index cb4060c..24f08ef 100644
|
||||
--- a/block/dmg.c
|
||||
+++ b/block/dmg.c
|
||||
@@ -297,21 +297,10 @@ static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
|
||||
s->current_chunk = s->n_chunks;
|
||||
switch (s->types[chunk]) {
|
||||
case 0x80000005: { /* zlib compressed */
|
||||
- int i;
|
||||
-
|
||||
/* we need to buffer, because only the chunk as whole can be
|
||||
* inflated. */
|
||||
- i = 0;
|
||||
- do {
|
||||
- ret = bdrv_pread(bs->file, s->offsets[chunk] + i,
|
||||
- s->compressed_chunk + i,
|
||||
- s->lengths[chunk] - i);
|
||||
- if (ret < 0 && errno == EINTR) {
|
||||
- ret = 0;
|
||||
- }
|
||||
- i += ret;
|
||||
- } while (ret >= 0 && ret + i < s->lengths[chunk]);
|
||||
-
|
||||
+ ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||
+ s->compressed_chunk, s->lengths[chunk]);
|
||||
if (ret != s->lengths[chunk]) {
|
||||
return -1;
|
||||
}
|
41
0149-dmg-use-appropriate-types-when-reading-chunks.patch
Normal file
41
0149-dmg-use-appropriate-types-when-reading-chunks.patch
Normal file
@ -0,0 +1,41 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:57 +0100
|
||||
Subject: [PATCH] dmg: use appropriate types when reading chunks
|
||||
|
||||
Use the right types instead of signed int:
|
||||
|
||||
size_t new_size;
|
||||
|
||||
This is a byte count for g_realloc() that is calculated from uint32_t
|
||||
and size_t values.
|
||||
|
||||
uint32_t chunk_count;
|
||||
|
||||
Use the same type as s->n_chunks, which is used together with
|
||||
chunk_count.
|
||||
|
||||
This patch is a cleanup and does not fix bugs.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit eb71803b041f55779ea10d860c0f66df285c68de)
|
||||
---
|
||||
block/dmg.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/dmg.c b/block/dmg.c
|
||||
index 24f08ef..5650e73 100644
|
||||
--- a/block/dmg.c
|
||||
+++ b/block/dmg.c
|
||||
@@ -160,7 +160,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
}
|
||||
|
||||
if (type == 0x6d697368 && count >= 244) {
|
||||
- int new_size, chunk_count;
|
||||
+ size_t new_size;
|
||||
+ uint32_t chunk_count;
|
||||
|
||||
offset += 4;
|
||||
offset += 200;
|
@ -0,0 +1,67 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:58 +0100
|
||||
Subject: [PATCH] dmg: sanitize chunk length and sectorcount (CVE-2014-0145)
|
||||
|
||||
Chunk length and sectorcount are used for decompression buffers as well
|
||||
as the bdrv_pread() count argument. Ensure that they have reasonable
|
||||
values so neither memory allocation nor conversion from uint64_t to int
|
||||
will cause problems.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit c165f7758009a4f793c1fc19ebb69cf55313450b)
|
||||
---
|
||||
block/dmg.c | 24 ++++++++++++++++++++++++
|
||||
1 file changed, 24 insertions(+)
|
||||
|
||||
diff --git a/block/dmg.c b/block/dmg.c
|
||||
index 5650e73..1a751ea 100644
|
||||
--- a/block/dmg.c
|
||||
+++ b/block/dmg.c
|
||||
@@ -27,6 +27,14 @@
|
||||
#include "qemu/module.h"
|
||||
#include <zlib.h>
|
||||
|
||||
+enum {
|
||||
+ /* Limit chunk sizes to prevent unreasonable amounts of memory being used
|
||||
+ * or truncating when converting to 32-bit types
|
||||
+ */
|
||||
+ DMG_LENGTHS_MAX = 64 * 1024 * 1024, /* 64 MB */
|
||||
+ DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
|
||||
+};
|
||||
+
|
||||
typedef struct BDRVDMGState {
|
||||
CoMutex lock;
|
||||
/* each chunk contains a certain number of sectors,
|
||||
@@ -207,6 +215,14 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
}
|
||||
offset += 8;
|
||||
|
||||
+ if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
|
||||
+ error_report("sector count %" PRIu64 " for chunk %u is "
|
||||
+ "larger than max (%u)",
|
||||
+ s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
ret = read_uint64(bs, offset, &s->offsets[i]);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
@@ -220,6 +236,14 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
}
|
||||
offset += 8;
|
||||
|
||||
+ if (s->lengths[i] > DMG_LENGTHS_MAX) {
|
||||
+ error_report("length %" PRIu64 " for chunk %u is larger "
|
||||
+ "than max (%u)",
|
||||
+ s->lengths[i], i, DMG_LENGTHS_MAX);
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
if (s->lengths[i] > max_compressed_size) {
|
||||
max_compressed_size = s->lengths[i];
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:05:59 +0100
|
||||
Subject: [PATCH] dmg: use uint64_t consistently for sectors and lengths
|
||||
|
||||
The DMG metadata is stored as uint64_t, so use the same type for
|
||||
sector_num. int was a particularly poor choice since it is only 32-bit
|
||||
and would truncate large values.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 686d7148ec23402a172628c800022b3a95a022c9)
|
||||
---
|
||||
block/dmg.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/block/dmg.c b/block/dmg.c
|
||||
index 1a751ea..5229876 100644
|
||||
--- a/block/dmg.c
|
||||
+++ b/block/dmg.c
|
||||
@@ -280,7 +280,7 @@ fail:
|
||||
}
|
||||
|
||||
static inline int is_sector_in_chunk(BDRVDMGState* s,
|
||||
- uint32_t chunk_num, int sector_num)
|
||||
+ uint32_t chunk_num, uint64_t sector_num)
|
||||
{
|
||||
if (chunk_num >= s->n_chunks || s->sectors[chunk_num] > sector_num ||
|
||||
s->sectors[chunk_num] + s->sectorcounts[chunk_num] <= sector_num) {
|
||||
@@ -290,7 +290,7 @@ static inline int is_sector_in_chunk(BDRVDMGState* s,
|
||||
}
|
||||
}
|
||||
|
||||
-static inline uint32_t search_chunk(BDRVDMGState *s, int sector_num)
|
||||
+static inline uint32_t search_chunk(BDRVDMGState *s, uint64_t sector_num)
|
||||
{
|
||||
/* binary search */
|
||||
uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3;
|
||||
@@ -307,7 +307,7 @@ static inline uint32_t search_chunk(BDRVDMGState *s, int sector_num)
|
||||
return s->n_chunks; /* error */
|
||||
}
|
||||
|
||||
-static inline int dmg_read_chunk(BlockDriverState *bs, int sector_num)
|
||||
+static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
|
94
0152-dmg-prevent-chunk-buffer-overflow-CVE-2014-0145.patch
Normal file
94
0152-dmg-prevent-chunk-buffer-overflow-CVE-2014-0145.patch
Normal file
@ -0,0 +1,94 @@
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:06:00 +0100
|
||||
Subject: [PATCH] dmg: prevent chunk buffer overflow (CVE-2014-0145)
|
||||
|
||||
Both compressed and uncompressed I/O is buffered. dmg_open() calculates
|
||||
the maximum buffer size needed from the metadata in the image file.
|
||||
|
||||
There is currently a buffer overflow since ->lengths[] is accounted
|
||||
against the maximum compressed buffer size but actually uses the
|
||||
uncompressed buffer:
|
||||
|
||||
switch (s->types[chunk]) {
|
||||
case 1: /* copy */
|
||||
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||
s->uncompressed_chunk, s->lengths[chunk]);
|
||||
|
||||
We must account against the maximum uncompressed buffer size for type=1
|
||||
chunks.
|
||||
|
||||
This patch fixes the maximum buffer size calculation to take into
|
||||
account the chunk type. It is critical that we update the correct
|
||||
maximum since there are two buffers ->compressed_chunk and
|
||||
->uncompressed_chunk.
|
||||
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit f0dce23475b5af5da6b17b97c1765271307734b6)
|
||||
|
||||
Conflicts:
|
||||
block/dmg.c
|
||||
---
|
||||
block/dmg.c | 40 ++++++++++++++++++++++++++++++++++------
|
||||
1 file changed, 34 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/block/dmg.c b/block/dmg.c
|
||||
index 5229876..8d5d42f 100644
|
||||
--- a/block/dmg.c
|
||||
+++ b/block/dmg.c
|
||||
@@ -100,6 +100,38 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int dmg_open(BlockDriverState *bs, QDict *options, int flags);
|
||||
+/* Increase max chunk sizes, if necessary. This function is used to calculate
|
||||
+ * the buffer sizes needed for compressed/uncompressed chunk I/O.
|
||||
+ */
|
||||
+static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
|
||||
+ uint32_t *max_compressed_size,
|
||||
+ uint32_t *max_sectors_per_chunk)
|
||||
+{
|
||||
+ uint32_t compressed_size = 0;
|
||||
+ uint32_t uncompressed_sectors = 0;
|
||||
+
|
||||
+ switch (s->types[chunk]) {
|
||||
+ case 0x80000005: /* zlib compressed */
|
||||
+ compressed_size = s->lengths[chunk];
|
||||
+ uncompressed_sectors = s->sectorcounts[chunk];
|
||||
+ break;
|
||||
+ case 1: /* copy */
|
||||
+ uncompressed_sectors = (s->lengths[chunk] + 511) / 512;
|
||||
+ break;
|
||||
+ case 2: /* zero */
|
||||
+ uncompressed_sectors = s->sectorcounts[chunk];
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (compressed_size > *max_compressed_size) {
|
||||
+ *max_compressed_size = compressed_size;
|
||||
+ }
|
||||
+ if (uncompressed_sectors > *max_sectors_per_chunk) {
|
||||
+ *max_sectors_per_chunk = uncompressed_sectors;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
{
|
||||
BDRVDMGState *s = bs->opaque;
|
||||
@@ -244,12 +276,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- if (s->lengths[i] > max_compressed_size) {
|
||||
- max_compressed_size = s->lengths[i];
|
||||
- }
|
||||
- if (s->sectorcounts[i] > max_sectors_per_chunk) {
|
||||
- max_sectors_per_chunk = s->sectorcounts[i];
|
||||
- }
|
||||
+ update_max_chunk_size(s, i, &max_compressed_size,
|
||||
+ &max_sectors_per_chunk);
|
||||
}
|
||||
s->n_chunks += chunk_count;
|
||||
}
|
32
0153-block-Limit-request-size-CVE-2014-0143.patch
Normal file
32
0153-block-Limit-request-size-CVE-2014-0143.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:06:02 +0100
|
||||
Subject: [PATCH] block: Limit request size (CVE-2014-0143)
|
||||
|
||||
Limiting the size of a single request to INT_MAX not only fixes a
|
||||
direct integer overflow in bdrv_check_request() (which would only
|
||||
trigger bad behaviour with ridiculously huge images, as in close to
|
||||
2^64 bytes), but can also prevent overflows in all block drivers.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 8f4754ede56e3f9ea3fd7207f4a7c4453e59285b)
|
||||
---
|
||||
block.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/block.c b/block.c
|
||||
index 8ce8b91..6c48469 100644
|
||||
--- a/block.c
|
||||
+++ b/block.c
|
||||
@@ -2160,6 +2160,10 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
||||
static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
+ if (nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
}
|
117
0154-qcow2-Fix-copy_sectors-with-VM-state.patch
Normal file
117
0154-qcow2-Fix-copy_sectors-with-VM-state.patch
Normal file
@ -0,0 +1,117 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:06:03 +0100
|
||||
Subject: [PATCH] qcow2: Fix copy_sectors() with VM state
|
||||
|
||||
bs->total_sectors is not the highest possible sector number that could
|
||||
be involved in a copy on write operation: VM state is after the end of
|
||||
the virtual disk. This resulted in wrong values for the number of
|
||||
sectors to be copied (n).
|
||||
|
||||
The code that checks for the end of the image isn't required any more
|
||||
because the code hasn't been calling the block layer's bdrv_read() for a
|
||||
long time; instead, it directly calls qcow2_readv(), which doesn't error
|
||||
out on VM state sector numbers.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 6b7d4c55586a849aa8313282d79432917eade3bf)
|
||||
---
|
||||
block/qcow2-cluster.c | 9 ---------
|
||||
tests/qemu-iotests/029 | 22 ++++++++++++++++++++--
|
||||
tests/qemu-iotests/029.out | 13 +++++++++++++
|
||||
3 files changed, 33 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
|
||||
index 06e3e14..3df140c 100644
|
||||
--- a/block/qcow2-cluster.c
|
||||
+++ b/block/qcow2-cluster.c
|
||||
@@ -335,15 +335,6 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
||||
struct iovec iov;
|
||||
int n, ret;
|
||||
|
||||
- /*
|
||||
- * If this is the last cluster and it is only partially used, we must only
|
||||
- * copy until the end of the image, or bdrv_check_request will fail for the
|
||||
- * bdrv_read/write calls below.
|
||||
- */
|
||||
- if (start_sect + n_end > bs->total_sectors) {
|
||||
- n_end = bs->total_sectors - start_sect;
|
||||
- }
|
||||
-
|
||||
n = n_end - n_start;
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
|
||||
index 0ad5e45..478fd96 100755
|
||||
--- a/tests/qemu-iotests/029
|
||||
+++ b/tests/qemu-iotests/029
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
-# Test loading internal snapshots where the L1 table of the snapshot
|
||||
-# is smaller than the current L1 table.
|
||||
+# qcow2 internal snapshots/VM state tests
|
||||
#
|
||||
# Copyright (C) 2011 Red Hat, Inc.
|
||||
#
|
||||
@@ -45,6 +44,11 @@ _supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
+echo
|
||||
+echo Test loading internal snapshots where the L1 table of the snapshot
|
||||
+echo is smaller than the current L1 table.
|
||||
+echo
|
||||
+
|
||||
CLUSTER_SIZE=65536
|
||||
_make_test_img 64M
|
||||
$QEMU_IMG snapshot -c foo $TEST_IMG
|
||||
@@ -59,6 +63,20 @@ $QEMU_IO -c 'write -b 0 4M' $TEST_IMG | _filter_qemu_io
|
||||
$QEMU_IMG snapshot -a foo $TEST_IMG
|
||||
_check_test_img
|
||||
|
||||
+
|
||||
+echo
|
||||
+echo Try using a huge VM state
|
||||
+echo
|
||||
+
|
||||
+CLUSTER_SIZE=65536
|
||||
+_make_test_img 64M
|
||||
+{ $QEMU_IO -c "write -b -P 0x11 1T 4k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
+{ $QEMU_IMG snapshot -c foo $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
+{ $QEMU_IMG snapshot -a foo $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
+{ $QEMU_IO -c "read -b -P 0x11 1T 4k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
+_check_test_img
|
||||
+
|
||||
+
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
diff --git a/tests/qemu-iotests/029.out b/tests/qemu-iotests/029.out
|
||||
index 0eedb3a..9029698 100644
|
||||
--- a/tests/qemu-iotests/029.out
|
||||
+++ b/tests/qemu-iotests/029.out
|
||||
@@ -1,4 +1,8 @@
|
||||
QA output created by 029
|
||||
+
|
||||
+Test loading internal snapshots where the L1 table of the snapshot
|
||||
+is smaller than the current L1 table.
|
||||
+
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 4096/4096 bytes at offset 0
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
@@ -7,4 +11,13 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216
|
||||
wrote 4194304/4194304 bytes at offset 0
|
||||
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
No errors were found on the image.
|
||||
+
|
||||
+Try using a huge VM state
|
||||
+
|
||||
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
+wrote 4096/4096 bytes at offset 1099511627776
|
||||
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
+read 4096/4096 bytes at offset 1099511627776
|
||||
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
+No errors were found on the image.
|
||||
*** done
|
@ -0,0 +1,48 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:06:04 +0100
|
||||
Subject: [PATCH] qcow2: Fix NULL dereference in qcow2_open() error path
|
||||
(CVE-2014-0146)
|
||||
|
||||
The qcow2 code assumes that s->snapshots is non-NULL if s->nb_snapshots
|
||||
!= 0. By having the initialisation of both fields separated in
|
||||
qcow2_open(), any error occuring in between would cause the error path
|
||||
to dereference NULL in qcow2_free_snapshots() if the image had any
|
||||
snapshots.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 11b128f4062dd7f89b14abc8877ff20d41b28be9)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/080
|
||||
tests/qemu-iotests/080.out
|
||||
---
|
||||
block/qcow2.c | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index af0a45c..c9beb01 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -515,9 +515,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- s->snapshots_offset = header.snapshots_offset;
|
||||
- s->nb_snapshots = header.nb_snapshots;
|
||||
-
|
||||
/* read the level 1 table */
|
||||
if (header.l1_size > 0x2000000) {
|
||||
/* 32 MB L1 table is enough for 2 PB images at 64k cluster size
|
||||
@@ -605,6 +602,10 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
bs->backing_file[len] = '\0';
|
||||
}
|
||||
|
||||
+ /* Internal snapshots */
|
||||
+ s->snapshots_offset = header.snapshots_offset;
|
||||
+ s->nb_snapshots = header.nb_snapshots;
|
||||
+
|
||||
ret = qcow2_read_snapshots(bs);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
@ -0,0 +1,89 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:06:05 +0100
|
||||
Subject: [PATCH] qcow2: Fix L1 allocation size in qcow2_snapshot_load_tmp()
|
||||
(CVE-2014-0145)
|
||||
|
||||
For the L1 table to loaded for an internal snapshot, the code allocated
|
||||
only enough memory to hold the currently active L1 table. If the
|
||||
snapshot's L1 table is actually larger than the current one, this leads
|
||||
to a buffer overflow.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit c05e4667be91b46ab42b5a11babf8e84d476cc6b)
|
||||
---
|
||||
block/qcow2-snapshot.c | 2 +-
|
||||
tests/qemu-iotests/029 | 18 +++++++++++++++++-
|
||||
tests/qemu-iotests/029.out | 4 ++++
|
||||
3 files changed, 22 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
|
||||
index eb80438..dc8736a 100644
|
||||
--- a/block/qcow2-snapshot.c
|
||||
+++ b/block/qcow2-snapshot.c
|
||||
@@ -622,7 +622,7 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
|
||||
sn = &s->snapshots[snapshot_index];
|
||||
|
||||
/* Allocate and read in the snapshot's L1 table */
|
||||
- new_l1_bytes = s->l1_size * sizeof(uint64_t);
|
||||
+ new_l1_bytes = sn->l1_size * sizeof(uint64_t);
|
||||
new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
|
||||
|
||||
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
||||
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
|
||||
index 478fd96..dfb5726 100755
|
||||
--- a/tests/qemu-iotests/029
|
||||
+++ b/tests/qemu-iotests/029
|
||||
@@ -30,7 +30,8 @@ status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
- _cleanup_test_img
|
||||
+ rm -f $TEST_IMG.snap
|
||||
+ _cleanup_test_img
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
@@ -44,6 +45,9 @@ _supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
+offset_size=24
|
||||
+offset_l1_size=36
|
||||
+
|
||||
echo
|
||||
echo Test loading internal snapshots where the L1 table of the snapshot
|
||||
echo is smaller than the current L1 table.
|
||||
@@ -77,6 +81,18 @@ _make_test_img 64M
|
||||
_check_test_img
|
||||
|
||||
|
||||
+echo
|
||||
+echo "qcow2_snapshot_load_tmp() should take the L1 size from the snapshot"
|
||||
+echo
|
||||
+
|
||||
+CLUSTER_SIZE=512
|
||||
+_make_test_img 64M
|
||||
+{ $QEMU_IMG snapshot -c foo $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
+poke_file "$TEST_IMG" "$offset_size" "\x00\x00\x00\x00\x00\x00\x02\x00"
|
||||
+poke_file "$TEST_IMG" "$offset_l1_size" "\x00\x00\x00\x01"
|
||||
+{ $QEMU_IMG convert -s foo $TEST_IMG $TEST_IMG.snap; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
+
|
||||
+
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
diff --git a/tests/qemu-iotests/029.out b/tests/qemu-iotests/029.out
|
||||
index 9029698..ce0e64d 100644
|
||||
--- a/tests/qemu-iotests/029.out
|
||||
+++ b/tests/qemu-iotests/029.out
|
||||
@@ -20,4 +20,8 @@ wrote 4096/4096 bytes at offset 1099511627776
|
||||
read 4096/4096 bytes at offset 1099511627776
|
||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
No errors were found on the image.
|
||||
+
|
||||
+qcow2_snapshot_load_tmp() should take the L1 size from the snapshot
|
||||
+
|
||||
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
*** done
|
@ -0,0 +1,67 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:06:06 +0100
|
||||
Subject: [PATCH] qcow2: Check maximum L1 size in qcow2_snapshot_load_tmp()
|
||||
(CVE-2014-0143)
|
||||
|
||||
This avoids an unbounded allocation.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 6a83f8b5bec6f59e56cc49bd49e4c3f8f805d56f)
|
||||
|
||||
Conflicts:
|
||||
block/qcow2.c
|
||||
tests/qemu-iotests/080
|
||||
tests/qemu-iotests/080.out
|
||||
---
|
||||
block/qcow2-snapshot.c | 4 ++++
|
||||
block/qcow2.c | 4 +---
|
||||
block/qcow2.h | 4 ++++
|
||||
3 files changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
|
||||
index dc8736a..d2c956c 100644
|
||||
--- a/block/qcow2-snapshot.c
|
||||
+++ b/block/qcow2-snapshot.c
|
||||
@@ -622,6 +622,10 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name)
|
||||
sn = &s->snapshots[snapshot_index];
|
||||
|
||||
/* Allocate and read in the snapshot's L1 table */
|
||||
+ if (sn->l1_size > QCOW_MAX_L1_SIZE) {
|
||||
+ fprintf(stderr, "Snapshot L1 table too large");
|
||||
+ return -EFBIG;
|
||||
+ }
|
||||
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
|
||||
new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
|
||||
|
||||
diff --git a/block/qcow2.c b/block/qcow2.c
|
||||
index c9beb01..5dfd5ec 100644
|
||||
--- a/block/qcow2.c
|
||||
+++ b/block/qcow2.c
|
||||
@@ -516,9 +516,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
}
|
||||
|
||||
/* read the level 1 table */
|
||||
- if (header.l1_size > 0x2000000) {
|
||||
- /* 32 MB L1 table is enough for 2 PB images at 64k cluster size
|
||||
- * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||
+ if (header.l1_size > QCOW_MAX_L1_SIZE) {
|
||||
fprintf(stderr, "Active L1 table too large");
|
||||
ret = -EFBIG;
|
||||
goto fail;
|
||||
diff --git a/block/qcow2.h b/block/qcow2.h
|
||||
index baf62a0..0912488 100644
|
||||
--- a/block/qcow2.h
|
||||
+++ b/block/qcow2.h
|
||||
@@ -44,6 +44,10 @@
|
||||
* (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||
#define QCOW_MAX_REFTABLE_SIZE 0x800000
|
||||
|
||||
+/* 32 MB L1 table is enough for 2 PB images at 64k cluster size
|
||||
+ * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||
+#define QCOW_MAX_L1_SIZE 0x2000000
|
||||
+
|
||||
/* indicate that the refcount of the referenced cluster is exactly one. */
|
||||
#define QCOW_OFLAG_COPIED (1LL << 63)
|
||||
/* indicate that the cluster is compressed (they never have the copied flag) */
|
81
0158-qcow2-Limit-snapshot-table-size.patch
Normal file
81
0158-qcow2-Limit-snapshot-table-size.patch
Normal file
@ -0,0 +1,81 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:06:07 +0100
|
||||
Subject: [PATCH] qcow2: Limit snapshot table size
|
||||
|
||||
Even with a limit of 64k snapshots, each snapshot could have a filename
|
||||
and an ID with up to 64k, which would still lead to pretty large
|
||||
allocations, which could potentially lead to qemu aborting. Limit the
|
||||
total size of the snapshot table to an average of 1k per entry when
|
||||
the limit of 64k snapshots is fully used. This should be plenty for any
|
||||
reasonable user.
|
||||
|
||||
This also fixes potential integer overflows of s->snapshot_size.
|
||||
|
||||
Suggested-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 5dae6e30c531feb31eed99f9039b52bf70832ce3)
|
||||
---
|
||||
block/qcow2-snapshot.c | 15 ++++++++++++++-
|
||||
block/qcow2.h | 4 ++++
|
||||
2 files changed, 18 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
|
||||
index d2c956c..5d3c0e6 100644
|
||||
--- a/block/qcow2-snapshot.c
|
||||
+++ b/block/qcow2-snapshot.c
|
||||
@@ -116,8 +116,14 @@ int qcow2_read_snapshots(BlockDriverState *bs)
|
||||
}
|
||||
offset += name_size;
|
||||
sn->name[name_size] = '\0';
|
||||
+
|
||||
+ if (offset - s->snapshots_offset > QCOW_MAX_SNAPSHOTS_SIZE) {
|
||||
+ ret = -EFBIG;
|
||||
+ goto fail;
|
||||
+ }
|
||||
}
|
||||
|
||||
+ assert(offset - s->snapshots_offset <= INT_MAX);
|
||||
s->snapshots_size = offset - s->snapshots_offset;
|
||||
return 0;
|
||||
|
||||
@@ -138,7 +144,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
||||
uint32_t nb_snapshots;
|
||||
uint64_t snapshots_offset;
|
||||
} QEMU_PACKED header_data;
|
||||
- int64_t offset, snapshots_offset;
|
||||
+ int64_t offset, snapshots_offset = 0;
|
||||
int ret;
|
||||
|
||||
/* compute the size of the snapshots */
|
||||
@@ -150,7 +156,14 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
|
||||
offset += sizeof(extra);
|
||||
offset += strlen(sn->id_str);
|
||||
offset += strlen(sn->name);
|
||||
+
|
||||
+ if (offset > QCOW_MAX_SNAPSHOTS_SIZE) {
|
||||
+ ret = -EFBIG;
|
||||
+ goto fail;
|
||||
+ }
|
||||
}
|
||||
+
|
||||
+ assert(offset <= INT_MAX);
|
||||
snapshots_size = offset;
|
||||
|
||||
/* Allocate space for the new snapshot list */
|
||||
diff --git a/block/qcow2.h b/block/qcow2.h
|
||||
index 0912488..797c9d8 100644
|
||||
--- a/block/qcow2.h
|
||||
+++ b/block/qcow2.h
|
||||
@@ -48,6 +48,10 @@
|
||||
* (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
|
||||
#define QCOW_MAX_L1_SIZE 0x2000000
|
||||
|
||||
+/* Allow for an average of 1k per snapshot table entry, should be plenty of
|
||||
+ * space for snapshot names and IDs */
|
||||
+#define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS)
|
||||
+
|
||||
/* indicate that the refcount of the referenced cluster is exactly one. */
|
||||
#define QCOW_OFLAG_COPIED (1LL << 63)
|
||||
/* indicate that the cluster is compressed (they never have the copied flag) */
|
@ -0,0 +1,52 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:06:08 +0100
|
||||
Subject: [PATCH] parallels: Fix catalog size integer overflow (CVE-2014-0143)
|
||||
|
||||
The first test case would cause a huge memory allocation, leading to a
|
||||
qemu abort; the second one to a too small malloc() for the catalog
|
||||
(smaller than s->catalog_size), which causes a read-only out-of-bounds
|
||||
array access and on big endian hosts an endianess conversion for an
|
||||
undefined memory area.
|
||||
|
||||
The sample image used here is not an original Parallels image. It was
|
||||
created using an hexeditor on the basis of the struct that qemu uses.
|
||||
Good enough for trying to crash the driver, but not for ensuring
|
||||
compatibility.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit afbcc40bee4ef51731102d7d4b499ee12fc182e1)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/common
|
||||
tests/qemu-iotests/group
|
||||
---
|
||||
block/parallels.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/parallels.c b/block/parallels.c
|
||||
index 18b3ac0..bad47f4 100644
|
||||
--- a/block/parallels.c
|
||||
+++ b/block/parallels.c
|
||||
@@ -49,7 +49,7 @@ typedef struct BDRVParallelsState {
|
||||
CoMutex lock;
|
||||
|
||||
uint32_t *catalog_bitmap;
|
||||
- int catalog_size;
|
||||
+ unsigned int catalog_size;
|
||||
|
||||
int tracks;
|
||||
} BDRVParallelsState;
|
||||
@@ -93,6 +93,11 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
s->tracks = le32_to_cpu(ph.tracks);
|
||||
|
||||
s->catalog_size = le32_to_cpu(ph.catalog_entries);
|
||||
+ if (s->catalog_size > INT_MAX / 4) {
|
||||
+ fprintf(stderr, "Catalog too large");
|
||||
+ ret = -EFBIG;
|
||||
+ goto fail;
|
||||
+ }
|
||||
s->catalog_bitmap = g_malloc(s->catalog_size * 4);
|
||||
|
||||
ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
|
47
0160-parallels-Sanity-check-for-s-tracks-CVE-2014-0142.patch
Normal file
47
0160-parallels-Sanity-check-for-s-tracks-CVE-2014-0142.patch
Normal file
@ -0,0 +1,47 @@
|
||||
From: Kevin Wolf <kwolf@redhat.com>
|
||||
Date: Wed, 26 Mar 2014 13:06:09 +0100
|
||||
Subject: [PATCH] parallels: Sanity check for s->tracks (CVE-2014-0142)
|
||||
|
||||
This avoids a possible division by zero.
|
||||
|
||||
Convert s->tracks to unsigned as well because it feels better than
|
||||
surviving just because the results of calculations with s->tracks are
|
||||
converted to unsigned anyway.
|
||||
|
||||
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||||
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||||
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
(cherry picked from commit 9302e863aa8baa5d932fc078967050c055fa1a7f)
|
||||
|
||||
Conflicts:
|
||||
tests/qemu-iotests/076
|
||||
tests/qemu-iotests/076.out
|
||||
---
|
||||
block/parallels.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/block/parallels.c b/block/parallels.c
|
||||
index bad47f4..4bcfe06 100644
|
||||
--- a/block/parallels.c
|
||||
+++ b/block/parallels.c
|
||||
@@ -51,7 +51,7 @@ typedef struct BDRVParallelsState {
|
||||
uint32_t *catalog_bitmap;
|
||||
unsigned int catalog_size;
|
||||
|
||||
- int tracks;
|
||||
+ unsigned int tracks;
|
||||
} BDRVParallelsState;
|
||||
|
||||
static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
@@ -91,6 +91,11 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags)
|
||||
bs->total_sectors = le32_to_cpu(ph.nb_sectors);
|
||||
|
||||
s->tracks = le32_to_cpu(ph.tracks);
|
||||
+ if (s->tracks == 0) {
|
||||
+ fprintf(stderr, "Invalid image: Zero sectors per track");
|
||||
+ ret = -EINVAL;
|
||||
+ goto fail;
|
||||
+ }
|
||||
|
||||
s->catalog_size = le32_to_cpu(ph.catalog_entries);
|
||||
if (s->catalog_size > INT_MAX / 4) {
|
50
0201-virtio-net-fix-guest-triggerable-buffer-overrun.patch
Normal file
50
0201-virtio-net-fix-guest-triggerable-buffer-overrun.patch
Normal file
@ -0,0 +1,50 @@
|
||||
From: "Michael S. Tsirkin" <mst@redhat.com>
|
||||
Date: Fri, 11 Apr 2014 15:18:08 +0300
|
||||
Subject: [PATCH] virtio-net: fix guest-triggerable buffer overrun
|
||||
|
||||
When VM guest programs multicast addresses for
|
||||
a virtio net card, it supplies a 32 bit
|
||||
entries counter for the number of addresses.
|
||||
These addresses are read into tail portion of
|
||||
a fixed macs array which has size MAC_TABLE_ENTRIES,
|
||||
at offset equal to in_use.
|
||||
|
||||
To avoid overflow of this array by guest, qemu attempts
|
||||
to test the size as follows:
|
||||
- if (in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
|
||||
|
||||
however, as mac_data.entries is uint32_t, this sum
|
||||
can overflow, e.g. if in_use is 1 and mac_data.entries
|
||||
is 0xffffffff then in_use + mac_data.entries will be 0.
|
||||
|
||||
Qemu will then read guest supplied buffer into this
|
||||
memory, overflowing buffer on heap.
|
||||
|
||||
CVE-2014-0150
|
||||
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Message-id: 1397218574-25058-1-git-send-email-mst@redhat.com
|
||||
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit edc243851279e3393000b28b6b69454cae1190ef)
|
||||
|
||||
Conflicts:
|
||||
hw/net/virtio-net.c
|
||||
---
|
||||
hw/net/virtio-net.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
|
||||
index 060b900..63f777f 100644
|
||||
--- a/hw/net/virtio-net.c
|
||||
+++ b/hw/net/virtio-net.c
|
||||
@@ -655,7 +655,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
|
||||
goto error;
|
||||
}
|
||||
|
||||
- if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
|
||||
+ if (mac_data.entries <= MAC_TABLE_ENTRIES - n->mac_table.in_use) {
|
||||
s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
|
||||
mac_data.entries * ETH_ALEN);
|
||||
if (s != mac_data.entries * ETH_ALEN) {
|
@ -0,0 +1,95 @@
|
||||
From: Dmitry Fleytman <dmitry@daynix.com>
|
||||
Date: Fri, 4 Apr 2014 12:45:19 +0300
|
||||
Subject: [PATCH] vmxnet3: validate interrupt indices coming from guest
|
||||
|
||||
CVE-2013-4544
|
||||
|
||||
Signed-off-by: Dmitry Fleytman <dmitry@daynix.com>
|
||||
Reported-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Message-id: 1396604722-11902-2-git-send-email-dmitry@daynix.com
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit 8c6c0478996e8f77374e69b6df68655b0b4ba689)
|
||||
|
||||
Conflicts:
|
||||
hw/net/vmxnet3.c
|
||||
---
|
||||
hw/net/vmxnet3.c | 36 ++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 34 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
|
||||
index 49c2466..6ae39a4 100644
|
||||
--- a/hw/net/vmxnet3.c
|
||||
+++ b/hw/net/vmxnet3.c
|
||||
@@ -52,6 +52,9 @@
|
||||
#define VMXNET3_DEVICE_VERSION 0x1
|
||||
#define VMXNET3_DEVICE_REVISION 0x1
|
||||
|
||||
+/* Number of interrupt vectors for non-MSIx modes */
|
||||
+#define VMXNET3_MAX_NMSIX_INTRS (1)
|
||||
+
|
||||
/* Macros for rings descriptors access */
|
||||
#define VMXNET3_READ_TX_QUEUE_DESCR8(dpa, field) \
|
||||
(vmw_shmem_ld8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
|
||||
@@ -1299,6 +1302,34 @@ static void vmxnet3_update_features(VMXNET3State *s)
|
||||
}
|
||||
}
|
||||
|
||||
+static void vmxnet3_validate_interrupt_idx(bool is_msix, int idx)
|
||||
+{
|
||||
+ int max_ints = is_msix ? VMXNET3_MAX_INTRS : VMXNET3_MAX_NMSIX_INTRS;
|
||||
+ if (idx >= max_ints) {
|
||||
+ hw_error("Bad interrupt index: %d\n", idx);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void vmxnet3_validate_interrupts(VMXNET3State *s)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ VMW_CFPRN("Verifying event interrupt index (%d)", s->event_int_idx);
|
||||
+ vmxnet3_validate_interrupt_idx(s->msix_used, s->event_int_idx);
|
||||
+
|
||||
+ for (i = 0; i < s->txq_num; i++) {
|
||||
+ int idx = s->txq_descr[i].intr_idx;
|
||||
+ VMW_CFPRN("Verifying TX queue %d interrupt index (%d)", i, idx);
|
||||
+ vmxnet3_validate_interrupt_idx(s->msix_used, idx);
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < s->rxq_num; i++) {
|
||||
+ int idx = s->rxq_descr[i].intr_idx;
|
||||
+ VMW_CFPRN("Verifying RX queue %d interrupt index (%d)", i, idx);
|
||||
+ vmxnet3_validate_interrupt_idx(s->msix_used, idx);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void vmxnet3_activate_device(VMXNET3State *s)
|
||||
{
|
||||
int i;
|
||||
@@ -1438,6 +1469,8 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
||||
sizeof(s->rxq_descr[i].rxq_stats));
|
||||
}
|
||||
|
||||
+ vmxnet3_validate_interrupts(s);
|
||||
+
|
||||
/* Make sure everything is in place before device activation */
|
||||
smp_wmb();
|
||||
|
||||
@@ -1998,7 +2031,6 @@ vmxnet3_cleanup_msix(VMXNET3State *s)
|
||||
}
|
||||
}
|
||||
|
||||
-#define VMXNET3_MSI_NUM_VECTORS (1)
|
||||
#define VMXNET3_MSI_OFFSET (0x50)
|
||||
#define VMXNET3_USE_64BIT (true)
|
||||
#define VMXNET3_PER_VECTOR_MASK (false)
|
||||
@@ -2009,7 +2041,7 @@ vmxnet3_init_msi(VMXNET3State *s)
|
||||
PCIDevice *d = PCI_DEVICE(s);
|
||||
int res;
|
||||
|
||||
- res = msi_init(d, VMXNET3_MSI_OFFSET, VMXNET3_MSI_NUM_VECTORS,
|
||||
+ res = msi_init(d, VMXNET3_MSI_OFFSET, VMXNET3_MAX_NMSIX_INTRS,
|
||||
VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK);
|
||||
if (0 > res) {
|
||||
VMW_WRPRN("Failed to initialize MSI, error %d", res);
|
@ -0,0 +1,54 @@
|
||||
From: Dmitry Fleytman <dmitry@daynix.com>
|
||||
Date: Fri, 4 Apr 2014 12:45:20 +0300
|
||||
Subject: [PATCH] vmxnet3: validate queues configuration coming from guest
|
||||
|
||||
CVE-2013-4544
|
||||
|
||||
Signed-off-by: Dmitry Fleytman <dmitry@daynix.com>
|
||||
Reported-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Message-id: 1396604722-11902-3-git-send-email-dmitry@daynix.com
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit 9878d173f574df74bde0ff50b2f81009fbee81bb)
|
||||
---
|
||||
hw/net/vmxnet3.c | 19 ++++++++++++++++++-
|
||||
1 file changed, 18 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
|
||||
index 6ae39a4..7325670 100644
|
||||
--- a/hw/net/vmxnet3.c
|
||||
+++ b/hw/net/vmxnet3.c
|
||||
@@ -1330,6 +1330,23 @@ static void vmxnet3_validate_interrupts(VMXNET3State *s)
|
||||
}
|
||||
}
|
||||
|
||||
+static void vmxnet3_validate_queues(VMXNET3State *s)
|
||||
+{
|
||||
+ /*
|
||||
+ * txq_num and rxq_num are total number of queues
|
||||
+ * configured by guest. These numbers must not
|
||||
+ * exceed corresponding maximal values.
|
||||
+ */
|
||||
+
|
||||
+ if (s->txq_num > VMXNET3_DEVICE_MAX_TX_QUEUES) {
|
||||
+ hw_error("Bad TX queues number: %d\n", s->txq_num);
|
||||
+ }
|
||||
+
|
||||
+ if (s->rxq_num > VMXNET3_DEVICE_MAX_RX_QUEUES) {
|
||||
+ hw_error("Bad RX queues number: %d\n", s->rxq_num);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void vmxnet3_activate_device(VMXNET3State *s)
|
||||
{
|
||||
int i;
|
||||
@@ -1375,7 +1392,7 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
||||
VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numRxQueues);
|
||||
|
||||
VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num);
|
||||
- assert(s->txq_num <= VMXNET3_DEVICE_MAX_TX_QUEUES);
|
||||
+ vmxnet3_validate_queues(s);
|
||||
|
||||
qdescr_table_pa =
|
||||
VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.misc.queueDescPA);
|
@ -0,0 +1,30 @@
|
||||
From: Dmitry Fleytman <dmitry@daynix.com>
|
||||
Date: Fri, 4 Apr 2014 12:45:21 +0300
|
||||
Subject: [PATCH] vmxnet3: validate interrupt indices read on migration
|
||||
|
||||
CVE-2013-4544
|
||||
|
||||
Signed-off-by: Dmitry Fleytman <dmitry@daynix.com>
|
||||
Reported-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Message-id: 1396604722-11902-4-git-send-email-dmitry@daynix.com
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit 3c99afc779c2c78718a565ad8c5e98de7c2c7484)
|
||||
---
|
||||
hw/net/vmxnet3.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
|
||||
index 7325670..20bd3c6 100644
|
||||
--- a/hw/net/vmxnet3.c
|
||||
+++ b/hw/net/vmxnet3.c
|
||||
@@ -2384,6 +2384,8 @@ static int vmxnet3_post_load(void *opaque, int version_id)
|
||||
}
|
||||
}
|
||||
|
||||
+ vmxnet3_validate_interrupts(s);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
From: Dmitry Fleytman <dmitry@daynix.com>
|
||||
Date: Fri, 4 Apr 2014 12:45:22 +0300
|
||||
Subject: [PATCH] vmxnet3: validate queues configuration read on migration
|
||||
|
||||
CVE-2013-4544
|
||||
|
||||
Signed-off-by: Dmitry Fleytman <dmitry@daynix.com>
|
||||
Reported-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Message-id: 1396604722-11902-5-git-send-email-dmitry@daynix.com
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit f12d048a523780dbda702027d4a91b62af1a08d7)
|
||||
---
|
||||
hw/net/vmxnet3.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
|
||||
index 20bd3c6..1bbea3b 100644
|
||||
--- a/hw/net/vmxnet3.c
|
||||
+++ b/hw/net/vmxnet3.c
|
||||
@@ -2384,6 +2384,7 @@ static int vmxnet3_post_load(void *opaque, int version_id)
|
||||
}
|
||||
}
|
||||
|
||||
+ vmxnet3_validate_queues(s);
|
||||
vmxnet3_validate_interrupts(s);
|
||||
|
||||
return 0;
|
@ -0,0 +1,37 @@
|
||||
From: =?UTF-8?q?Beno=C3=AEt=20Canet?= <benoit.canet@irqsave.net>
|
||||
Date: Sat, 12 Apr 2014 22:59:50 +0200
|
||||
Subject: [PATCH] ide: Correct improper smart self test counter reset in ide
|
||||
core.
|
||||
|
||||
The SMART self test counter was incorrectly being reset to zero,
|
||||
not 1. This had the effect that on every 21st SMART EXECUTE OFFLINE:
|
||||
* We would write off the beginning of a dynamically allocated buffer
|
||||
* We forgot the SMART history
|
||||
Fix this.
|
||||
|
||||
Signed-off-by: Benoit Canet <benoit@irqsave.net>
|
||||
Message-id: 1397336390-24664-1-git-send-email-benoit.canet@irqsave.net
|
||||
Reviewed-by: Markus Armbruster <armbru@redhat.com>
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
[PMM: tweaked commit message as per suggestions from Markus]
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
|
||||
(cherry picked from commit 940973ae0b45c9b6817bab8e4cf4df99a9ef83d7)
|
||||
---
|
||||
hw/ide/core.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/ide/core.c b/hw/ide/core.c
|
||||
index a73af72..3fe67ca 100644
|
||||
--- a/hw/ide/core.c
|
||||
+++ b/hw/ide/core.c
|
||||
@@ -1601,7 +1601,7 @@ static bool cmd_smart(IDEState *s, uint8_t cmd)
|
||||
case 2: /* extended self test */
|
||||
s->smart_selftest_count++;
|
||||
if (s->smart_selftest_count > 21) {
|
||||
- s->smart_selftest_count = 0;
|
||||
+ s->smart_selftest_count = 1;
|
||||
}
|
||||
n = 2 + (s->smart_selftest_count - 1) * 24;
|
||||
s->smart_selftest_data[n] = s->sector;
|
29
0207-char-serial-Fix-emptyness-check.patch
Normal file
29
0207-char-serial-Fix-emptyness-check.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
Date: Mon, 10 Feb 2014 22:49:35 -0800
|
||||
Subject: [PATCH] char/serial: Fix emptyness check
|
||||
|
||||
This was guarding against a full fifo rather than an empty fifo when
|
||||
popping. Fix.
|
||||
|
||||
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
|
||||
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
|
||||
(cherry picked from commit 88c1ee73d3231c74ff90bcfc084a7589670ec244)
|
||||
---
|
||||
hw/char/serial.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/char/serial.c b/hw/char/serial.c
|
||||
index 6025592..2989ca2 100644
|
||||
--- a/hw/char/serial.c
|
||||
+++ b/hw/char/serial.c
|
||||
@@ -224,7 +224,7 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
|
||||
if (s->tsr_retry <= 0) {
|
||||
if (s->fcr & UART_FCR_FE) {
|
||||
- s->tsr = fifo8_is_full(&s->xmit_fifo) ?
|
||||
+ s->tsr = fifo8_is_empty(&s->xmit_fifo) ?
|
||||
0 : fifo8_pop(&s->xmit_fifo);
|
||||
if (!s->xmit_fifo.num) {
|
||||
s->lsr |= UART_LSR_THRE;
|
37
0208-char-serial-Fix-emptyness-handling.patch
Normal file
37
0208-char-serial-Fix-emptyness-handling.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From: Don Slutz <dslutz@verizon.com>
|
||||
Date: Tue, 18 Mar 2014 12:29:34 -0400
|
||||
Subject: [PATCH] char/serial: Fix emptyness handling
|
||||
|
||||
The commit 88c1ee73d3231c74ff90bcfc084a7589670ec244
|
||||
char/serial: Fix emptyness check
|
||||
|
||||
Still causes extra NULL byte(s) to be sent.
|
||||
|
||||
So if the fifo is empty, do not send an extra NULL byte.
|
||||
|
||||
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
Signed-off-by: Don Slutz <dslutz@verizon.com>
|
||||
Message-id: 1395160174-16006-1-git-send-email-dslutz@verizon.com
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit dffacd4654ec8bf2898aed230852154c6ed755ed)
|
||||
---
|
||||
hw/char/serial.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/char/serial.c b/hw/char/serial.c
|
||||
index 2989ca2..6d10747 100644
|
||||
--- a/hw/char/serial.c
|
||||
+++ b/hw/char/serial.c
|
||||
@@ -224,8 +224,10 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
|
||||
if (s->tsr_retry <= 0) {
|
||||
if (s->fcr & UART_FCR_FE) {
|
||||
- s->tsr = fifo8_is_empty(&s->xmit_fifo) ?
|
||||
- 0 : fifo8_pop(&s->xmit_fifo);
|
||||
+ if (fifo8_is_empty(&s->xmit_fifo)) {
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ s->tsr = fifo8_pop(&s->xmit_fifo);
|
||||
if (!s->xmit_fifo.num) {
|
||||
s->lsr |= UART_LSR_THRE;
|
||||
}
|
34
0209-vmstate-Add-uint32-2D-array-support.patch
Normal file
34
0209-vmstate-Add-uint32-2D-array-support.patch
Normal file
@ -0,0 +1,34 @@
|
||||
From: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Date: Fri, 20 Sep 2013 20:35:06 +0100
|
||||
Subject: [PATCH] vmstate: Add uint32 2D-array support
|
||||
|
||||
Add support for saving VMState of 2D arrays of uint32 values.
|
||||
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit a1b1d277cdaac98f25be249e7819aac781a35530)
|
||||
---
|
||||
include/migration/vmstate.h | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
|
||||
index 1c31b5d..e5538c7 100644
|
||||
--- a/include/migration/vmstate.h
|
||||
+++ b/include/migration/vmstate.h
|
||||
@@ -633,9 +633,15 @@ extern const VMStateInfo vmstate_info_bitmap;
|
||||
#define VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v) \
|
||||
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint32, uint32_t)
|
||||
|
||||
+#define VMSTATE_UINT32_2DARRAY_V(_f, _s, _n1, _n2, _v) \
|
||||
+ VMSTATE_2DARRAY(_f, _s, _n1, _n2, _v, vmstate_info_uint32, uint32_t)
|
||||
+
|
||||
#define VMSTATE_UINT32_ARRAY(_f, _s, _n) \
|
||||
VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
|
||||
|
||||
+#define VMSTATE_UINT32_2DARRAY(_f, _s, _n1, _n2) \
|
||||
+ VMSTATE_UINT32_2DARRAY_V(_f, _s, _n1, _n2, 0)
|
||||
+
|
||||
#define VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v) \
|
||||
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint64, uint64_t)
|
||||
|
312
0210-arm_gic-Extract-headers-hw-intc-arm_gic-_common-.h.patch
Normal file
312
0210-arm_gic-Extract-headers-hw-intc-arm_gic-_common-.h.patch
Normal file
@ -0,0 +1,312 @@
|
||||
From: =?UTF-8?q?Andreas=20F=C3=A4rber?= <afaerber@suse.de>
|
||||
Date: Tue, 23 Jul 2013 03:37:49 +0200
|
||||
Subject: [PATCH] arm_gic: Extract headers hw/intc/arm_gic{,_common}.h
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Rename NCPU to GIC_NCPU and move GICState away from gic_internal.h.
|
||||
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Andreas Färber <afaerber@suse.de>
|
||||
(cherry picked from commit 83728796ad3f2ce7d6162c1cb894528b12915646)
|
||||
---
|
||||
hw/intc/arm_gic_common.c | 18 ++++----
|
||||
hw/intc/gic_internal.h | 80 +---------------------------------
|
||||
include/hw/intc/arm_gic.h | 42 ++++++++++++++++++
|
||||
include/hw/intc/arm_gic_common.h | 92 ++++++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 145 insertions(+), 87 deletions(-)
|
||||
create mode 100644 include/hw/intc/arm_gic.h
|
||||
create mode 100644 include/hw/intc/arm_gic_common.h
|
||||
|
||||
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
|
||||
index 709b5c2..c765850 100644
|
||||
--- a/hw/intc/arm_gic_common.c
|
||||
+++ b/hw/intc/arm_gic_common.c
|
||||
@@ -64,17 +64,17 @@ static const VMStateDescription vmstate_gic = {
|
||||
.post_load = gic_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(enabled, GICState),
|
||||
- VMSTATE_BOOL_ARRAY(cpu_enabled, GICState, NCPU),
|
||||
+ VMSTATE_BOOL_ARRAY(cpu_enabled, GICState, GIC_NCPU),
|
||||
VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1,
|
||||
vmstate_gic_irq_state, gic_irq_state),
|
||||
VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
|
||||
- VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, NCPU),
|
||||
+ VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, GIC_NCPU),
|
||||
VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
|
||||
- VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, NCPU),
|
||||
- VMSTATE_UINT16_ARRAY(priority_mask, GICState, NCPU),
|
||||
- VMSTATE_UINT16_ARRAY(running_irq, GICState, NCPU),
|
||||
- VMSTATE_UINT16_ARRAY(running_priority, GICState, NCPU),
|
||||
- VMSTATE_UINT16_ARRAY(current_pending, GICState, NCPU),
|
||||
+ VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, GIC_NCPU),
|
||||
+ VMSTATE_UINT16_ARRAY(priority_mask, GICState, GIC_NCPU),
|
||||
+ VMSTATE_UINT16_ARRAY(running_irq, GICState, GIC_NCPU),
|
||||
+ VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU),
|
||||
+ VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
@@ -84,9 +84,9 @@ static void arm_gic_common_realize(DeviceState *dev, Error **errp)
|
||||
GICState *s = ARM_GIC_COMMON(dev);
|
||||
int num_irq = s->num_irq;
|
||||
|
||||
- if (s->num_cpu > NCPU) {
|
||||
+ if (s->num_cpu > GIC_NCPU) {
|
||||
error_setg(errp, "requested %u CPUs exceeds GIC maximum %d",
|
||||
- s->num_cpu, NCPU);
|
||||
+ s->num_cpu, GIC_NCPU);
|
||||
return;
|
||||
}
|
||||
s->num_irq += GIC_BASE_IRQ;
|
||||
diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h
|
||||
index 1426437..3989fd1 100644
|
||||
--- a/hw/intc/gic_internal.h
|
||||
+++ b/hw/intc/gic_internal.h
|
||||
@@ -21,16 +21,9 @@
|
||||
#ifndef QEMU_ARM_GIC_INTERNAL_H
|
||||
#define QEMU_ARM_GIC_INTERNAL_H
|
||||
|
||||
-#include "hw/sysbus.h"
|
||||
+#include "hw/intc/arm_gic.h"
|
||||
|
||||
-/* Maximum number of possible interrupts, determined by the GIC architecture */
|
||||
-#define GIC_MAXIRQ 1020
|
||||
-/* First 32 are private to each CPU (SGIs and PPIs). */
|
||||
-#define GIC_INTERNAL 32
|
||||
-/* Maximum number of possible CPU interfaces, determined by GIC architecture */
|
||||
-#define NCPU 8
|
||||
-
|
||||
-#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1)))
|
||||
+#define ALL_CPU_MASK ((unsigned)(((1 << GIC_NCPU) - 1)))
|
||||
|
||||
/* The NVIC has 16 internal vectors. However these are not exposed
|
||||
through the normal GIC interface. */
|
||||
@@ -59,48 +52,6 @@
|
||||
s->priority2[(irq) - GIC_INTERNAL])
|
||||
#define GIC_TARGET(irq) s->irq_target[irq]
|
||||
|
||||
-typedef struct gic_irq_state {
|
||||
- /* The enable bits are only banked for per-cpu interrupts. */
|
||||
- uint8_t enabled;
|
||||
- uint8_t pending;
|
||||
- uint8_t active;
|
||||
- uint8_t level;
|
||||
- bool model; /* 0 = N:N, 1 = 1:N */
|
||||
- bool trigger; /* nonzero = edge triggered. */
|
||||
-} gic_irq_state;
|
||||
-
|
||||
-typedef struct GICState {
|
||||
- /*< private >*/
|
||||
- SysBusDevice parent_obj;
|
||||
- /*< public >*/
|
||||
-
|
||||
- qemu_irq parent_irq[NCPU];
|
||||
- bool enabled;
|
||||
- bool cpu_enabled[NCPU];
|
||||
-
|
||||
- gic_irq_state irq_state[GIC_MAXIRQ];
|
||||
- uint8_t irq_target[GIC_MAXIRQ];
|
||||
- uint8_t priority1[GIC_INTERNAL][NCPU];
|
||||
- uint8_t priority2[GIC_MAXIRQ - GIC_INTERNAL];
|
||||
- uint16_t last_active[GIC_MAXIRQ][NCPU];
|
||||
-
|
||||
- uint16_t priority_mask[NCPU];
|
||||
- uint16_t running_irq[NCPU];
|
||||
- uint16_t running_priority[NCPU];
|
||||
- uint16_t current_pending[NCPU];
|
||||
-
|
||||
- uint32_t num_cpu;
|
||||
-
|
||||
- MemoryRegion iomem; /* Distributor */
|
||||
- /* This is just so we can have an opaque pointer which identifies
|
||||
- * both this GIC and which CPU interface we should be accessing.
|
||||
- */
|
||||
- struct GICState *backref[NCPU];
|
||||
- MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
|
||||
- uint32_t num_irq;
|
||||
- uint32_t revision;
|
||||
-} GICState;
|
||||
-
|
||||
/* The special cases for the revision property: */
|
||||
#define REV_11MPCORE 0
|
||||
#define REV_NVIC 0xffffffff
|
||||
@@ -111,31 +62,4 @@ void gic_complete_irq(GICState *s, int cpu, int irq);
|
||||
void gic_update(GICState *s);
|
||||
void gic_init_irqs_and_distributor(GICState *s, int num_irq);
|
||||
|
||||
-#define TYPE_ARM_GIC_COMMON "arm_gic_common"
|
||||
-#define ARM_GIC_COMMON(obj) \
|
||||
- OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC_COMMON)
|
||||
-#define ARM_GIC_COMMON_CLASS(klass) \
|
||||
- OBJECT_CLASS_CHECK(ARMGICCommonClass, (klass), TYPE_ARM_GIC_COMMON)
|
||||
-#define ARM_GIC_COMMON_GET_CLASS(obj) \
|
||||
- OBJECT_GET_CLASS(ARMGICCommonClass, (obj), TYPE_ARM_GIC_COMMON)
|
||||
-
|
||||
-typedef struct ARMGICCommonClass {
|
||||
- SysBusDeviceClass parent_class;
|
||||
- void (*pre_save)(GICState *s);
|
||||
- void (*post_load)(GICState *s);
|
||||
-} ARMGICCommonClass;
|
||||
-
|
||||
-#define TYPE_ARM_GIC "arm_gic"
|
||||
-#define ARM_GIC(obj) \
|
||||
- OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC)
|
||||
-#define ARM_GIC_CLASS(klass) \
|
||||
- OBJECT_CLASS_CHECK(ARMGICClass, (klass), TYPE_ARM_GIC)
|
||||
-#define ARM_GIC_GET_CLASS(obj) \
|
||||
- OBJECT_GET_CLASS(ARMGICClass, (obj), TYPE_ARM_GIC)
|
||||
-
|
||||
-typedef struct ARMGICClass {
|
||||
- ARMGICCommonClass parent_class;
|
||||
- DeviceRealize parent_realize;
|
||||
-} ARMGICClass;
|
||||
-
|
||||
#endif /* !QEMU_ARM_GIC_INTERNAL_H */
|
||||
diff --git a/include/hw/intc/arm_gic.h b/include/hw/intc/arm_gic.h
|
||||
new file mode 100644
|
||||
index 0000000..0971e37
|
||||
--- /dev/null
|
||||
+++ b/include/hw/intc/arm_gic.h
|
||||
@@ -0,0 +1,42 @@
|
||||
+/*
|
||||
+ * ARM GIC support
|
||||
+ *
|
||||
+ * Copyright (c) 2012 Linaro Limited
|
||||
+ * Written by Peter Maydell
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation, either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License along
|
||||
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#ifndef HW_ARM_GIC_H
|
||||
+#define HW_ARM_GIC_H
|
||||
+
|
||||
+#include "arm_gic_common.h"
|
||||
+
|
||||
+#define TYPE_ARM_GIC "arm_gic"
|
||||
+#define ARM_GIC(obj) \
|
||||
+ OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC)
|
||||
+#define ARM_GIC_CLASS(klass) \
|
||||
+ OBJECT_CLASS_CHECK(ARMGICClass, (klass), TYPE_ARM_GIC)
|
||||
+#define ARM_GIC_GET_CLASS(obj) \
|
||||
+ OBJECT_GET_CLASS(ARMGICClass, (obj), TYPE_ARM_GIC)
|
||||
+
|
||||
+typedef struct ARMGICClass {
|
||||
+ /*< private >*/
|
||||
+ ARMGICCommonClass parent_class;
|
||||
+ /*< public >*/
|
||||
+
|
||||
+ DeviceRealize parent_realize;
|
||||
+} ARMGICClass;
|
||||
+
|
||||
+#endif
|
||||
diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h
|
||||
new file mode 100644
|
||||
index 0000000..4f381bd
|
||||
--- /dev/null
|
||||
+++ b/include/hw/intc/arm_gic_common.h
|
||||
@@ -0,0 +1,92 @@
|
||||
+/*
|
||||
+ * ARM GIC support
|
||||
+ *
|
||||
+ * Copyright (c) 2012 Linaro Limited
|
||||
+ * Written by Peter Maydell
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation, either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License along
|
||||
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#ifndef HW_ARM_GIC_COMMON_H
|
||||
+#define HW_ARM_GIC_COMMON_H
|
||||
+
|
||||
+#include "hw/sysbus.h"
|
||||
+
|
||||
+/* Maximum number of possible interrupts, determined by the GIC architecture */
|
||||
+#define GIC_MAXIRQ 1020
|
||||
+/* First 32 are private to each CPU (SGIs and PPIs). */
|
||||
+#define GIC_INTERNAL 32
|
||||
+/* Maximum number of possible CPU interfaces, determined by GIC architecture */
|
||||
+#define GIC_NCPU 8
|
||||
+
|
||||
+typedef struct gic_irq_state {
|
||||
+ /* The enable bits are only banked for per-cpu interrupts. */
|
||||
+ uint8_t enabled;
|
||||
+ uint8_t pending;
|
||||
+ uint8_t active;
|
||||
+ uint8_t level;
|
||||
+ bool model; /* 0 = N:N, 1 = 1:N */
|
||||
+ bool trigger; /* nonzero = edge triggered. */
|
||||
+} gic_irq_state;
|
||||
+
|
||||
+typedef struct GICState {
|
||||
+ /*< private >*/
|
||||
+ SysBusDevice parent_obj;
|
||||
+ /*< public >*/
|
||||
+
|
||||
+ qemu_irq parent_irq[GIC_NCPU];
|
||||
+ bool enabled;
|
||||
+ bool cpu_enabled[GIC_NCPU];
|
||||
+
|
||||
+ gic_irq_state irq_state[GIC_MAXIRQ];
|
||||
+ uint8_t irq_target[GIC_MAXIRQ];
|
||||
+ uint8_t priority1[GIC_INTERNAL][GIC_NCPU];
|
||||
+ uint8_t priority2[GIC_MAXIRQ - GIC_INTERNAL];
|
||||
+ uint16_t last_active[GIC_MAXIRQ][GIC_NCPU];
|
||||
+
|
||||
+ uint16_t priority_mask[GIC_NCPU];
|
||||
+ uint16_t running_irq[GIC_NCPU];
|
||||
+ uint16_t running_priority[GIC_NCPU];
|
||||
+ uint16_t current_pending[GIC_NCPU];
|
||||
+
|
||||
+ uint32_t num_cpu;
|
||||
+
|
||||
+ MemoryRegion iomem; /* Distributor */
|
||||
+ /* This is just so we can have an opaque pointer which identifies
|
||||
+ * both this GIC and which CPU interface we should be accessing.
|
||||
+ */
|
||||
+ struct GICState *backref[GIC_NCPU];
|
||||
+ MemoryRegion cpuiomem[GIC_NCPU + 1]; /* CPU interfaces */
|
||||
+ uint32_t num_irq;
|
||||
+ uint32_t revision;
|
||||
+} GICState;
|
||||
+
|
||||
+#define TYPE_ARM_GIC_COMMON "arm_gic_common"
|
||||
+#define ARM_GIC_COMMON(obj) \
|
||||
+ OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC_COMMON)
|
||||
+#define ARM_GIC_COMMON_CLASS(klass) \
|
||||
+ OBJECT_CLASS_CHECK(ARMGICCommonClass, (klass), TYPE_ARM_GIC_COMMON)
|
||||
+#define ARM_GIC_COMMON_GET_CLASS(obj) \
|
||||
+ OBJECT_GET_CLASS(ARMGICCommonClass, (obj), TYPE_ARM_GIC_COMMON)
|
||||
+
|
||||
+typedef struct ARMGICCommonClass {
|
||||
+ /*< private >*/
|
||||
+ SysBusDeviceClass parent_class;
|
||||
+ /*< public >*/
|
||||
+
|
||||
+ void (*pre_save)(GICState *s);
|
||||
+ void (*post_load)(GICState *s);
|
||||
+} ARMGICCommonClass;
|
||||
+
|
||||
+#endif
|
124
0211-arm_gic-Rename-GIC_X_TRIGGER-to-GIC_X_EDGE_TRIGGER.patch
Normal file
124
0211-arm_gic-Rename-GIC_X_TRIGGER-to-GIC_X_EDGE_TRIGGER.patch
Normal file
@ -0,0 +1,124 @@
|
||||
From: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Date: Fri, 20 Dec 2013 22:09:32 -0800
|
||||
Subject: [PATCH] arm_gic: Rename GIC_X_TRIGGER to GIC_X_EDGE_TRIGGER
|
||||
|
||||
TRIGGER can really mean mean anything (e.g. was it triggered, is it
|
||||
level-triggered, is it edge-triggered, etc.). Rename to EDGE_TRIGGER to
|
||||
make the code comprehensible without looking up the data structure.
|
||||
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Message-id: 1387606179-22709-2-git-send-email-christoffer.dall@linaro.org
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit 04050c5c6aa6f9c086a63a30b182b996fb2d3d02)
|
||||
---
|
||||
hw/intc/arm_gic.c | 12 ++++++------
|
||||
hw/intc/arm_gic_common.c | 4 ++--
|
||||
hw/intc/gic_internal.h | 6 +++---
|
||||
include/hw/intc/arm_gic_common.h | 2 +-
|
||||
4 files changed, 12 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
|
||||
index d431b7a..27c258a 100644
|
||||
--- a/hw/intc/arm_gic.c
|
||||
+++ b/hw/intc/arm_gic.c
|
||||
@@ -128,7 +128,7 @@ static void gic_set_irq(void *opaque, int irq, int level)
|
||||
|
||||
if (level) {
|
||||
GIC_SET_LEVEL(irq, cm);
|
||||
- if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
|
||||
+ if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
|
||||
DPRINTF("Set %d pending mask %x\n", irq, target);
|
||||
GIC_SET_PENDING(irq, target);
|
||||
}
|
||||
@@ -188,7 +188,7 @@ void gic_complete_irq(GICState *s, int cpu, int irq)
|
||||
return; /* No active IRQ. */
|
||||
/* Mark level triggered interrupts as pending if they are still
|
||||
raised. */
|
||||
- if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
|
||||
+ if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
|
||||
&& GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
|
||||
DPRINTF("Set %d pending mask %x\n", irq, cm);
|
||||
GIC_SET_PENDING(irq, cm);
|
||||
@@ -311,7 +311,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset)
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (GIC_TEST_MODEL(irq + i))
|
||||
res |= (1 << (i * 2));
|
||||
- if (GIC_TEST_TRIGGER(irq + i))
|
||||
+ if (GIC_TEST_EDGE_TRIGGER(irq + i))
|
||||
res |= (2 << (i * 2));
|
||||
}
|
||||
} else if (offset < 0xfe0) {
|
||||
@@ -386,7 +386,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
||||
/* If a raised level triggered IRQ enabled then mark
|
||||
is as pending. */
|
||||
if (GIC_TEST_LEVEL(irq + i, mask)
|
||||
- && !GIC_TEST_TRIGGER(irq + i)) {
|
||||
+ && !GIC_TEST_EDGE_TRIGGER(irq + i)) {
|
||||
DPRINTF("Set %d pending mask %x\n", irq + i, mask);
|
||||
GIC_SET_PENDING(irq + i, mask);
|
||||
}
|
||||
@@ -478,9 +478,9 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
||||
GIC_CLEAR_MODEL(irq + i);
|
||||
}
|
||||
if (value & (2 << (i * 2))) {
|
||||
- GIC_SET_TRIGGER(irq + i);
|
||||
+ GIC_SET_EDGE_TRIGGER(irq + i);
|
||||
} else {
|
||||
- GIC_CLEAR_TRIGGER(irq + i);
|
||||
+ GIC_CLEAR_EDGE_TRIGGER(irq + i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
|
||||
index c765850..710607b 100644
|
||||
--- a/hw/intc/arm_gic_common.c
|
||||
+++ b/hw/intc/arm_gic_common.c
|
||||
@@ -51,7 +51,7 @@ static const VMStateDescription vmstate_gic_irq_state = {
|
||||
VMSTATE_UINT8(active, gic_irq_state),
|
||||
VMSTATE_UINT8(level, gic_irq_state),
|
||||
VMSTATE_BOOL(model, gic_irq_state),
|
||||
- VMSTATE_BOOL(trigger, gic_irq_state),
|
||||
+ VMSTATE_BOOL(edge_trigger, gic_irq_state),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
@@ -126,7 +126,7 @@ static void arm_gic_common_reset(DeviceState *dev)
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
GIC_SET_ENABLED(i, ALL_CPU_MASK);
|
||||
- GIC_SET_TRIGGER(i);
|
||||
+ GIC_SET_EDGE_TRIGGER(i);
|
||||
}
|
||||
if (s->num_cpu == 1) {
|
||||
/* For uniprocessor GICs all interrupts always target the sole CPU */
|
||||
diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h
|
||||
index 3989fd1..efac78d 100644
|
||||
--- a/hw/intc/gic_internal.h
|
||||
+++ b/hw/intc/gic_internal.h
|
||||
@@ -44,9 +44,9 @@
|
||||
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
|
||||
#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
|
||||
#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
|
||||
-#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = true
|
||||
-#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = false
|
||||
-#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
|
||||
+#define GIC_SET_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = true
|
||||
+#define GIC_CLEAR_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = false
|
||||
+#define GIC_TEST_EDGE_TRIGGER(irq) (s->irq_state[irq].edge_trigger)
|
||||
#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ? \
|
||||
s->priority1[irq][cpu] : \
|
||||
s->priority2[(irq) - GIC_INTERNAL])
|
||||
diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h
|
||||
index 4f381bd..0d232df 100644
|
||||
--- a/include/hw/intc/arm_gic_common.h
|
||||
+++ b/include/hw/intc/arm_gic_common.h
|
||||
@@ -37,7 +37,7 @@ typedef struct gic_irq_state {
|
||||
uint8_t active;
|
||||
uint8_t level;
|
||||
bool model; /* 0 = N:N, 1 = 1:N */
|
||||
- bool trigger; /* nonzero = edge triggered. */
|
||||
+ bool edge_trigger; /* true: edge-triggered, false: level-triggered */
|
||||
} gic_irq_state;
|
||||
|
||||
typedef struct GICState {
|
62
0212-hw-arm_gic-Introduce-gic_set_priority-function.patch
Normal file
62
0212-hw-arm_gic-Introduce-gic_set_priority-function.patch
Normal file
@ -0,0 +1,62 @@
|
||||
From: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Date: Fri, 20 Dec 2013 22:09:33 -0800
|
||||
Subject: [PATCH] hw: arm_gic: Introduce gic_set_priority function
|
||||
|
||||
To make the code slightly cleaner to look at and make the save/restore
|
||||
code easier to understand, introduce this function to set the priority of
|
||||
interrupts.
|
||||
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Message-id: 1387606179-22709-3-git-send-email-christoffer.dall@linaro.org
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit 9df90ad078ec782d1339bd6879b6ea117f9759f7)
|
||||
---
|
||||
hw/intc/arm_gic.c | 15 ++++++++++-----
|
||||
hw/intc/gic_internal.h | 1 +
|
||||
2 files changed, 11 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
|
||||
index 27c258a..6c59650 100644
|
||||
--- a/hw/intc/arm_gic.c
|
||||
+++ b/hw/intc/arm_gic.c
|
||||
@@ -168,6 +168,15 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu)
|
||||
return new_irq;
|
||||
}
|
||||
|
||||
+void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val)
|
||||
+{
|
||||
+ if (irq < GIC_INTERNAL) {
|
||||
+ s->priority1[irq][cpu] = val;
|
||||
+ } else {
|
||||
+ s->priority2[(irq) - GIC_INTERNAL] = val;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void gic_complete_irq(GICState *s, int cpu, int irq)
|
||||
{
|
||||
int update = 0;
|
||||
@@ -443,11 +452,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
||||
irq = (offset - 0x400) + GIC_BASE_IRQ;
|
||||
if (irq >= s->num_irq)
|
||||
goto bad_reg;
|
||||
- if (irq < GIC_INTERNAL) {
|
||||
- s->priority1[irq][cpu] = value;
|
||||
- } else {
|
||||
- s->priority2[irq - GIC_INTERNAL] = value;
|
||||
- }
|
||||
+ gic_set_priority(s, cpu, irq, value);
|
||||
} else if (offset < 0xc00) {
|
||||
/* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the
|
||||
* annoying exception of the 11MPCore's GIC.
|
||||
diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h
|
||||
index efac78d..8c02d58 100644
|
||||
--- a/hw/intc/gic_internal.h
|
||||
+++ b/hw/intc/gic_internal.h
|
||||
@@ -61,5 +61,6 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu);
|
||||
void gic_complete_irq(GICState *s, int cpu, int irq);
|
||||
void gic_update(GICState *s);
|
||||
void gic_init_irqs_and_distributor(GICState *s, int num_irq);
|
||||
+void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val);
|
||||
|
||||
#endif /* !QEMU_ARM_GIC_INTERNAL_H */
|
70
0213-arm_gic-Introduce-define-for-GIC_NR_SGIS.patch
Normal file
70
0213-arm_gic-Introduce-define-for-GIC_NR_SGIS.patch
Normal file
@ -0,0 +1,70 @@
|
||||
From: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Date: Fri, 31 Jan 2014 14:47:38 +0000
|
||||
Subject: [PATCH] arm_gic: Introduce define for GIC_NR_SGIS
|
||||
|
||||
Instead of hardcoding 16 various places in the code, use a define to
|
||||
make it more clear what is going on.
|
||||
|
||||
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit 41ab7b55108e2699e7c2e77788465cb52a0b2c08)
|
||||
---
|
||||
hw/intc/arm_gic.c | 17 +++++++++++------
|
||||
include/hw/intc/arm_gic_common.h | 1 +
|
||||
2 files changed, 12 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
|
||||
index 6c59650..0ce11ac 100644
|
||||
--- a/hw/intc/arm_gic.c
|
||||
+++ b/hw/intc/arm_gic.c
|
||||
@@ -380,8 +380,10 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
||||
irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
|
||||
if (irq >= s->num_irq)
|
||||
goto bad_reg;
|
||||
- if (irq < 16)
|
||||
- value = 0xff;
|
||||
+ if (irq < GIC_NR_SGIS) {
|
||||
+ value = 0xff;
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (value & (1 << i)) {
|
||||
int mask =
|
||||
@@ -406,8 +408,10 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
||||
irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
|
||||
if (irq >= s->num_irq)
|
||||
goto bad_reg;
|
||||
- if (irq < 16)
|
||||
- value = 0;
|
||||
+ if (irq < GIC_NR_SGIS) {
|
||||
+ value = 0;
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (value & (1 << i)) {
|
||||
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
|
||||
@@ -423,8 +427,9 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
||||
irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
|
||||
if (irq >= s->num_irq)
|
||||
goto bad_reg;
|
||||
- if (irq < 16)
|
||||
- irq = 0;
|
||||
+ if (irq < GIC_NR_SGIS) {
|
||||
+ irq = 0;
|
||||
+ }
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (value & (1 << i)) {
|
||||
diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h
|
||||
index 0d232df..8a2aa00 100644
|
||||
--- a/include/hw/intc/arm_gic_common.h
|
||||
+++ b/include/hw/intc/arm_gic_common.h
|
||||
@@ -27,6 +27,7 @@
|
||||
#define GIC_MAXIRQ 1020
|
||||
/* First 32 are private to each CPU (SGIs and PPIs). */
|
||||
#define GIC_INTERNAL 32
|
||||
+#define GIC_NR_SGIS 16
|
||||
/* Maximum number of possible CPU interfaces, determined by GIC architecture */
|
||||
#define GIC_NCPU 8
|
||||
|
39
0214-arm_gic-Fix-GICD_ICPENDR-and-GICD_ISPENDR-writes.patch
Normal file
39
0214-arm_gic-Fix-GICD_ICPENDR-and-GICD_ISPENDR-writes.patch
Normal file
@ -0,0 +1,39 @@
|
||||
From: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Date: Fri, 31 Jan 2014 14:47:38 +0000
|
||||
Subject: [PATCH] arm_gic: Fix GICD_ICPENDR and GICD_ISPENDR writes
|
||||
|
||||
Fix two bugs that would allow changing the state of SGIs through the
|
||||
ICPENDR and ISPENDRs.
|
||||
|
||||
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit 5b0adce156216fb24dcc5f1683e8b686f3793fff)
|
||||
---
|
||||
hw/intc/arm_gic.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
|
||||
index 0ce11ac..62153fd 100644
|
||||
--- a/hw/intc/arm_gic.c
|
||||
+++ b/hw/intc/arm_gic.c
|
||||
@@ -428,7 +428,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
||||
if (irq >= s->num_irq)
|
||||
goto bad_reg;
|
||||
if (irq < GIC_NR_SGIS) {
|
||||
- irq = 0;
|
||||
+ value = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
@@ -441,6 +441,10 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
||||
irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
|
||||
if (irq >= s->num_irq)
|
||||
goto bad_reg;
|
||||
+ if (irq < GIC_NR_SGIS) {
|
||||
+ value = 0;
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* ??? This currently clears the pending bit for all CPUs, even
|
||||
for per-CPU interrupts. It's unclear whether this is the
|
196
0215-arm_gic-Fix-GIC-pending-behavior.patch
Normal file
196
0215-arm_gic-Fix-GIC-pending-behavior.patch
Normal file
@ -0,0 +1,196 @@
|
||||
From: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Date: Mon, 18 Nov 2013 20:32:00 -0800
|
||||
Subject: [PATCH] arm_gic: Fix GIC pending behavior
|
||||
|
||||
The existing implementation of the pending behavior in gic_set_irq,
|
||||
gic_complete_irq, and the distributor pending set/clear registers does
|
||||
not follow the semantics of the GICv2.0 specs, but may implement the
|
||||
11MPCore support. Therefore, maintain the existing semantics for
|
||||
11MPCore and v7M NVIC and change the behavior to be in accordance with
|
||||
the GICv2.0 specs for "generic implementations" (s->revision == 1 ||
|
||||
s->revision == 2).
|
||||
|
||||
Generic implementations distinguish between setting a level-triggered
|
||||
interrupt pending through writes to the GICD_ISPENDR and when hardware
|
||||
raises the interrupt line. Writing to the GICD_ICPENDR will not cause
|
||||
the interrupt to become non-pending if the line is still active, and
|
||||
conversely, if the line is deactivated but the interrupt is marked as
|
||||
pending through a write to GICD_ISPENDR, the interrupt remains pending.
|
||||
Handle this situation in the GIC_TEST_PENDING (which now becomes a
|
||||
static inline named gic_test_pending) and let the 'pending' field
|
||||
correspond only to the latched state of the D-flip flop in the GICv2.0
|
||||
specs Figure 4-10.
|
||||
|
||||
The following changes are added:
|
||||
|
||||
gic_test_pending:
|
||||
Make this a static inline and split out the 11MPCore from the generic
|
||||
behavior. For the generic behavior, consider interrupts pending if:
|
||||
((s->irq_state[irq].pending & (cm) != 0) ||
|
||||
(!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_LEVEL(irq, cm))
|
||||
|
||||
gic_set_irq:
|
||||
Split out the 11MPCore from the generic behavior. For the generic
|
||||
behavior, always GIC_SET_LEVEL() on positive level, but only
|
||||
GIC_SET_PENDING for edge-triggered interrupts and always simply
|
||||
GIC_CLEAR_LEVEL() on negative level.
|
||||
|
||||
gic_complete_irq:
|
||||
Only resample the line for line-triggered interrupts on an 11MPCore.
|
||||
Generic implementations will sample the line directly in
|
||||
gic_test_pending().
|
||||
|
||||
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit 8d999995e45c1002aa11f269c98f2e93e6f8c42a)
|
||||
---
|
||||
hw/intc/arm_gic.c | 64 ++++++++++++++++++++++++++++++++++++--------------
|
||||
hw/intc/gic_internal.h | 16 ++++++++++++-
|
||||
2 files changed, 62 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
|
||||
index 62153fd..11fe3c4 100644
|
||||
--- a/hw/intc/arm_gic.c
|
||||
+++ b/hw/intc/arm_gic.c
|
||||
@@ -66,7 +66,7 @@ void gic_update(GICState *s)
|
||||
best_prio = 0x100;
|
||||
best_irq = 1023;
|
||||
for (irq = 0; irq < s->num_irq; irq++) {
|
||||
- if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
|
||||
+ if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm)) {
|
||||
if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
|
||||
best_prio = GIC_GET_PRIORITY(irq, cpu);
|
||||
best_irq = irq;
|
||||
@@ -89,14 +89,43 @@ void gic_set_pending_private(GICState *s, int cpu, int irq)
|
||||
{
|
||||
int cm = 1 << cpu;
|
||||
|
||||
- if (GIC_TEST_PENDING(irq, cm))
|
||||
+ if (gic_test_pending(s, irq, cm)) {
|
||||
return;
|
||||
+ }
|
||||
|
||||
DPRINTF("Set %d pending cpu %d\n", irq, cpu);
|
||||
GIC_SET_PENDING(irq, cm);
|
||||
gic_update(s);
|
||||
}
|
||||
|
||||
+static void gic_set_irq_11mpcore(GICState *s, int irq, int level,
|
||||
+ int cm, int target)
|
||||
+{
|
||||
+ if (level) {
|
||||
+ GIC_SET_LEVEL(irq, cm);
|
||||
+ if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
|
||||
+ DPRINTF("Set %d pending mask %x\n", irq, target);
|
||||
+ GIC_SET_PENDING(irq, target);
|
||||
+ }
|
||||
+ } else {
|
||||
+ GIC_CLEAR_LEVEL(irq, cm);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void gic_set_irq_generic(GICState *s, int irq, int level,
|
||||
+ int cm, int target)
|
||||
+{
|
||||
+ if (level) {
|
||||
+ GIC_SET_LEVEL(irq, cm);
|
||||
+ DPRINTF("Set %d pending mask %x\n", irq, target);
|
||||
+ if (GIC_TEST_EDGE_TRIGGER(irq)) {
|
||||
+ GIC_SET_PENDING(irq, target);
|
||||
+ }
|
||||
+ } else {
|
||||
+ GIC_CLEAR_LEVEL(irq, cm);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* Process a change in an external IRQ input. */
|
||||
static void gic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
@@ -126,15 +155,12 @@ static void gic_set_irq(void *opaque, int irq, int level)
|
||||
return;
|
||||
}
|
||||
|
||||
- if (level) {
|
||||
- GIC_SET_LEVEL(irq, cm);
|
||||
- if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
|
||||
- DPRINTF("Set %d pending mask %x\n", irq, target);
|
||||
- GIC_SET_PENDING(irq, target);
|
||||
- }
|
||||
+ if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
|
||||
+ gic_set_irq_11mpcore(s, irq, level, cm, target);
|
||||
} else {
|
||||
- GIC_CLEAR_LEVEL(irq, cm);
|
||||
+ gic_set_irq_generic(s, irq, level, cm, target);
|
||||
}
|
||||
+
|
||||
gic_update(s);
|
||||
}
|
||||
|
||||
@@ -195,14 +221,18 @@ void gic_complete_irq(GICState *s, int cpu, int irq)
|
||||
}
|
||||
if (s->running_irq[cpu] == 1023)
|
||||
return; /* No active IRQ. */
|
||||
- /* Mark level triggered interrupts as pending if they are still
|
||||
- raised. */
|
||||
- if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
|
||||
- && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
|
||||
- DPRINTF("Set %d pending mask %x\n", irq, cm);
|
||||
- GIC_SET_PENDING(irq, cm);
|
||||
- update = 1;
|
||||
+
|
||||
+ if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
|
||||
+ /* Mark level triggered interrupts as pending if they are still
|
||||
+ raised. */
|
||||
+ if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
|
||||
+ && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
|
||||
+ DPRINTF("Set %d pending mask %x\n", irq, cm);
|
||||
+ GIC_SET_PENDING(irq, cm);
|
||||
+ update = 1;
|
||||
+ }
|
||||
}
|
||||
+
|
||||
if (irq != s->running_irq[cpu]) {
|
||||
/* Complete an IRQ that is not currently running. */
|
||||
int tmp = s->running_irq[cpu];
|
||||
@@ -273,7 +303,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset)
|
||||
res = 0;
|
||||
mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK;
|
||||
for (i = 0; i < 8; i++) {
|
||||
- if (GIC_TEST_PENDING(irq + i, mask)) {
|
||||
+ if (gic_test_pending(s, irq + i, mask)) {
|
||||
res |= (1 << i);
|
||||
}
|
||||
}
|
||||
diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h
|
||||
index 8c02d58..92a6f7a 100644
|
||||
--- a/hw/intc/gic_internal.h
|
||||
+++ b/hw/intc/gic_internal.h
|
||||
@@ -34,7 +34,6 @@
|
||||
#define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0)
|
||||
#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
|
||||
#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
|
||||
-#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
|
||||
#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
|
||||
#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
|
||||
#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
|
||||
@@ -63,4 +62,19 @@ void gic_update(GICState *s);
|
||||
void gic_init_irqs_and_distributor(GICState *s, int num_irq);
|
||||
void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val);
|
||||
|
||||
+static inline bool gic_test_pending(GICState *s, int irq, int cm)
|
||||
+{
|
||||
+ if (s->revision == REV_NVIC || s->revision == REV_11MPCORE) {
|
||||
+ return s->irq_state[irq].pending & cm;
|
||||
+ } else {
|
||||
+ /* Edge-triggered interrupts are marked pending on a rising edge, but
|
||||
+ * level-triggered interrupts are either considered pending when the
|
||||
+ * level is active or if software has explicitly written to
|
||||
+ * GICD_ISPENDR to set the state pending.
|
||||
+ */
|
||||
+ return (s->irq_state[irq].pending & cm) ||
|
||||
+ (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_LEVEL(irq, cm));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
#endif /* !QEMU_ARM_GIC_INTERNAL_H */
|
217
0216-arm_gic-Keep-track-of-SGI-sources.patch
Normal file
217
0216-arm_gic-Keep-track-of-SGI-sources.patch
Normal file
@ -0,0 +1,217 @@
|
||||
From: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Date: Mon, 18 Nov 2013 20:32:00 -0800
|
||||
Subject: [PATCH] arm_gic: Keep track of SGI sources
|
||||
|
||||
Right now the arm gic emulation doesn't keep track of the source of an
|
||||
SGI (which apparently Linux guests don't use, or they're fine with
|
||||
assuming CPU 0 always).
|
||||
|
||||
Add the necessary matrix on the GICState structure and maintain the data
|
||||
when setting and clearing the pending state of an IRQ and make the state
|
||||
visible to the guest.
|
||||
|
||||
Note that we always choose to present the source as the lowest-numbered
|
||||
CPU in case multiple cores have signalled the same SGI number to a core
|
||||
on the system.
|
||||
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit 40d225009efe17cad647b4b7424b77a3ace232f1)
|
||||
---
|
||||
hw/intc/arm_gic.c | 98 +++++++++++++++++++++++++++++++++++-----
|
||||
hw/intc/arm_gic_common.c | 5 +-
|
||||
include/hw/intc/arm_gic_common.h | 7 +++
|
||||
3 files changed, 96 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
|
||||
index 11fe3c4..29f98be 100644
|
||||
--- a/hw/intc/arm_gic.c
|
||||
+++ b/hw/intc/arm_gic.c
|
||||
@@ -151,6 +151,8 @@ static void gic_set_irq(void *opaque, int irq, int level)
|
||||
target = cm;
|
||||
}
|
||||
|
||||
+ assert(irq >= GIC_NR_SGIS);
|
||||
+
|
||||
if (level == GIC_TEST_LEVEL(irq, cm)) {
|
||||
return;
|
||||
}
|
||||
@@ -177,21 +179,48 @@ static void gic_set_running_irq(GICState *s, int cpu, int irq)
|
||||
|
||||
uint32_t gic_acknowledge_irq(GICState *s, int cpu)
|
||||
{
|
||||
- int new_irq;
|
||||
+ int ret, irq, src;
|
||||
int cm = 1 << cpu;
|
||||
- new_irq = s->current_pending[cpu];
|
||||
- if (new_irq == 1023
|
||||
- || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
|
||||
+ irq = s->current_pending[cpu];
|
||||
+ if (irq == 1023
|
||||
+ || GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) {
|
||||
DPRINTF("ACK no pending IRQ\n");
|
||||
return 1023;
|
||||
}
|
||||
- s->last_active[new_irq][cpu] = s->running_irq[cpu];
|
||||
- /* Clear pending flags for both level and edge triggered interrupts.
|
||||
- Level triggered IRQs will be reasserted once they become inactive. */
|
||||
- GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
|
||||
- gic_set_running_irq(s, cpu, new_irq);
|
||||
- DPRINTF("ACK %d\n", new_irq);
|
||||
- return new_irq;
|
||||
+ s->last_active[irq][cpu] = s->running_irq[cpu];
|
||||
+
|
||||
+ if (s->revision == REV_11MPCORE) {
|
||||
+ /* Clear pending flags for both level and edge triggered interrupts.
|
||||
+ * Level triggered IRQs will be reasserted once they become inactive.
|
||||
+ */
|
||||
+ GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm);
|
||||
+ ret = irq;
|
||||
+ } else {
|
||||
+ if (irq < GIC_NR_SGIS) {
|
||||
+ /* Lookup the source CPU for the SGI and clear this in the
|
||||
+ * sgi_pending map. Return the src and clear the overall pending
|
||||
+ * state on this CPU if the SGI is not pending from any CPUs.
|
||||
+ */
|
||||
+ assert(s->sgi_pending[irq][cpu] != 0);
|
||||
+ src = ctz32(s->sgi_pending[irq][cpu]);
|
||||
+ s->sgi_pending[irq][cpu] &= ~(1 << src);
|
||||
+ if (s->sgi_pending[irq][cpu] == 0) {
|
||||
+ GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm);
|
||||
+ }
|
||||
+ ret = irq | ((src & 0x7) << 10);
|
||||
+ } else {
|
||||
+ /* Clear pending state for both level and edge triggered
|
||||
+ * interrupts. (level triggered interrupts with an active line
|
||||
+ * remain pending, see gic_test_pending)
|
||||
+ */
|
||||
+ GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm);
|
||||
+ ret = irq;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ gic_set_running_irq(s, cpu, irq);
|
||||
+ DPRINTF("ACK %d\n", irq);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val)
|
||||
@@ -353,6 +382,22 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset)
|
||||
if (GIC_TEST_EDGE_TRIGGER(irq + i))
|
||||
res |= (2 << (i * 2));
|
||||
}
|
||||
+ } else if (offset < 0xf10) {
|
||||
+ goto bad_reg;
|
||||
+ } else if (offset < 0xf30) {
|
||||
+ if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
|
||||
+ goto bad_reg;
|
||||
+ }
|
||||
+
|
||||
+ if (offset < 0xf20) {
|
||||
+ /* GICD_CPENDSGIRn */
|
||||
+ irq = (offset - 0xf10);
|
||||
+ } else {
|
||||
+ irq = (offset - 0xf20);
|
||||
+ /* GICD_SPENDSGIRn */
|
||||
+ }
|
||||
+
|
||||
+ res = s->sgi_pending[irq][cpu];
|
||||
} else if (offset < 0xfe0) {
|
||||
goto bad_reg;
|
||||
} else /* offset >= 0xfe0 */ {
|
||||
@@ -527,9 +572,31 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
|
||||
GIC_CLEAR_EDGE_TRIGGER(irq + i);
|
||||
}
|
||||
}
|
||||
- } else {
|
||||
+ } else if (offset < 0xf10) {
|
||||
/* 0xf00 is only handled for 32-bit writes. */
|
||||
goto bad_reg;
|
||||
+ } else if (offset < 0xf20) {
|
||||
+ /* GICD_CPENDSGIRn */
|
||||
+ if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
|
||||
+ goto bad_reg;
|
||||
+ }
|
||||
+ irq = (offset - 0xf10);
|
||||
+
|
||||
+ s->sgi_pending[irq][cpu] &= ~value;
|
||||
+ if (s->sgi_pending[irq][cpu] == 0) {
|
||||
+ GIC_CLEAR_PENDING(irq, 1 << cpu);
|
||||
+ }
|
||||
+ } else if (offset < 0xf30) {
|
||||
+ /* GICD_SPENDSGIRn */
|
||||
+ if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
|
||||
+ goto bad_reg;
|
||||
+ }
|
||||
+ irq = (offset - 0xf20);
|
||||
+
|
||||
+ GIC_SET_PENDING(irq, 1 << cpu);
|
||||
+ s->sgi_pending[irq][cpu] |= value;
|
||||
+ } else {
|
||||
+ goto bad_reg;
|
||||
}
|
||||
gic_update(s);
|
||||
return;
|
||||
@@ -553,6 +620,7 @@ static void gic_dist_writel(void *opaque, hwaddr offset,
|
||||
int cpu;
|
||||
int irq;
|
||||
int mask;
|
||||
+ int target_cpu;
|
||||
|
||||
cpu = gic_get_current_cpu(s);
|
||||
irq = value & 0x3ff;
|
||||
@@ -572,6 +640,12 @@ static void gic_dist_writel(void *opaque, hwaddr offset,
|
||||
break;
|
||||
}
|
||||
GIC_SET_PENDING(irq, mask);
|
||||
+ target_cpu = ctz32(mask);
|
||||
+ while (target_cpu < GIC_NCPU) {
|
||||
+ s->sgi_pending[irq][target_cpu] |= (1 << cpu);
|
||||
+ mask &= ~(1 << target_cpu);
|
||||
+ target_cpu = ctz32(mask);
|
||||
+ }
|
||||
gic_update(s);
|
||||
return;
|
||||
}
|
||||
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
|
||||
index 710607b..f4c7f14 100644
|
||||
--- a/hw/intc/arm_gic_common.c
|
||||
+++ b/hw/intc/arm_gic_common.c
|
||||
@@ -58,8 +58,8 @@ static const VMStateDescription vmstate_gic_irq_state = {
|
||||
|
||||
static const VMStateDescription vmstate_gic = {
|
||||
.name = "arm_gic",
|
||||
- .version_id = 4,
|
||||
- .minimum_version_id = 4,
|
||||
+ .version_id = 5,
|
||||
+ .minimum_version_id = 5,
|
||||
.pre_save = gic_pre_save,
|
||||
.post_load = gic_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
@@ -71,6 +71,7 @@ static const VMStateDescription vmstate_gic = {
|
||||
VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, GIC_NCPU),
|
||||
VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
|
||||
VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, GIC_NCPU),
|
||||
+ VMSTATE_UINT8_2DARRAY(sgi_pending, GICState, GIC_NR_SGIS, GIC_NCPU),
|
||||
VMSTATE_UINT16_ARRAY(priority_mask, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT16_ARRAY(running_irq, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU),
|
||||
diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h
|
||||
index 8a2aa00..d2e0c2f 100644
|
||||
--- a/include/hw/intc/arm_gic_common.h
|
||||
+++ b/include/hw/intc/arm_gic_common.h
|
||||
@@ -55,6 +55,13 @@ typedef struct GICState {
|
||||
uint8_t priority1[GIC_INTERNAL][GIC_NCPU];
|
||||
uint8_t priority2[GIC_MAXIRQ - GIC_INTERNAL];
|
||||
uint16_t last_active[GIC_MAXIRQ][GIC_NCPU];
|
||||
+ /* For each SGI on the target CPU, we store 8 bits
|
||||
+ * indicating which source CPUs have made this SGI
|
||||
+ * pending on the target CPU. These correspond to
|
||||
+ * the bytes in the GIC_SPENDSGIR* registers as
|
||||
+ * read by the target CPU.
|
||||
+ */
|
||||
+ uint8_t sgi_pending[GIC_NR_SGIS][GIC_NCPU];
|
||||
|
||||
uint16_t priority_mask[GIC_NCPU];
|
||||
uint16_t running_irq[GIC_NCPU];
|
99
0217-arm_gic-Support-setting-getting-binary-point-reg.patch
Normal file
99
0217-arm_gic-Support-setting-getting-binary-point-reg.patch
Normal file
@ -0,0 +1,99 @@
|
||||
From: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Date: Thu, 12 Sep 2013 22:18:20 -0700
|
||||
Subject: [PATCH] arm_gic: Support setting/getting binary point reg
|
||||
|
||||
Add a binary_point field to the gic emulation structure and support
|
||||
setting/getting this register now when we have it. We don't actually
|
||||
support interrupt grouping yet, oh well.
|
||||
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit aa7d461ae9dd79d35999f4710743cdf9dec88cef)
|
||||
---
|
||||
hw/intc/arm_gic.c | 12 +++++++++---
|
||||
hw/intc/arm_gic_common.c | 6 ++++--
|
||||
include/hw/intc/arm_gic_common.h | 7 +++++++
|
||||
3 files changed, 20 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
|
||||
index 29f98be..d31892d 100644
|
||||
--- a/hw/intc/arm_gic.c
|
||||
+++ b/hw/intc/arm_gic.c
|
||||
@@ -669,14 +669,15 @@ static uint32_t gic_cpu_read(GICState *s, int cpu, int offset)
|
||||
case 0x04: /* Priority mask */
|
||||
return s->priority_mask[cpu];
|
||||
case 0x08: /* Binary Point */
|
||||
- /* ??? Not implemented. */
|
||||
- return 0;
|
||||
+ return s->bpr[cpu];
|
||||
case 0x0c: /* Acknowledge */
|
||||
return gic_acknowledge_irq(s, cpu);
|
||||
case 0x14: /* Running Priority */
|
||||
return s->running_priority[cpu];
|
||||
case 0x18: /* Highest Pending Interrupt */
|
||||
return s->current_pending[cpu];
|
||||
+ case 0x1c: /* Aliased Binary Point */
|
||||
+ return s->abpr[cpu];
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_cpu_read: Bad offset %x\n", (int)offset);
|
||||
@@ -695,10 +696,15 @@ static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value)
|
||||
s->priority_mask[cpu] = (value & 0xff);
|
||||
break;
|
||||
case 0x08: /* Binary Point */
|
||||
- /* ??? Not implemented. */
|
||||
+ s->bpr[cpu] = (value & 0x7);
|
||||
break;
|
||||
case 0x10: /* End Of Interrupt */
|
||||
return gic_complete_irq(s, cpu, value & 0x3ff);
|
||||
+ case 0x1c: /* Aliased Binary Point */
|
||||
+ if (s->revision >= 2) {
|
||||
+ s->abpr[cpu] = (value & 0x7);
|
||||
+ }
|
||||
+ break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_cpu_write: Bad offset %x\n", (int)offset);
|
||||
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
|
||||
index f4c7f14..7966985 100644
|
||||
--- a/hw/intc/arm_gic_common.c
|
||||
+++ b/hw/intc/arm_gic_common.c
|
||||
@@ -58,8 +58,8 @@ static const VMStateDescription vmstate_gic_irq_state = {
|
||||
|
||||
static const VMStateDescription vmstate_gic = {
|
||||
.name = "arm_gic",
|
||||
- .version_id = 5,
|
||||
- .minimum_version_id = 5,
|
||||
+ .version_id = 6,
|
||||
+ .minimum_version_id = 6,
|
||||
.pre_save = gic_pre_save,
|
||||
.post_load = gic_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
@@ -76,6 +76,8 @@ static const VMStateDescription vmstate_gic = {
|
||||
VMSTATE_UINT16_ARRAY(running_irq, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU),
|
||||
+ VMSTATE_UINT8_ARRAY(bpr, GICState, GIC_NCPU),
|
||||
+ VMSTATE_UINT8_ARRAY(abpr, GICState, GIC_NCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h
|
||||
index d2e0c2f..983c3cf 100644
|
||||
--- a/include/hw/intc/arm_gic_common.h
|
||||
+++ b/include/hw/intc/arm_gic_common.h
|
||||
@@ -68,6 +68,13 @@ typedef struct GICState {
|
||||
uint16_t running_priority[GIC_NCPU];
|
||||
uint16_t current_pending[GIC_NCPU];
|
||||
|
||||
+ /* We present the GICv2 without security extensions to a guest and
|
||||
+ * therefore the guest can configure the GICC_CTLR to configure group 1
|
||||
+ * binary point in the abpr.
|
||||
+ */
|
||||
+ uint8_t bpr[GIC_NCPU];
|
||||
+ uint8_t abpr[GIC_NCPU];
|
||||
+
|
||||
uint32_t num_cpu;
|
||||
|
||||
MemoryRegion iomem; /* Distributor */
|
104
0218-arm_gic-Add-GICC_APRn-state-to-the-GICState.patch
Normal file
104
0218-arm_gic-Add-GICC_APRn-state-to-the-GICState.patch
Normal file
@ -0,0 +1,104 @@
|
||||
From: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Date: Mon, 18 Nov 2013 19:26:33 -0800
|
||||
Subject: [PATCH] arm_gic: Add GICC_APRn state to the GICState
|
||||
|
||||
The GICC_APRn registers are not currently supported by the ARM GIC v2.0
|
||||
emulation. This patch adds the missing state.
|
||||
|
||||
Note that we also change the number of APRs to use a define GIC_NR_APRS
|
||||
based on the maximum number of preemption levels. This patch also adds
|
||||
RAZ/WI accessors for the four registers on the emulated CPU interface.
|
||||
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
(cherry picked from commit a9d477c4e3d614409a48d12f34624c2dd9f1ec2d)
|
||||
---
|
||||
hw/intc/arm_gic.c | 5 +++++
|
||||
hw/intc/arm_gic_common.c | 5 +++--
|
||||
include/hw/intc/arm_gic_common.h | 19 +++++++++++++++++++
|
||||
3 files changed, 27 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
|
||||
index d31892d..9ca3f03 100644
|
||||
--- a/hw/intc/arm_gic.c
|
||||
+++ b/hw/intc/arm_gic.c
|
||||
@@ -678,6 +678,8 @@ static uint32_t gic_cpu_read(GICState *s, int cpu, int offset)
|
||||
return s->current_pending[cpu];
|
||||
case 0x1c: /* Aliased Binary Point */
|
||||
return s->abpr[cpu];
|
||||
+ case 0xd0: case 0xd4: case 0xd8: case 0xdc:
|
||||
+ return s->apr[(offset - 0xd0) / 4][cpu];
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_cpu_read: Bad offset %x\n", (int)offset);
|
||||
@@ -705,6 +707,9 @@ static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value)
|
||||
s->abpr[cpu] = (value & 0x7);
|
||||
}
|
||||
break;
|
||||
+ case 0xd0: case 0xd4: case 0xd8: case 0xdc:
|
||||
+ qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n");
|
||||
+ break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_cpu_write: Bad offset %x\n", (int)offset);
|
||||
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
|
||||
index 7966985..ec6286b 100644
|
||||
--- a/hw/intc/arm_gic_common.c
|
||||
+++ b/hw/intc/arm_gic_common.c
|
||||
@@ -58,8 +58,8 @@ static const VMStateDescription vmstate_gic_irq_state = {
|
||||
|
||||
static const VMStateDescription vmstate_gic = {
|
||||
.name = "arm_gic",
|
||||
- .version_id = 6,
|
||||
- .minimum_version_id = 6,
|
||||
+ .version_id = 7,
|
||||
+ .minimum_version_id = 7,
|
||||
.pre_save = gic_pre_save,
|
||||
.post_load = gic_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
@@ -78,6 +78,7 @@ static const VMStateDescription vmstate_gic = {
|
||||
VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT8_ARRAY(bpr, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT8_ARRAY(abpr, GICState, GIC_NCPU),
|
||||
+ VMSTATE_UINT32_2DARRAY(apr, GICState, GIC_NR_APRS, GIC_NCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h
|
||||
index 983c3cf..89384c2 100644
|
||||
--- a/include/hw/intc/arm_gic_common.h
|
||||
+++ b/include/hw/intc/arm_gic_common.h
|
||||
@@ -31,6 +31,9 @@
|
||||
/* Maximum number of possible CPU interfaces, determined by GIC architecture */
|
||||
#define GIC_NCPU 8
|
||||
|
||||
+#define MAX_NR_GROUP_PRIO 128
|
||||
+#define GIC_NR_APRS (MAX_NR_GROUP_PRIO / 32)
|
||||
+
|
||||
typedef struct gic_irq_state {
|
||||
/* The enable bits are only banked for per-cpu interrupts. */
|
||||
uint8_t enabled;
|
||||
@@ -75,6 +78,22 @@ typedef struct GICState {
|
||||
uint8_t bpr[GIC_NCPU];
|
||||
uint8_t abpr[GIC_NCPU];
|
||||
|
||||
+ /* The APR is implementation defined, so we choose a layout identical to
|
||||
+ * the KVM ABI layout for QEMU's implementation of the gic:
|
||||
+ * If an interrupt for preemption level X is active, then
|
||||
+ * APRn[X mod 32] == 0b1, where n = X / 32
|
||||
+ * otherwise the bit is clear.
|
||||
+ *
|
||||
+ * TODO: rewrite the interrupt acknowlege/complete routines to use
|
||||
+ * the APR registers to track the necessary information to update
|
||||
+ * s->running_priority[] on interrupt completion (ie completely remove
|
||||
+ * last_active[][] and running_irq[]). This will be necessary if we ever
|
||||
+ * want to support TCG<->KVM migration, or TCG guests which can
|
||||
+ * do power management involving powering down and restarting
|
||||
+ * the GIC.
|
||||
+ */
|
||||
+ uint32_t apr[GIC_NR_APRS][GIC_NCPU];
|
||||
+
|
||||
uint32_t num_cpu;
|
||||
|
||||
MemoryRegion iomem; /* Distributor */
|
31
0219-hw-intc-arm_gic-Fix-NVIC-assertion-failure.patch
Normal file
31
0219-hw-intc-arm_gic-Fix-NVIC-assertion-failure.patch
Normal file
@ -0,0 +1,31 @@
|
||||
From: Peter Maydell <peter.maydell@linaro.org>
|
||||
Date: Thu, 20 Feb 2014 10:35:48 +0000
|
||||
Subject: [PATCH] hw/intc/arm_gic: Fix NVIC assertion failure
|
||||
|
||||
Commit 40d225009ef accidentally changed the behaviour of
|
||||
gic_acknowledge_irq() for the NVIC. The NVIC doesn't have SGIs,
|
||||
so this meant we hit an assertion:
|
||||
gic_acknowledge_irq: Assertion `s->sgi_pending[irq][cpu] != 0' failed.
|
||||
|
||||
Return NVIC acknowledge-irq to its previous behaviour, like 11MPCore.
|
||||
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
|
||||
(cherry picked from commit 873169022aa58daabd10979002f8009c7e5f3f05)
|
||||
---
|
||||
hw/intc/arm_gic.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
|
||||
index 9ca3f03..4e0628c 100644
|
||||
--- a/hw/intc/arm_gic.c
|
||||
+++ b/hw/intc/arm_gic.c
|
||||
@@ -189,7 +189,7 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu)
|
||||
}
|
||||
s->last_active[irq][cpu] = s->running_irq[cpu];
|
||||
|
||||
- if (s->revision == REV_11MPCORE) {
|
||||
+ if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
|
||||
/* Clear pending flags for both level and edge triggered interrupts.
|
||||
* Level triggered IRQs will be reasserted once they become inactive.
|
||||
*/
|
56
0301-vmstate-add-VMS_MUST_EXIST.patch
Normal file
56
0301-vmstate-add-VMS_MUST_EXIST.patch
Normal file
@ -0,0 +1,56 @@
|
||||
From: "Michael S. Tsirkin" <mst@redhat.com>
|
||||
Date: Thu, 3 Apr 2014 19:50:31 +0300
|
||||
Subject: [PATCH] vmstate: add VMS_MUST_EXIST
|
||||
|
||||
Can be used to verify a required field exists or validate
|
||||
state in some other way.
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
Signed-off-by: Juan Quintela <quintela@redhat.com>
|
||||
(cherry picked from commit 5bf81c8d63db0216a4d29dc87f9ce530bb791dd1)
|
||||
---
|
||||
include/migration/vmstate.h | 1 +
|
||||
savevm.c | 10 ++++++++++
|
||||
2 files changed, 11 insertions(+)
|
||||
|
||||
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
|
||||
index e5538c7..c1717c2 100644
|
||||
--- a/include/migration/vmstate.h
|
||||
+++ b/include/migration/vmstate.h
|
||||
@@ -100,6 +100,7 @@ enum VMStateFlags {
|
||||
VMS_MULTIPLY = 0x200, /* multiply "size" field by field_size */
|
||||
VMS_VARRAY_UINT8 = 0x400, /* Array with size in uint8_t field*/
|
||||
VMS_VARRAY_UINT32 = 0x800, /* Array with size in uint32_t field*/
|
||||
+ VMS_MUST_EXIST = 0x1000, /* Field must exist in input */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
diff --git a/savevm.c b/savevm.c
|
||||
index 03fc4d9..9f7f668 100644
|
||||
--- a/savevm.c
|
||||
+++ b/savevm.c
|
||||
@@ -1731,6 +1731,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
+ } else if (field->flags & VMS_MUST_EXIST) {
|
||||
+ fprintf(stderr, "Input validation failed: %s/%s\n",
|
||||
+ vmsd->name, field->name);
|
||||
+ return -1;
|
||||
}
|
||||
field++;
|
||||
}
|
||||
@@ -1791,6 +1795,12 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
|
||||
field->info->put(f, addr, size);
|
||||
}
|
||||
}
|
||||
+ } else {
|
||||
+ if (field->flags & VMS_MUST_EXIST) {
|
||||
+ fprintf(stderr, "Output state validation failed: %s/%s\n",
|
||||
+ vmsd->name, field->name);
|
||||
+ assert(!(field->flags & VMS_MUST_EXIST));
|
||||
+ }
|
||||
}
|
||||
field++;
|
||||
}
|
32
0302-vmstate-add-VMSTATE_VALIDATE.patch
Normal file
32
0302-vmstate-add-VMSTATE_VALIDATE.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From: "Michael S. Tsirkin" <mst@redhat.com>
|
||||
Date: Thu, 3 Apr 2014 19:50:35 +0300
|
||||
Subject: [PATCH] vmstate: add VMSTATE_VALIDATE
|
||||
|
||||
Validate state using VMS_ARRAY with num = 0 and VMS_MUST_EXIST
|
||||
|
||||
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Juan Quintela <quintela@redhat.com>
|
||||
(cherry picked from commit 4082f0889ba04678fc14816c53e1b9251ea9207e)
|
||||
---
|
||||
include/migration/vmstate.h | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
|
||||
index c1717c2..d5a63ce 100644
|
||||
--- a/include/migration/vmstate.h
|
||||
+++ b/include/migration/vmstate.h
|
||||
@@ -204,6 +204,14 @@ extern const VMStateInfo vmstate_info_bitmap;
|
||||
.offset = vmstate_offset_value(_state, _field, _type), \
|
||||
}
|
||||
|
||||
+/* Validate state using a boolean predicate. */
|
||||
+#define VMSTATE_VALIDATE(_name, _test) { \
|
||||
+ .name = (_name), \
|
||||
+ .field_exists = (_test), \
|
||||
+ .flags = VMS_ARRAY | VMS_MUST_EXIST, \
|
||||
+ .num = 0, /* 0 elements: no data, only run _test */ \
|
||||
+}
|
||||
+
|
||||
#define VMSTATE_POINTER(_field, _state, _version, _info, _type) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user