diff --git a/SOURCES/kvm-Allow-mismatched-virtio-config-len.patch b/SOURCES/kvm-Allow-mismatched-virtio-config-len.patch new file mode 100644 index 0000000..8e05351 --- /dev/null +++ b/SOURCES/kvm-Allow-mismatched-virtio-config-len.patch @@ -0,0 +1,73 @@ +From 88fd47b4c3a1a272d7e21ba0e7358e0a4e9ecf88 Mon Sep 17 00:00:00 2001 +From: Dr. David Alan Gilbert (git) +Date: Mon, 30 Jun 2014 11:10:01 +0200 +Subject: [PATCH] Allow mismatched virtio config-len + +RH-Author: Dr. David Alan Gilbert (git) +Message-id: <1404126601-23992-2-git-send-email-dgilbert@redhat.com> +Patchwork-id: 59407 +O-Subject: [RHEL-7.0.z qemu-kvm PATCH 1/1] Allow mismatched virtio config-len +Bugzilla: 1095782 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Juan Quintela +RH-Acked-by: Michael S. Tsirkin + +From: "Dr. David Alan Gilbert" + +Commit 'virtio: validate config_len on load' restricted config_len +loaded from the wire to match the config_len that the device had. + +Unfortunately, there are cases where this isn't true, the one +we found it on was the wce addition in virtio-blk. + +Allow mismatched config-lengths: + *) If the version on the wire is shorter then fine + *) If the version on the wire is longer, load what we have space + for and skip the rest. + +(This is mst@redhat.com's rework of what I originally posted) + +Signed-off-by: Dr. David Alan Gilbert +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 2f5732e9648fcddc8759a8fd25c0b41a38352be6) +--- + hw/virtio/virtio.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio.c | 16 +++++++++++----- + 1 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 44309c2..132b5af 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -886,12 +886,18 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) + return -1; + } + config_len = qemu_get_be32(f); +- if (config_len != vdev->config_len) { +- error_report("Unexpected config length 0x%x. Expected 0x%zx", +- config_len, vdev->config_len); +- return -1; ++ ++ /* ++ * There are cases where the incoming config can be bigger or smaller ++ * than what we have; so load what we have space for, and skip ++ * any excess that's in the stream. ++ */ ++ qemu_get_buffer(f, vdev->config, MIN(config_len, vdev->config_len)); ++ ++ while (config_len > vdev->config_len) { ++ qemu_get_byte(f); ++ config_len--; + } +- qemu_get_buffer(f, vdev->config, vdev->config_len); + + num = qemu_get_be32(f); + +-- +1.7.1 + diff --git a/SOURCES/kvm-Count-used-RAMBlock-pages-for-migration_dirty_pages.patch b/SOURCES/kvm-Count-used-RAMBlock-pages-for-migration_dirty_pages.patch new file mode 100644 index 0000000..f8afbca --- /dev/null +++ b/SOURCES/kvm-Count-used-RAMBlock-pages-for-migration_dirty_pages.patch @@ -0,0 +1,85 @@ +From 118493a7515526d7adc52b1ca1b667db1458e98c Mon Sep 17 00:00:00 2001 +From: Dr. David Alan Gilbert (git) +Date: Thu, 8 May 2014 11:27:33 +0200 +Subject: [PATCH 21/30] Count used RAMBlock pages for migration_dirty_pages + +RH-Author: Dr. David Alan Gilbert (git) +Message-id: <1399548453-9181-2-git-send-email-dgilbert@redhat.com> +Patchwork-id: 58746 +O-Subject: [RHEL7.1/RHEL7.0.z qemu-kvm PATCH 1/1] Count used RAMBlock pages for migration_dirty_pages +Bugzilla: 1110189 +RH-Acked-by: Juan Quintela +RH-Acked-by: Markus Armbruster +RH-Acked-by: Amit Shah + +From: "Dr. David Alan Gilbert" + +This is a fix for a bug triggered by a migration after hot unplugging +a few virtio-net NICs, that caused migration never to converge, because +'migration_dirty_pages' is incorrectly initialised. + +'migration_dirty_pages' is used as a tally of the number of outstanding +dirty pages, to give the migration code an idea of how much more data +will need to be transferred, and thus whether it can end the iterative +phase. + +It was initialised to the total size of the RAMBlock address space, +however hotunplug can leave this space sparse, and hence +migration_dirty_pages ended up too large. + +Signed-off-by: Dr. David Alan Gilbert + +Signed-off-by: Juan Quintela +(cherry picked from commit e30d1d8c7195848abb28a8c734a82b845b8b456a) +--- + arch_init.c | 21 +++++++++++++++++---- + 1 file changed, 17 insertions(+), 4 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + arch_init.c | 21 +++++++++++++++++---- + 1 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/arch_init.c b/arch_init.c +index 22f7def..b88d686 100644 +--- a/arch_init.c ++++ b/arch_init.c +@@ -728,11 +728,8 @@ static void reset_ram_globals(void) + static int ram_save_setup(QEMUFile *f, void *opaque) + { + RAMBlock *block; +- int64_t ram_pages = last_ram_offset() >> TARGET_PAGE_BITS; ++ int64_t ram_bitmap_pages; /* Size of bitmap in pages, including gaps */ + +- migration_bitmap = bitmap_new(ram_pages); +- bitmap_set(migration_bitmap, 0, ram_pages); +- migration_dirty_pages = ram_pages; + mig_throttle_on = false; + dirty_rate_high_cnt = 0; + +@@ -771,6 +768,22 @@ static int ram_save_setup(QEMUFile *f, void *opaque) + bytes_transferred = 0; + reset_ram_globals(); + ++ ram_bitmap_pages = last_ram_offset() >> TARGET_PAGE_BITS; ++ migration_bitmap = bitmap_new(ram_bitmap_pages); ++ bitmap_set(migration_bitmap, 0, ram_bitmap_pages); ++ ++ /* ++ * Count the total number of pages used by ram blocks not including any ++ * gaps due to alignment or unplugs. ++ */ ++ migration_dirty_pages = 0; ++ QTAILQ_FOREACH(block, &ram_list.blocks, next) { ++ uint64_t block_pages; ++ ++ block_pages = block->length >> TARGET_PAGE_BITS; ++ migration_dirty_pages += block_pages; ++ } ++ + memory_global_dirty_log_start(); + migration_bitmap_sync(); + qemu_mutex_unlock_iothread(); +-- +1.7.1 + diff --git a/SOURCES/kvm-Init-the-XBZRLE.lock-in-ram_mig_init.patch b/SOURCES/kvm-Init-the-XBZRLE.lock-in-ram_mig_init.patch new file mode 100644 index 0000000..2cb8c51 --- /dev/null +++ b/SOURCES/kvm-Init-the-XBZRLE.lock-in-ram_mig_init.patch @@ -0,0 +1,170 @@ +From ac978ade92aa12ae6c700b8be85a10355f728c78 Mon Sep 17 00:00:00 2001 +From: Dr. David Alan Gilbert (git) +Date: Thu, 8 May 2014 10:58:41 +0200 +Subject: [PATCH 19/30] Init the XBZRLE.lock in ram_mig_init + +RH-Author: Dr. David Alan Gilbert (git) +Message-id: <1399546722-6350-4-git-send-email-dgilbert@redhat.com> +Patchwork-id: 58743 +O-Subject: [RHEL7.1/RHEL7.0.z qemu-kvm PATCH 3/4] Init the XBZRLE.lock in ram_mig_init +Bugzilla: 1110191 +RH-Acked-by: Juan Quintela +RH-Acked-by: Markus Armbruster +RH-Acked-by: Amit Shah + +From: "Dr. David Alan Gilbert" + +Initialising the XBZRLE.lock earlier simplifies the lock use. + +Based on Markus's patch in: +http://lists.gnu.org/archive/html/qemu-devel/2014-03/msg03879.html + +Signed-off-by: Dr. David Alan Gilbert +Reviewed-by: Gonglei +Reviewed-by: Markus Armbruster +Signed-off-by: Juan Quintela +(cherry picked from commit d97326eec2ca1313eaf0b5cffd69af5663b5af5d) +--- + arch_init.c | 61 +++++++++++++++++++++++++++++++------------------------------ + 1 file changed, 31 insertions(+), 30 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + arch_init.c | 61 ++++++++++++++++++++++++++++++----------------------------- + 1 files changed, 31 insertions(+), 30 deletions(-) + +diff --git a/arch_init.c b/arch_init.c +index 37c9f6d..80e48f2 100644 +--- a/arch_init.c ++++ b/arch_init.c +@@ -45,6 +45,7 @@ + #include "hw/audio/pcspk.h" + #include "migration/page_cache.h" + #include "qemu/config-file.h" ++#include "qemu/error-report.h" + #include "qmp-commands.h" + #include "trace.h" + #include "exec/cpu-all.h" +@@ -167,11 +168,8 @@ static struct { + /* Cache for XBZRLE, Protected by lock. */ + PageCache *cache; + QemuMutex lock; +-} XBZRLE = { +- .encoded_buf = NULL, +- .current_buf = NULL, +- .cache = NULL, +-}; ++} XBZRLE; ++ + /* buffer used for XBZRLE decoding */ + static uint8_t *xbzrle_decoded_buf; + +@@ -187,41 +185,44 @@ static void XBZRLE_cache_unlock(void) + qemu_mutex_unlock(&XBZRLE.lock); + } + ++/* ++ * called from qmp_migrate_set_cache_size in main thread, possibly while ++ * a migration is in progress. ++ * A running migration maybe using the cache and might finish during this ++ * call, hence changes to the cache are protected by XBZRLE.lock(). ++ */ + int64_t xbzrle_cache_resize(int64_t new_size) + { +- PageCache *new_cache, *cache_to_free; ++ PageCache *new_cache; ++ int64_t ret; + + if (new_size < TARGET_PAGE_SIZE) { + return -1; + } + +- /* no need to lock, the current thread holds qemu big lock */ ++ XBZRLE_cache_lock(); ++ + if (XBZRLE.cache != NULL) { +- /* check XBZRLE.cache again later */ + if (pow2floor(new_size) == migrate_xbzrle_cache_size()) { +- return pow2floor(new_size); ++ goto out_new_size; + } + new_cache = cache_init(new_size / TARGET_PAGE_SIZE, + TARGET_PAGE_SIZE); + if (!new_cache) { +- DPRINTF("Error creating cache\n"); +- return -1; +- } +- +- XBZRLE_cache_lock(); +- /* the XBZRLE.cache may have be destroyed, check it again */ +- if (XBZRLE.cache != NULL) { +- cache_to_free = XBZRLE.cache; +- XBZRLE.cache = new_cache; +- } else { +- cache_to_free = new_cache; ++ error_report("Error creating cache"); ++ ret = -1; ++ goto out; + } +- XBZRLE_cache_unlock(); + +- cache_fini(cache_to_free); ++ cache_fini(XBZRLE.cache); ++ XBZRLE.cache = new_cache; + } + +- return pow2floor(new_size); ++out_new_size: ++ ret = pow2floor(new_size); ++out: ++ XBZRLE_cache_unlock(); ++ return ret; + } + + /* accounting for migration statistics */ +@@ -735,28 +736,27 @@ static int ram_save_setup(QEMUFile *f, void *opaque) + dirty_rate_high_cnt = 0; + + if (migrate_use_xbzrle()) { +- qemu_mutex_lock_iothread(); ++ XBZRLE_cache_lock(); + XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() / + TARGET_PAGE_SIZE, + TARGET_PAGE_SIZE); + if (!XBZRLE.cache) { +- qemu_mutex_unlock_iothread(); +- DPRINTF("Error creating cache\n"); ++ XBZRLE_cache_unlock(); ++ error_report("Error creating cache"); + return -1; + } +- qemu_mutex_init(&XBZRLE.lock); +- qemu_mutex_unlock_iothread(); ++ XBZRLE_cache_unlock(); + + /* We prefer not to abort if there is no memory */ + XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE); + if (!XBZRLE.encoded_buf) { +- DPRINTF("Error allocating encoded_buf\n"); ++ error_report("Error allocating encoded_buf"); + return -1; + } + + XBZRLE.current_buf = g_try_malloc(TARGET_PAGE_SIZE); + if (!XBZRLE.current_buf) { +- DPRINTF("Error allocating current_buf\n"); ++ error_report("Error allocating current_buf"); + g_free(XBZRLE.encoded_buf); + XBZRLE.encoded_buf = NULL; + return -1; +@@ -1110,6 +1110,7 @@ static SaveVMHandlers savevm_ram_handlers = { + + void ram_mig_init(void) + { ++ qemu_mutex_init(&XBZRLE.lock); + register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, NULL); + } + +-- +1.7.1 + diff --git a/SOURCES/kvm-Provide-init-function-for-ram-migration.patch b/SOURCES/kvm-Provide-init-function-for-ram-migration.patch new file mode 100644 index 0000000..d94b29f --- /dev/null +++ b/SOURCES/kvm-Provide-init-function-for-ram-migration.patch @@ -0,0 +1,113 @@ +From 8928f6a2f77e167b7602c3f3bb071641134e544e Mon Sep 17 00:00:00 2001 +From: Dr. David Alan Gilbert (git) +Date: Thu, 8 May 2014 10:58:40 +0200 +Subject: [PATCH 18/30] Provide init function for ram migration + +RH-Author: Dr. David Alan Gilbert (git) +Message-id: <1399546722-6350-3-git-send-email-dgilbert@redhat.com> +Patchwork-id: 58742 +O-Subject: [RHEL7.1/RHEL7.0.z qemu-kvm PATCH 2/4] Provide init function for ram migration +Bugzilla: 1110191 +RH-Acked-by: Juan Quintela +RH-Acked-by: Markus Armbruster +RH-Acked-by: Amit Shah + +From: "Dr. David Alan Gilbert" + +Provide ram_mig_init (like blk_mig_init) for vl.c to initialise stuff +to do with ram migration (currently in arch_init.c). + +Signed-off-by: Dr. David Alan Gilbert +Reviewed-by: Gonglei +Reviewed-by: Markus Armbruster +Signed-off-by: Juan Quintela +(cherry picked from commit 0d6ab3ab9149767eba192ec5ad659fd34e55a291) +--- + arch_init.c | 7 ++++++- + include/migration/migration.h | 2 -- + include/sysemu/arch_init.h | 1 + + vl.c | 3 +-- + 4 files changed, 8 insertions(+), 5 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + arch_init.c | 7 ++++++- + include/migration/migration.h | 2 -- + include/sysemu/arch_init.h | 1 + + vl.c | 3 +-- + 4 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/arch_init.c b/arch_init.c +index 8641afa..37c9f6d 100644 +--- a/arch_init.c ++++ b/arch_init.c +@@ -1099,7 +1099,7 @@ done: + return ret; + } + +-SaveVMHandlers savevm_ram_handlers = { ++static SaveVMHandlers savevm_ram_handlers = { + .save_live_setup = ram_save_setup, + .save_live_iterate = ram_save_iterate, + .save_live_complete = ram_save_complete, +@@ -1108,6 +1108,11 @@ SaveVMHandlers savevm_ram_handlers = { + .cancel = ram_migration_cancel, + }; + ++void ram_mig_init(void) ++{ ++ register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, NULL); ++} ++ + struct soundhw { + const char *name; + const char *descr; +diff --git a/include/migration/migration.h b/include/migration/migration.h +index 9314511..c99a67c 100644 +--- a/include/migration/migration.h ++++ b/include/migration/migration.h +@@ -102,8 +102,6 @@ void free_xbzrle_decoded_buf(void); + + void acct_update_position(QEMUFile *f, size_t size, bool zero); + +-extern SaveVMHandlers savevm_ram_handlers; +- + uint64_t dup_mig_bytes_transferred(void); + uint64_t dup_mig_pages_transferred(void); + uint64_t skipped_mig_bytes_transferred(void); +diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h +index be71bca..182d48d 100644 +--- a/include/sysemu/arch_init.h ++++ b/include/sysemu/arch_init.h +@@ -29,6 +29,7 @@ extern const uint32_t arch_type; + void select_soundhw(const char *optarg); + void do_acpitable_option(const QemuOpts *opts); + void do_smbios_option(QemuOpts *opts); ++void ram_mig_init(void); + void cpudef_init(void); + void audio_init(void); + int tcg_available(void); +diff --git a/vl.c b/vl.c +index 51300e7..6ff06cc 100644 +--- a/vl.c ++++ b/vl.c +@@ -4133,6 +4133,7 @@ int main(int argc, char **argv, char **envp) + cpu_exec_init_all(); + + blk_mig_init(); ++ ram_mig_init(); + + /* open the virtual block devices */ + if (snapshot) +@@ -4147,8 +4148,6 @@ int main(int argc, char **argv, char **envp) + default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS); + default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS); + +- register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, NULL); +- + if (nb_numa_nodes > 0) { + int i; + +-- +1.7.1 + diff --git a/SOURCES/kvm-XBZRLE-Fix-one-XBZRLE-corruption-issues.patch b/SOURCES/kvm-XBZRLE-Fix-one-XBZRLE-corruption-issues.patch new file mode 100644 index 0000000..3130627 --- /dev/null +++ b/SOURCES/kvm-XBZRLE-Fix-one-XBZRLE-corruption-issues.patch @@ -0,0 +1,106 @@ +From a00bde30c0730d3434d9f4556a9cb119f3f8d68d Mon Sep 17 00:00:00 2001 +From: Dr. David Alan Gilbert (git) +Date: Thu, 8 May 2014 10:58:42 +0200 +Subject: [PATCH 20/30] XBZRLE: Fix one XBZRLE corruption issues + +RH-Author: Dr. David Alan Gilbert (git) +Message-id: <1399546722-6350-5-git-send-email-dgilbert@redhat.com> +Patchwork-id: 58744 +O-Subject: [RHEL7.1/RHEL7.0.z qemu-kvm PATCH 4/4] XBZRLE: Fix one XBZRLE corruption issues +Bugzilla: 1110191 +RH-Acked-by: Juan Quintela +RH-Acked-by: Markus Armbruster +RH-Acked-by: Amit Shah + +From: ChenLiang + +The page may not be inserted into cache after executing save_xbzrle_page. +In case of failure to insert, the original page should be sent rather +than the page in the cache. + +Signed-off-by: ChenLiang +Signed-off-by: Gonglei +Reviewed-by: Juan Quintela +Signed-off-by: Juan Quintela +(cherry picked from commit 1534ee93cc6be992c05577886b24bd44c37ecff6) +--- + arch_init.c | 25 +++++++++++++------------ + 1 file changed, 13 insertions(+), 12 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + arch_init.c | 25 +++++++++++++------------ + 1 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/arch_init.c b/arch_init.c +index 80e48f2..22f7def 100644 +--- a/arch_init.c ++++ b/arch_init.c +@@ -341,7 +341,7 @@ static void xbzrle_cache_zero_page(ram_addr_t current_addr) + + #define ENCODING_FLAG_XBZRLE 0x1 + +-static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, ++static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data, + ram_addr_t current_addr, RAMBlock *block, + ram_addr_t offset, int cont, bool last_stage) + { +@@ -349,19 +349,23 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, + uint8_t *prev_cached_page; + + if (!cache_is_cached(XBZRLE.cache, current_addr)) { ++ acct_info.xbzrle_cache_miss++; + if (!last_stage) { +- if (cache_insert(XBZRLE.cache, current_addr, current_data) == -1) { ++ if (cache_insert(XBZRLE.cache, current_addr, *current_data) == -1) { + return -1; ++ } else { ++ /* update *current_data when the page has been ++ inserted into cache */ ++ *current_data = get_cached_data(XBZRLE.cache, current_addr); + } + } +- acct_info.xbzrle_cache_miss++; + return -1; + } + + prev_cached_page = get_cached_data(XBZRLE.cache, current_addr); + + /* save current buffer into memory */ +- memcpy(XBZRLE.current_buf, current_data, TARGET_PAGE_SIZE); ++ memcpy(XBZRLE.current_buf, *current_data, TARGET_PAGE_SIZE); + + /* XBZRLE encoding (if there is no overflow) */ + encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf, +@@ -374,7 +378,10 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, + DPRINTF("Overflow\n"); + acct_info.xbzrle_overflows++; + /* update data in the cache */ +- memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE); ++ if (!last_stage) { ++ memcpy(prev_cached_page, *current_data, TARGET_PAGE_SIZE); ++ *current_data = prev_cached_page; ++ } + return -1; + } + +@@ -599,15 +606,9 @@ static int ram_save_block(QEMUFile *f, bool last_stage) + */ + xbzrle_cache_zero_page(current_addr); + } else if (!ram_bulk_stage && migrate_use_xbzrle()) { +- bytes_sent = save_xbzrle_page(f, p, current_addr, block, ++ bytes_sent = save_xbzrle_page(f, &p, current_addr, block, + offset, cont, last_stage); + if (!last_stage) { +- /* We must send exactly what's in the xbzrle cache +- * even if the page wasn't xbzrle compressed, so that +- * it's right next time. +- */ +- p = get_cached_data(XBZRLE.cache, current_addr); +- + /* Can't send this cached data async, since the cache page + * might get updated before it gets to the wire + */ +-- +1.7.1 + diff --git a/SOURCES/kvm-XBZRLE-Fix-qemu-crash-when-resize-the-xbzrle-cache.patch b/SOURCES/kvm-XBZRLE-Fix-qemu-crash-when-resize-the-xbzrle-cache.patch new file mode 100644 index 0000000..261ad8f --- /dev/null +++ b/SOURCES/kvm-XBZRLE-Fix-qemu-crash-when-resize-the-xbzrle-cache.patch @@ -0,0 +1,158 @@ +From e30b7a4a8810a49a1b8a915a9ed174b9b254c999 Mon Sep 17 00:00:00 2001 +From: Dr. David Alan Gilbert (git) +Date: Thu, 8 May 2014 10:58:39 +0200 +Subject: [PATCH 17/30] XBZRLE: Fix qemu crash when resize the xbzrle cache + +RH-Author: Dr. David Alan Gilbert (git) +Message-id: <1399546722-6350-2-git-send-email-dgilbert@redhat.com> +Patchwork-id: 58741 +O-Subject: [RHEL7.1/RHEL7.0.z qemu-kvm PATCH 1/4] XBZRLE: Fix qemu crash when resize the xbzrle cache +Bugzilla: 1110191 +RH-Acked-by: Juan Quintela +RH-Acked-by: Markus Armbruster +RH-Acked-by: Amit Shah + +From: Gonglei + +Resizing the xbzrle cache during migration causes qemu-crash, +because the main-thread and migration-thread modify the xbzrle +cache size concurrently without lock-protection. + +Signed-off-by: ChenLiang +Signed-off-by: Gonglei +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Juan Quintela +(cherry picked from commit fd8cec932c2ddc687e2da954978954b46a926f90) +--- + arch_init.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 49 insertions(+), 3 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + arch_init.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 files changed, 49 insertions(+), 3 deletions(-) + +diff --git a/arch_init.c b/arch_init.c +index f5d521a..8641afa 100644 +--- a/arch_init.c ++++ b/arch_init.c +@@ -164,8 +164,9 @@ static struct { + uint8_t *encoded_buf; + /* buffer for storing page content */ + uint8_t *current_buf; +- /* Cache for XBZRLE */ ++ /* Cache for XBZRLE, Protected by lock. */ + PageCache *cache; ++ QemuMutex lock; + } XBZRLE = { + .encoded_buf = NULL, + .current_buf = NULL, +@@ -174,16 +175,52 @@ static struct { + /* buffer used for XBZRLE decoding */ + static uint8_t *xbzrle_decoded_buf; + ++static void XBZRLE_cache_lock(void) ++{ ++ if (migrate_use_xbzrle()) ++ qemu_mutex_lock(&XBZRLE.lock); ++} ++ ++static void XBZRLE_cache_unlock(void) ++{ ++ if (migrate_use_xbzrle()) ++ qemu_mutex_unlock(&XBZRLE.lock); ++} ++ + int64_t xbzrle_cache_resize(int64_t new_size) + { ++ PageCache *new_cache, *cache_to_free; ++ + if (new_size < TARGET_PAGE_SIZE) { + return -1; + } + ++ /* no need to lock, the current thread holds qemu big lock */ + if (XBZRLE.cache != NULL) { +- return cache_resize(XBZRLE.cache, new_size / TARGET_PAGE_SIZE) * +- TARGET_PAGE_SIZE; ++ /* check XBZRLE.cache again later */ ++ if (pow2floor(new_size) == migrate_xbzrle_cache_size()) { ++ return pow2floor(new_size); ++ } ++ new_cache = cache_init(new_size / TARGET_PAGE_SIZE, ++ TARGET_PAGE_SIZE); ++ if (!new_cache) { ++ DPRINTF("Error creating cache\n"); ++ return -1; ++ } ++ ++ XBZRLE_cache_lock(); ++ /* the XBZRLE.cache may have be destroyed, check it again */ ++ if (XBZRLE.cache != NULL) { ++ cache_to_free = XBZRLE.cache; ++ XBZRLE.cache = new_cache; ++ } else { ++ cache_to_free = new_cache; ++ } ++ XBZRLE_cache_unlock(); ++ ++ cache_fini(cache_to_free); + } ++ + return pow2floor(new_size); + } + +@@ -539,6 +576,8 @@ static int ram_save_block(QEMUFile *f, bool last_stage) + ret = ram_control_save_page(f, block->offset, + offset, TARGET_PAGE_SIZE, &bytes_sent); + ++ XBZRLE_cache_lock(); ++ + current_addr = block->offset + offset; + if (ret != RAM_SAVE_CONTROL_NOT_SUPP) { + if (ret != RAM_SAVE_CONTROL_DELAYED) { +@@ -587,6 +626,7 @@ static int ram_save_block(QEMUFile *f, bool last_stage) + acct_info.norm_pages++; + } + ++ XBZRLE_cache_unlock(); + /* if page is unmodified, continue to the next */ + if (bytes_sent > 0) { + last_sent_block = block; +@@ -654,6 +694,7 @@ static void migration_end(void) + migration_bitmap = NULL; + } + ++ XBZRLE_cache_lock(); + if (XBZRLE.cache) { + cache_fini(XBZRLE.cache); + g_free(XBZRLE.cache); +@@ -663,6 +704,7 @@ static void migration_end(void) + XBZRLE.encoded_buf = NULL; + XBZRLE.current_buf = NULL; + } ++ XBZRLE_cache_unlock(); + } + + static void ram_migration_cancel(void *opaque) +@@ -693,13 +735,17 @@ static int ram_save_setup(QEMUFile *f, void *opaque) + dirty_rate_high_cnt = 0; + + if (migrate_use_xbzrle()) { ++ qemu_mutex_lock_iothread(); + XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() / + TARGET_PAGE_SIZE, + TARGET_PAGE_SIZE); + if (!XBZRLE.cache) { ++ qemu_mutex_unlock_iothread(); + DPRINTF("Error creating cache\n"); + return -1; + } ++ qemu_mutex_init(&XBZRLE.lock); ++ qemu_mutex_unlock_iothread(); + + /* We prefer not to abort if there is no memory */ + XBZRLE.encoded_buf = g_try_malloc0(TARGET_PAGE_SIZE); +-- +1.7.1 + diff --git a/SOURCES/kvm-char-restore-read-callback-on-a-reattached-hotplug-c.patch b/SOURCES/kvm-char-restore-read-callback-on-a-reattached-hotplug-c.patch new file mode 100644 index 0000000..e1c6c3d --- /dev/null +++ b/SOURCES/kvm-char-restore-read-callback-on-a-reattached-hotplug-c.patch @@ -0,0 +1,91 @@ +From 3322e336871252ea0ff22920cfb13d302b07bd11 Mon Sep 17 00:00:00 2001 +From: Gal Hammer +Date: Sun, 16 Mar 2014 09:57:09 +0100 +Subject: [PATCH 28/30] char: restore read callback on a reattached (hotplug) chardev + +RH-Author: Gal Hammer +Message-id: <1394963829-5384-1-git-send-email-ghammer@redhat.com> +Patchwork-id: 58105 +O-Subject: [RHEL-7.0 qemu-kvm PATCH] char: restore read callback on a reattached (hotplug) chardev +Bugzilla: 1110219 +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Amit Shah +RH-Acked-by: Amos Kong + +Brew: https://brewweb.devel.redhat.com/taskinfo?taskID=7207613 +Upstream: commit ac1b84dd1e020648db82a99260891aa982d1142c + +Fix a bug that was introduced in commit 386a5a1e. A removal of a device +set the chr handlers to NULL. However when the device is plugged back, +its read callback is not restored so data can't be transferred from the +host to the guest (e.g. via the virtio-serial port). + +Signed-off-by: Gal Hammer +Signed-off-by: Gerd Hoffmann +--- + qemu-char.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + qemu-char.c | 17 +++++++++++++++-- + 1 files changed, 15 insertions(+), 2 deletions(-) + +diff --git a/qemu-char.c b/qemu-char.c +index 983f686..930f3d4 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -215,7 +215,7 @@ void qemu_chr_add_handlers(CharDriverState *s, + s->chr_read = fd_read; + s->chr_event = fd_event; + s->handler_opaque = opaque; +- if (s->chr_update_read_handler) ++ if (fe_open && s->chr_update_read_handler) + s->chr_update_read_handler(s); + + if (!s->explicit_fe_open) { +@@ -1140,13 +1140,14 @@ static void pty_chr_state(CharDriverState *chr, int connected) + if (!s->connected) { + s->connected = 1; + qemu_chr_be_generic_open(chr); ++ } ++ if (!chr->fd_in_tag) { + chr->fd_in_tag = io_add_watch_poll(s->fd, pty_chr_read_poll, + pty_chr_read, chr); + } + } + } + +- + static void pty_chr_close(struct CharDriverState *chr) + { + PtyCharDriver *s = chr->opaque; +@@ -2514,6 +2515,17 @@ static void tcp_chr_connect(void *opaque) + qemu_chr_be_generic_open(chr); + } + ++static void tcp_chr_update_read_handler(CharDriverState *chr) ++{ ++ TCPCharDriver *s = chr->opaque; ++ ++ remove_fd_in_watch(chr); ++ if (s->chan) { ++ chr->fd_in_tag = io_add_watch_poll(s->chan, tcp_chr_read_poll, ++ tcp_chr_read, chr); ++ } ++} ++ + #define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c; + static void tcp_chr_telnet_init(int fd) + { +@@ -2669,6 +2681,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, + chr->get_msgfd = tcp_get_msgfd; + chr->chr_add_client = tcp_chr_add_client; + chr->chr_add_watch = tcp_chr_add_watch; ++ chr->chr_update_read_handler = tcp_chr_update_read_handler; + /* be isn't opened until we get a connection */ + chr->explicit_be_open = true; + +-- +1.7.1 + diff --git a/SOURCES/kvm-hpet-fix-buffer-overrun-on-invalid-state-load.patch b/SOURCES/kvm-hpet-fix-buffer-overrun-on-invalid-state-load.patch new file mode 100644 index 0000000..8c36dc8 --- /dev/null +++ b/SOURCES/kvm-hpet-fix-buffer-overrun-on-invalid-state-load.patch @@ -0,0 +1,73 @@ +From 53cea58f1e2ed721356a705ec22751083f9e23b5 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:24:37 +0200 +Subject: [PATCH 12/30] hpet: fix buffer overrun on invalid state load + +RH-Author: Michael S. Tsirkin +Message-id: <1400055633-6261-4-git-send-email-mst@redhat.com> +Patchwork-id: 58851 +O-Subject: [PATCH qemu-kvm RHEL7.0.z 4/5] hpet: fix buffer overrun on invalid state load +Bugzilla: 1095706 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Marcel Apfelbaum +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Juan Quintela + +CVE-2013-4527 hw/timer/hpet.c buffer overrun + +hpet is a VARRAY with a uint8 size but static array of 32 + +To fix, make sure num_timers is valid using VMSTATE_VALID hook. + +Reported-by: Anthony Liguori +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Juan Quintela +(cherry picked from commit 3f1c49e2136fa08ab1ef3183fd55def308829584) + +Tested: lightly on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Bugzilla:1095706 +--- + hw/timer/hpet.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + hw/timer/hpet.c | 13 +++++++++++++ + 1 files changed, 13 insertions(+), 0 deletions(-) + +diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c +index dd486a1..54ffa49 100644 +--- a/hw/timer/hpet.c ++++ b/hw/timer/hpet.c +@@ -222,6 +222,18 @@ static int hpet_pre_load(void *opaque) + return 0; + } + ++static bool hpet_validate_num_timers(void *opaque, int version_id) ++{ ++ HPETState *s = opaque; ++ ++ if (s->num_timers < HPET_MIN_TIMERS) { ++ return false; ++ } else if (s->num_timers > HPET_MAX_TIMERS) { ++ return false; ++ } ++ return true; ++} ++ + static int hpet_post_load(void *opaque, int version_id) + { + HPETState *s = opaque; +@@ -290,6 +302,7 @@ static const VMStateDescription vmstate_hpet = { + VMSTATE_UINT64(isr, HPETState), + VMSTATE_UINT64(hpet_counter, HPETState), + VMSTATE_UINT8_V(num_timers, HPETState, 2), ++ VMSTATE_VALIDATE("num_timers in range", hpet_validate_num_timers), + VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0, + vmstate_hpet_timer, HPETTimer), + VMSTATE_END_OF_LIST() +-- +1.7.1 + diff --git a/SOURCES/kvm-hw-pci-pcie_aer.c-fix-buffer-overruns-on-invalid-sta.patch b/SOURCES/kvm-hw-pci-pcie_aer.c-fix-buffer-overruns-on-invalid-sta.patch new file mode 100644 index 0000000..a9d836a --- /dev/null +++ b/SOURCES/kvm-hw-pci-pcie_aer.c-fix-buffer-overruns-on-invalid-sta.patch @@ -0,0 +1,77 @@ +From ed30bd1d0e45463cc48aeb839b4ae3c65009ce79 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:24:43 +0200 +Subject: [PATCH 13/30] hw/pci/pcie_aer.c: fix buffer overruns on invalid state load + +RH-Author: Michael S. Tsirkin +Message-id: <1400055633-6261-5-git-send-email-mst@redhat.com> +Patchwork-id: 58852 +O-Subject: [PATCH qemu-kvm RHEL7.0.z 5/5] hw/pci/pcie_aer.c: fix buffer overruns on invalid state load +Bugzilla: 1095714 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Marcel Apfelbaum +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Juan Quintela + +4) CVE-2013-4529 +hw/pci/pcie_aer.c pcie aer log can overrun the buffer if log_num is + too large + +There are two issues in this file: +1. log_max from remote can be larger than on local +then buffer will overrun with data coming from state file. +2. log_num can be larger then we get data corruption +again with an overflow but not adversary controlled. + +Fix both issues. + +Reported-by: Anthony Liguori +Reported-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Juan Quintela +(cherry picked from commit 5f691ff91d323b6f97c6600405a7f9dc115a0ad1) + +Tested: lightly on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Bugzilla:1095714 +--- + hw/pci/pcie_aer.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +Signed-off-by: Miroslav Rezanina +--- + hw/pci/pcie_aer.c | 10 +++++++++- + 1 files changed, 9 insertions(+), 1 deletions(-) + +diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c +index 1ce72ce..ab5c9c6 100644 +--- a/hw/pci/pcie_aer.c ++++ b/hw/pci/pcie_aer.c +@@ -795,6 +795,13 @@ static const VMStateDescription vmstate_pcie_aer_err = { + } + }; + ++static bool pcie_aer_state_log_num_valid(void *opaque, int version_id) ++{ ++ PCIEAERLog *s = opaque; ++ ++ return s->log_num <= s->log_max; ++} ++ + const VMStateDescription vmstate_pcie_aer_log = { + .name = "PCIE_AER_ERROR_LOG", + .version_id = 1, +@@ -802,7 +809,8 @@ const VMStateDescription vmstate_pcie_aer_log = { + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT16(log_num, PCIEAERLog), +- VMSTATE_UINT16(log_max, PCIEAERLog), ++ VMSTATE_UINT16_EQUAL(log_max, PCIEAERLog), ++ VMSTATE_VALIDATE("log_num <= log_max", pcie_aer_state_log_num_valid), + VMSTATE_STRUCT_VARRAY_POINTER_UINT16(log, PCIEAERLog, log_num, + vmstate_pcie_aer_err, PCIEAERErr), + VMSTATE_END_OF_LIST() +-- +1.7.1 + diff --git a/SOURCES/kvm-qcow-correctly-propagate-errors.patch b/SOURCES/kvm-qcow-correctly-propagate-errors.patch new file mode 100644 index 0000000..40f9e9a --- /dev/null +++ b/SOURCES/kvm-qcow-correctly-propagate-errors.patch @@ -0,0 +1,78 @@ +From 8e046eb446573101d92b41a88ebe1066a42d653c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 2 Jun 2014 13:54:43 +0200 +Subject: [PATCH 22/30] qcow: correctly propagate errors + +RH-Author: Kevin Wolf +Message-id: <1401717288-3918-2-git-send-email-kwolf@redhat.com> +Patchwork-id: 59096 +O-Subject: [RHEL-7.1/7.0.z qemu-kvm PATCH 1/6] qcow: correctly propagate errors +Bugzilla: 1097229 +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Stefan Hajnoczi + +From: Paolo Bonzini + +Signed-off-by: Paolo Bonzini +Reviewed-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit b6d5066d32f9e6c3d7508c1af9ae78327a927120) +Signed-off-by: Kevin Wolf +--- + block/qcow.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + block/qcow.c | 12 ++++++------ + 1 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/block/qcow.c b/block/qcow.c +index c470e05..b57b900 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -119,17 +119,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, + if (header.version != QCOW_VERSION) { + char version[64]; + snprintf(version, sizeof(version), "QCOW version %d", header.version); +- qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, +- bs->device_name, "qcow", version); ++ error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, ++ bs->device_name, "qcow", version); + ret = -ENOTSUP; + goto fail; + } + + if (header.size <= 1 || header.cluster_bits < 9) { ++ error_setg(errp, "invalid value in qcow header"); + ret = -EINVAL; + goto fail; + } + if (header.crypt_method > QCOW_CRYPT_AES) { ++ error_setg(errp, "invalid encryption method in qcow header"); + ret = -EINVAL; + goto fail; + } +@@ -686,15 +688,13 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options, + + ret = bdrv_create_file(filename, options, &local_err); + if (ret < 0) { +- qerror_report_err(local_err); +- error_free(local_err); ++ error_propagate(errp, local_err); + return ret; + } + + ret = bdrv_file_open(&qcow_bs, filename, NULL, BDRV_O_RDWR, &local_err); + if (ret < 0) { +- qerror_report_err(local_err); +- error_free(local_err); ++ error_propagate(errp, local_err); + return ret; + } + +-- +1.7.1 + diff --git a/SOURCES/kvm-qcow1-Check-maximum-cluster-size.patch b/SOURCES/kvm-qcow1-Check-maximum-cluster-size.patch new file mode 100644 index 0000000..e006f39 --- /dev/null +++ b/SOURCES/kvm-qcow1-Check-maximum-cluster-size.patch @@ -0,0 +1,175 @@ +From 0867b2aac8b789d492af127b12437e526774b7cf Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 2 Jun 2014 13:54:45 +0200 +Subject: [PATCH 24/30] qcow1: Check maximum cluster size + +RH-Author: Kevin Wolf +Message-id: <1401717288-3918-4-git-send-email-kwolf@redhat.com> +Patchwork-id: 59098 +O-Subject: [RHEL-7.1/7.0.z qemu-kvm PATCH 3/6] qcow1: Check maximum cluster size +Bugzilla: 1097229 +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Stefan Hajnoczi + +Huge values for header.cluster_bits cause unbounded allocations (e.g. +for s->cluster_cache) and crash qemu this way. Less huge values may +survive those allocations, but can cause integer overflows later on. + +The only cluster sizes that qemu can create are 4k (for standalone +images) and 512 (for images with backing files), so we can limit it +to 64k. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Benoit Canet + +Conflicts: + tests/qemu-iotests/group + +Signed-off-by: Kevin Wolf +(cherry picked from commit 7159a45b2bf2dcb9f49f1e27d1d3d135a0247a2f) +--- + block/qcow.c | 10 ++++++-- + tests/qemu-iotests/092 | 63 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/092.out | 13 ++++++++++ + tests/qemu-iotests/group | 1 + + 4 files changed, 85 insertions(+), 2 deletions(-) + create mode 100755 tests/qemu-iotests/092 + create mode 100644 tests/qemu-iotests/092.out + +Signed-off-by: Miroslav Rezanina +--- + block/qcow.c | 10 +++++- + tests/qemu-iotests/092 | 63 ++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/092.out | 13 +++++++++ + tests/qemu-iotests/group | 1 + + 4 files changed, 85 insertions(+), 2 deletions(-) + create mode 100755 tests/qemu-iotests/092 + create mode 100644 tests/qemu-iotests/092.out + +diff --git a/block/qcow.c b/block/qcow.c +index 220ac04..2efe2fc 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -126,11 +126,17 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, + goto fail; + } + +- if (header.size <= 1 || header.cluster_bits < 9) { +- error_setg(errp, "invalid value in qcow header"); ++ if (header.size <= 1) { ++ error_setg(errp, "Image size is too small (must be at least 2 bytes)"); + ret = -EINVAL; + goto fail; + } ++ if (header.cluster_bits < 9 || header.cluster_bits > 16) { ++ error_setg(errp, "Cluster size must be between 512 and 64k"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ + if (header.crypt_method > QCOW_CRYPT_AES) { + error_setg(errp, "invalid encryption method in qcow header"); + ret = -EINVAL; +diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092 +new file mode 100755 +index 0000000..d060e6f +--- /dev/null ++++ b/tests/qemu-iotests/092 +@@ -0,0 +1,63 @@ ++#!/bin/bash ++# ++# qcow1 format input validation tests ++# ++# Copyright (C) 2014 Red Hat, Inc. ++# ++# 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 . ++# ++ ++# creator ++owner=kwolf@redhat.com ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++here=`pwd` ++tmp=/tmp/$$ ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ rm -f $TEST_IMG.snap ++ _cleanup_test_img ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++_supported_fmt qcow ++_supported_proto generic ++_supported_os Linux ++ ++offset_cluster_bits=32 ++ ++echo ++echo "== Invalid cluster size ==" ++_make_test_img 64M ++poke_file "$TEST_IMG" "$offset_cluster_bits" "\xff" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++poke_file "$TEST_IMG" "$offset_cluster_bits" "\x1f" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++poke_file "$TEST_IMG" "$offset_cluster_bits" "\x08" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++poke_file "$TEST_IMG" "$offset_cluster_bits" "\x11" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++ ++# success, all done ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/092.out b/tests/qemu-iotests/092.out +new file mode 100644 +index 0000000..8bf8158 +--- /dev/null ++++ b/tests/qemu-iotests/092.out +@@ -0,0 +1,13 @@ ++QA output created by 092 ++ ++== Invalid cluster size == ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 ++qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k ++no file open, try 'help open' ++qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k ++no file open, try 'help open' ++qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k ++no file open, try 'help open' ++qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k ++no file open, try 'help open' ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index ad96fcf..d6d4a7f 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -81,3 +81,4 @@ + 084 img auto + 086 rw auto quick + 088 rw auto ++092 rw auto quick +-- +1.7.1 + diff --git a/SOURCES/kvm-qcow1-Make-padding-in-the-header-explicit.patch b/SOURCES/kvm-qcow1-Make-padding-in-the-header-explicit.patch new file mode 100644 index 0000000..c8a69b8 --- /dev/null +++ b/SOURCES/kvm-qcow1-Make-padding-in-the-header-explicit.patch @@ -0,0 +1,52 @@ +From 3dae291d6b66443e016123ff763e89c07119cacb Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 2 Jun 2014 13:54:44 +0200 +Subject: [PATCH 23/30] qcow1: Make padding in the header explicit + +RH-Author: Kevin Wolf +Message-id: <1401717288-3918-3-git-send-email-kwolf@redhat.com> +Patchwork-id: 59097 +O-Subject: [RHEL-7.1/7.0.z qemu-kvm PATCH 2/6] qcow1: Make padding in the header explicit +Bugzilla: 1097229 +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Stefan Hajnoczi + +We were relying on all compilers inserting the same padding in the +header struct that is used for the on-disk format. Let's not do that. +Mark the struct as packed and insert an explicit padding field for +compatibility. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Benoit Canet +(cherry picked from commit ea54feff58efedc809641474b25a3130309678e7) +--- + block/qcow.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Signed-off-by: Miroslav Rezanina +--- + block/qcow.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/block/qcow.c b/block/qcow.c +index b57b900..220ac04 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -48,9 +48,10 @@ typedef struct QCowHeader { + uint64_t size; /* in bytes */ + uint8_t cluster_bits; + uint8_t l2_bits; ++ uint16_t padding; + uint32_t crypt_method; + uint64_t l1_table_offset; +-} QCowHeader; ++} QEMU_PACKED QCowHeader; + + #define L2_CACHE_SIZE 16 + +-- +1.7.1 + diff --git a/SOURCES/kvm-qcow1-Stricter-backing-file-length-check.patch b/SOURCES/kvm-qcow1-Stricter-backing-file-length-check.patch new file mode 100644 index 0000000..cbb569f --- /dev/null +++ b/SOURCES/kvm-qcow1-Stricter-backing-file-length-check.patch @@ -0,0 +1,114 @@ +From 9e8900ff62bb5c0009ca25a98158650e39f99c47 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 2 Jun 2014 13:54:48 +0200 +Subject: [PATCH 27/30] qcow1: Stricter backing file length check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Kevin Wolf +Message-id: <1401717288-3918-7-git-send-email-kwolf@redhat.com> +Patchwork-id: 59100 +O-Subject: [RHEL-7.1/7.0.z qemu-kvm PATCH 6/6] qcow1: Stricter backing file length check +Bugzilla: 1097236 +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Stefan Hajnoczi + +Like qcow2 since commit 6d33e8e7, error out on invalid lengths instead +of silently truncating them to 1023. + +Also don't rely on bdrv_pread() catching integer overflows that make len +negative, but use unsigned variables in the first place. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Benoit Canet +│(cherry picked from commit d66e5cee002c471b78139228a4e7012736b375f9) +--- + block/qcow.c | 7 +++++-- + tests/qemu-iotests/092 | 11 +++++++++++ + tests/qemu-iotests/092.out | 7 +++++++ + 3 files changed, 23 insertions(+), 2 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + block/qcow.c | 7 +++++-- + tests/qemu-iotests/092 | 11 +++++++++++ + tests/qemu-iotests/092.out | 7 +++++++ + 3 files changed, 23 insertions(+), 2 deletions(-) + +diff --git a/block/qcow.c b/block/qcow.c +index 4fdc751..ad44f78 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -97,7 +97,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, + Error **errp) + { + BDRVQcowState *s = bs->opaque; +- int len, i, shift, ret; ++ unsigned int len, i, shift; ++ int ret; + QCowHeader header; + + ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); +@@ -200,7 +201,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, + if (header.backing_file_offset != 0) { + len = header.backing_file_size; + if (len > 1023) { +- len = 1023; ++ error_setg(errp, "Backing file name too long"); ++ ret = -EINVAL; ++ goto fail; + } + ret = bdrv_pread(bs->file, header.backing_file_offset, + bs->backing_file, len); +diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092 +index ae6ca76..a8c0c9c 100755 +--- a/tests/qemu-iotests/092 ++++ b/tests/qemu-iotests/092 +@@ -43,6 +43,8 @@ _supported_fmt qcow + _supported_proto generic + _supported_os Linux + ++offset_backing_file_offset=8 ++offset_backing_file_size=16 + offset_size=24 + offset_cluster_bits=32 + offset_l2_bits=33 +@@ -81,6 +83,15 @@ poke_file "$TEST_IMG" "$offset_size" "\xee\xee\xee\xee\xee\xee\xee\xee" + poke_file "$TEST_IMG" "$offset_size" "\x7f\xff\xff\xff\xff\xff\xff\xff" + { $QEMU_IO -c "write 0 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + ++echo ++echo "== Invalid backing file length ==" ++_make_test_img 64M ++poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\xff" ++poke_file "$TEST_IMG" "$offset_backing_file_size" "\xff\xff\xff\xff" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++poke_file "$TEST_IMG" "$offset_backing_file_size" "\x7f\xff\xff\xff" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/092.out b/tests/qemu-iotests/092.out +index ac03302..496d8f0 100644 +--- a/tests/qemu-iotests/092.out ++++ b/tests/qemu-iotests/092.out +@@ -28,4 +28,11 @@ qemu-io: can't open device TEST_DIR/t.qcow: Image too large + no file open, try 'help open' + qemu-io: can't open device TEST_DIR/t.qcow: Image too large + no file open, try 'help open' ++ ++== Invalid backing file length == ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 ++qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long ++no file open, try 'help open' ++qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long ++no file open, try 'help open' + *** done +-- +1.7.1 + diff --git a/SOURCES/kvm-qcow1-Validate-L2-table-size-CVE-2014-0222.patch b/SOURCES/kvm-qcow1-Validate-L2-table-size-CVE-2014-0222.patch new file mode 100644 index 0000000..425db79 --- /dev/null +++ b/SOURCES/kvm-qcow1-Validate-L2-table-size-CVE-2014-0222.patch @@ -0,0 +1,119 @@ +From 6cec75be66671262a640c0424d93902862f6f1e7 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 2 Jun 2014 13:54:46 +0200 +Subject: [PATCH 25/30] qcow1: Validate L2 table size (CVE-2014-0222) + +RH-Author: Kevin Wolf +Message-id: <1401717288-3918-5-git-send-email-kwolf@redhat.com> +Patchwork-id: 59099 +O-Subject: [RHEL-7.1/7.0.z qemu-kvm PATCH 4/6] qcow1: Validate L2 table size (CVE-2014-0222) +Bugzilla: 1097229 +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Stefan Hajnoczi + +Too large L2 table sizes cause unbounded allocations. Images actually +created by qemu-img only have 512 byte or 4k L2 tables. + +To keep things consistent with cluster sizes, allow ranges between 512 +bytes and 64k (in fact, down to 1 entry = 8 bytes is technically +working, but L2 table sizes smaller than a cluster don't make a lot of +sense). + +This also means that the number of bytes on the virtual disk that are +described by the same L2 table is limited to at most 8k * 64k or 2^29, +preventively avoiding any integer overflows. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Reviewed-by: Benoit Canet +(cherry picked from commit 42eb58179b3b215bb507da3262b682b8a2ec10b5) +--- + block/qcow.c | 8 ++++++++ + tests/qemu-iotests/092 | 15 +++++++++++++++ + tests/qemu-iotests/092.out | 11 +++++++++++ + 3 files changed, 34 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + block/qcow.c | 8 ++++++++ + tests/qemu-iotests/092 | 15 +++++++++++++++ + tests/qemu-iotests/092.out | 11 +++++++++++ + 3 files changed, 34 insertions(+), 0 deletions(-) + +diff --git a/block/qcow.c b/block/qcow.c +index 2efe2fc..f266701 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -137,6 +137,14 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, + goto fail; + } + ++ /* l2_bits specifies number of entries; storing a uint64_t in each entry, ++ * so bytes = num_entries << 3. */ ++ if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) { ++ error_setg(errp, "L2 table size must be between 512 and 64k"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ + if (header.crypt_method > QCOW_CRYPT_AES) { + error_setg(errp, "invalid encryption method in qcow header"); + ret = -EINVAL; +diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092 +index d060e6f..fb8bacc 100755 +--- a/tests/qemu-iotests/092 ++++ b/tests/qemu-iotests/092 +@@ -44,6 +44,7 @@ _supported_proto generic + _supported_os Linux + + offset_cluster_bits=32 ++offset_l2_bits=33 + + echo + echo "== Invalid cluster size ==" +@@ -57,6 +58,20 @@ poke_file "$TEST_IMG" "$offset_cluster_bits" "\x08" + poke_file "$TEST_IMG" "$offset_cluster_bits" "\x11" + { $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + ++echo ++echo "== Invalid L2 table size ==" ++_make_test_img 64M ++poke_file "$TEST_IMG" "$offset_l2_bits" "\xff" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++poke_file "$TEST_IMG" "$offset_l2_bits" "\x05" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++ ++# 1 << 0x1b = 2^31 / L2_CACHE_SIZE ++poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/092.out b/tests/qemu-iotests/092.out +index 8bf8158..73918b3 100644 +--- a/tests/qemu-iotests/092.out ++++ b/tests/qemu-iotests/092.out +@@ -10,4 +10,15 @@ qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and + no file open, try 'help open' + qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k + no file open, try 'help open' ++ ++== Invalid L2 table size == ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 ++qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k ++no file open, try 'help open' ++qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k ++no file open, try 'help open' ++qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k ++no file open, try 'help open' ++qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k ++no file open, try 'help open' + *** done +-- +1.7.1 + diff --git a/SOURCES/kvm-qcow1-Validate-image-size-CVE-2014-0223.patch b/SOURCES/kvm-qcow1-Validate-image-size-CVE-2014-0223.patch new file mode 100644 index 0000000..dd56cbb --- /dev/null +++ b/SOURCES/kvm-qcow1-Validate-image-size-CVE-2014-0223.patch @@ -0,0 +1,118 @@ +From a193c89099b75ab17e530fb909813373f72c1ca7 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Mon, 2 Jun 2014 13:54:47 +0200 +Subject: [PATCH 26/30] qcow1: Validate image size (CVE-2014-0223) + +RH-Author: Kevin Wolf +Message-id: <1401717288-3918-6-git-send-email-kwolf@redhat.com> +Patchwork-id: 59101 +O-Subject: [RHEL-7.1/7.0.z qemu-kvm PATCH 5/6] qcow1: Validate image size (CVE-2014-0223) +Bugzilla: 1097236 +RH-Acked-by: Max Reitz +RH-Acked-by: Fam Zheng +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Stefan Hajnoczi + +A huge image size could cause s->l1_size to overflow. Make sure that +images never require a L1 table larger than what fits in s->l1_size. + +This cannot only cause unbounded allocations, but also the allocation of +a too small L1 table, resulting in out-of-bounds array accesses (both +reads and writes). + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +(cherry picked from commit 46485de0cb357b57373e1ca895adedf1f3ed46ec) +--- + block/qcow.c | 16 ++++++++++++++-- + tests/qemu-iotests/092 | 9 +++++++++ + tests/qemu-iotests/092.out | 7 +++++++ + 3 files changed, 30 insertions(+), 2 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + block/qcow.c | 16 ++++++++++++++-- + tests/qemu-iotests/092 | 9 +++++++++ + tests/qemu-iotests/092.out | 7 +++++++ + 3 files changed, 30 insertions(+), 2 deletions(-) + +diff --git a/block/qcow.c b/block/qcow.c +index f266701..4fdc751 100644 +--- a/block/qcow.c ++++ b/block/qcow.c +@@ -61,7 +61,7 @@ typedef struct BDRVQcowState { + int cluster_sectors; + int l2_bits; + int l2_size; +- int l1_size; ++ unsigned int l1_size; + uint64_t cluster_offset_mask; + uint64_t l1_table_offset; + uint64_t *l1_table; +@@ -164,7 +164,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, + + /* read the level 1 table */ + shift = s->cluster_bits + s->l2_bits; +- s->l1_size = (header.size + (1LL << shift) - 1) >> shift; ++ if (header.size > UINT64_MAX - (1LL << shift)) { ++ error_setg(errp, "Image too large"); ++ ret = -EINVAL; ++ goto fail; ++ } else { ++ uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift; ++ if (l1_size > INT_MAX / sizeof(uint64_t)) { ++ error_setg(errp, "Image too large"); ++ ret = -EINVAL; ++ goto fail; ++ } ++ s->l1_size = l1_size; ++ } + + s->l1_table_offset = header.l1_table_offset; + s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t)); +diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092 +index fb8bacc..ae6ca76 100755 +--- a/tests/qemu-iotests/092 ++++ b/tests/qemu-iotests/092 +@@ -43,6 +43,7 @@ _supported_fmt qcow + _supported_proto generic + _supported_os Linux + ++offset_size=24 + offset_cluster_bits=32 + offset_l2_bits=33 + +@@ -72,6 +73,14 @@ poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e" + poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b" + { $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + ++echo ++echo "== Invalid size ==" ++_make_test_img 64M ++poke_file "$TEST_IMG" "$offset_size" "\xee\xee\xee\xee\xee\xee\xee\xee" ++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++poke_file "$TEST_IMG" "$offset_size" "\x7f\xff\xff\xff\xff\xff\xff\xff" ++{ $QEMU_IO -c "write 0 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir ++ + # success, all done + echo "*** done" + rm -f $seq.full +diff --git a/tests/qemu-iotests/092.out b/tests/qemu-iotests/092.out +index 73918b3..ac03302 100644 +--- a/tests/qemu-iotests/092.out ++++ b/tests/qemu-iotests/092.out +@@ -21,4 +21,11 @@ qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 an + no file open, try 'help open' + qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k + no file open, try 'help open' ++ ++== Invalid size == ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 ++qemu-io: can't open device TEST_DIR/t.qcow: Image too large ++no file open, try 'help open' ++qemu-io: can't open device TEST_DIR/t.qcow: Image too large ++no file open, try 'help open' + *** done +-- +1.7.1 + diff --git a/SOURCES/kvm-qcow2-Free-preallocated-zero-clusters.patch b/SOURCES/kvm-qcow2-Free-preallocated-zero-clusters.patch new file mode 100644 index 0000000..f8ce501 --- /dev/null +++ b/SOURCES/kvm-qcow2-Free-preallocated-zero-clusters.patch @@ -0,0 +1,55 @@ +From 0a83451f1962265f2ac2d43c7c1cbbf1ecd77552 Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Fri, 2 May 2014 16:06:20 +0200 +Subject: [PATCH 29/30] qcow2: Free preallocated zero clusters + +RH-Author: Max Reitz +Message-id: <1399046781-16359-2-git-send-email-mreitz@redhat.com> +Patchwork-id: 58644 +O-Subject: [RHEL-7.0 qemu-kvm PATCH 1/2] qcow2: Free preallocated zero clusters +Bugzilla: 1110188 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Jeffrey Cody + +In qcow2_free_any_clusters, preallocated zero clusters should be freed +just as normal clusters are. + +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 8f730dd24edd2576ecbd596de7ea4361296b129c) + +Signed-off-by: Max Reitz +--- + block/qcow2-refcount.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + block/qcow2-refcount.c | 8 +++++--- + 1 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c +index 73ae4e3..429b01c 100644 +--- a/block/qcow2-refcount.c ++++ b/block/qcow2-refcount.c +@@ -811,11 +811,13 @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry, + } + break; + case QCOW2_CLUSTER_NORMAL: +- qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK, +- nb_clusters << s->cluster_bits, type); ++ case QCOW2_CLUSTER_ZERO: ++ if (l2_entry & L2E_OFFSET_MASK) { ++ qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK, ++ nb_clusters << s->cluster_bits, type); ++ } + break; + case QCOW2_CLUSTER_UNALLOCATED: +- case QCOW2_CLUSTER_ZERO: + break; + default: + abort(); +-- +1.7.1 + diff --git a/SOURCES/kvm-qemu-iotests-Discard-preallocated-zero-clusters.patch b/SOURCES/kvm-qemu-iotests-Discard-preallocated-zero-clusters.patch new file mode 100644 index 0000000..e749c6d --- /dev/null +++ b/SOURCES/kvm-qemu-iotests-Discard-preallocated-zero-clusters.patch @@ -0,0 +1,145 @@ +From f5484ed380fdff9c3d6895b72f4a05c312ee37ea Mon Sep 17 00:00:00 2001 +From: Max Reitz +Date: Fri, 2 May 2014 16:06:21 +0200 +Subject: [PATCH 30/30] qemu-iotests: Discard preallocated zero clusters + +RH-Author: Max Reitz +Message-id: <1399046781-16359-3-git-send-email-mreitz@redhat.com> +Patchwork-id: 58645 +O-Subject: [RHEL-7.0 qemu-kvm PATCH 2/2] qemu-iotests: Discard preallocated zero clusters +Bugzilla: 1110188 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Jeffrey Cody + +Add a new test case for discarding preallocated zero clusters; doing +this should not result in any leaks. + +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 975a93c082452db9aa1397a797ca8f13ba367393) + +Conflicts: + tests/qemu-iotests/group + +Signed-off-by: Max Reitz +--- + tests/qemu-iotests/066 | 63 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/066.out | 13 ++++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 77 insertions(+) + create mode 100755 tests/qemu-iotests/066 + create mode 100644 tests/qemu-iotests/066.out + +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/066 | 63 ++++++++++++++++++++++++++++++++++++++++++++ + tests/qemu-iotests/066.out | 13 +++++++++ + tests/qemu-iotests/group | 1 + + 3 files changed, 77 insertions(+), 0 deletions(-) + create mode 100755 tests/qemu-iotests/066 + create mode 100644 tests/qemu-iotests/066.out + +diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066 +new file mode 100755 +index 0000000..1c2452b +--- /dev/null ++++ b/tests/qemu-iotests/066 +@@ -0,0 +1,63 @@ ++#!/bin/bash ++# ++# Test case for discarding preallocated zero clusters in qcow2 ++# ++# Copyright (C) 2013 Red Hat, Inc. ++# ++# 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 . ++# ++ ++# creator ++owner=mreitz@redhat.com ++ ++seq="$(basename $0)" ++echo "QA output created by $seq" ++ ++here="$PWD" ++tmp=/tmp/$$ ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_test_img ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++. ./common.rc ++. ./common.filter ++ ++# This tests qocw2-specific low-level functionality ++_supported_fmt qcow2 ++_supported_proto generic ++_supported_os Linux ++ ++IMGOPTS="compat=1.1" ++IMG_SIZE=64M ++ ++echo ++echo "=== Testing snapshotting an image with zero clusters ===" ++echo ++_make_test_img $IMG_SIZE ++# Write some normal clusters, zero them (creating preallocated zero clusters) ++# and discard those ++$QEMU_IO -c "write 0 256k" -c "write -z 0 256k" -c "discard 0 256k" "$TEST_IMG" \ ++ | _filter_qemu_io ++# Check the image (there shouldn't be any leaks) ++_check_test_img ++ ++# success, all done ++echo "*** done" ++rm -f $seq.full ++status=0 +diff --git a/tests/qemu-iotests/066.out b/tests/qemu-iotests/066.out +new file mode 100644 +index 0000000..9139780 +--- /dev/null ++++ b/tests/qemu-iotests/066.out +@@ -0,0 +1,13 @@ ++QA output created by 066 ++ ++=== Testing snapshotting an image with zero clusters === ++ ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 ++wrote 262144/262144 bytes at offset 0 ++256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++wrote 262144/262144 bytes at offset 0 ++256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++discard 262144/262144 bytes at offset 0 ++256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++No errors were found on the image. ++*** done +diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group +index d6d4a7f..e588404 100644 +--- a/tests/qemu-iotests/group ++++ b/tests/qemu-iotests/group +@@ -68,6 +68,7 @@ + 063 rw auto + 064 rw auto + 065 rw auto ++066 rw auto + 067 rw auto + 068 rw auto + 070 rw auto +-- +1.7.1 + diff --git a/SOURCES/kvm-skip-system-call-when-msi-route-is-unchanged.patch b/SOURCES/kvm-skip-system-call-when-msi-route-is-unchanged.patch new file mode 100644 index 0000000..70ce125 --- /dev/null +++ b/SOURCES/kvm-skip-system-call-when-msi-route-is-unchanged.patch @@ -0,0 +1,51 @@ +From 00a2c1d4f4dff271a314f0e9eb3b4c873b1a06c1 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Mon, 19 May 2014 09:57:40 +0200 +Subject: [PATCH 2/2] kvm: skip system call when msi route is unchanged + +RH-Author: Michael S. Tsirkin +Message-id: <1400493448-29146-3-git-send-email-mst@redhat.com> +Patchwork-id: 58949 +O-Subject: [PATCH qemu-kvm RHEL7.1 2/2] kvm: skip system call when msi route is unchanged +Bugzilla: 1110693 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Marcel Apfelbaum +RH-Acked-by: Alex Williamson + +Some guests do a large number of mask/unmask +calls which currently trigger expensive route update +system calls. +Detect that route in unchanged and skip the system call. + +Reported-by: "Zhanghaoyu (A)" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Gleb Natapov +(cherry picked from commit 40509f7f52672fe41c2cce895e187352fc09f53a) +--- + kvm-all.c | 4 ++++ + 1 file changed, 4 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + kvm-all.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/kvm-all.c b/kvm-all.c +index 592301a..f7f621b 100644 +--- a/kvm-all.c ++++ b/kvm-all.c +@@ -1008,6 +1008,10 @@ static int kvm_update_routing_entry(KVMState *s, + continue; + } + ++ if(!memcmp(entry, new_entry, sizeof *entry)) { ++ return 0; ++ } ++ + *entry = *new_entry; + + kvm_irqchip_commit_routes(s); +-- +1.7.1 + diff --git a/SOURCES/kvm-usb-fix-up-post-load-checks.patch b/SOURCES/kvm-usb-fix-up-post-load-checks.patch new file mode 100644 index 0000000..ca14310 --- /dev/null +++ b/SOURCES/kvm-usb-fix-up-post-load-checks.patch @@ -0,0 +1,64 @@ +From f01e8ceed912ea31bf22046197fd18b82e554e48 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Thu, 15 May 2014 09:52:52 +0200 +Subject: [PATCH 16/30] usb: fix up post load checks + +RH-Author: Michael S. Tsirkin +Message-id: <1400144747-16304-1-git-send-email-mst@redhat.com> +Patchwork-id: 58906 +O-Subject: [PATCH qemu-kvm RHEL7.0.z] usb: fix up post load checks +Bugzilla: 1096828 +RH-Acked-by: Gerd Hoffmann +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Marcel Apfelbaum +RH-Acked-by: Juan Quintela + +Correct post load checks: +1. dev->setup_len == sizeof(dev->data_buf) + seems fine, no need to fail migration +2. When state is DATA, passing index > len + will cause memcpy with negative length, + resulting in heap overflow + +First of the issues was reported by dgilbert. + +Reported-by: "Dr. David Alan Gilbert" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Juan Quintela +(cherry picked from commit 719ffe1f5f72b1c7ace4afe9ba2815bcb53a829e) +Note: in maintainer's tree + git://github.com/juanquintela/qemu.git tags/migration/20140515, + pull request sent + +CVE-2014-3461 + +Bugzilla: 1096828 +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7459773 +Tested: lightly on developer's box +--- + hw/usb/bus.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + hw/usb/bus.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/bus.c b/hw/usb/bus.c +index 9766b7f..f4eeb5e 100644 +--- a/hw/usb/bus.c ++++ b/hw/usb/bus.c +@@ -51,8 +51,8 @@ static int usb_device_post_load(void *opaque, int version_id) + } + if (dev->setup_index < 0 || + dev->setup_len < 0 || +- dev->setup_index >= sizeof(dev->data_buf) || +- dev->setup_len >= sizeof(dev->data_buf)) { ++ dev->setup_index > dev->setup_len || ++ dev->setup_len > sizeof(dev->data_buf)) { + return -EINVAL; + } + return 0; +-- +1.7.1 + diff --git a/SOURCES/kvm-usb-sanity-check-setup_index-setup_len-in-post_l2.patch b/SOURCES/kvm-usb-sanity-check-setup_index-setup_len-in-post_l2.patch new file mode 100644 index 0000000..74a41d4 --- /dev/null +++ b/SOURCES/kvm-usb-sanity-check-setup_index-setup_len-in-post_l2.patch @@ -0,0 +1,62 @@ +From bbe33dbd43e6b562459624adb801f9b35d0f5211 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:26:17 +0200 +Subject: [PATCH 15/30] usb: sanity check setup_index+setup_len in post_load + +RH-Author: Michael S. Tsirkin +Message-id: <1400055942-6418-2-git-send-email-mst@redhat.com> +Patchwork-id: 58854 +O-Subject: [PATCH qemu-kvm RHEL7.0.z 2/2] usb: sanity check setup_index+setup_len in post_load +Bugzilla: 1095746 +RH-Acked-by: Marcel Apfelbaum +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Gerd Hoffmann + +CVE-2013-4541 + +s->setup_len and s->setup_index are fed into usb_packet_copy as +size/offset into s->data_buf, it's possible for invalid state to exploit +this to load arbitrary data. + +setup_len and setup_index should be checked to make sure +they are not negative. + +Cc: Gerd Hoffmann +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Gerd Hoffmann +Signed-off-by: Juan Quintela +(cherry picked from commit 9f8e9895c504149d7048e9fc5eb5cbb34b16e49a) + +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Tested: lightly on developer's box +Bugzilla: 1095743 + +Note: the fix isn't complete upstream. there's a separate bugzilla to +fix more issues upstream and in rhel. +--- + hw/usb/bus.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +Signed-off-by: Miroslav Rezanina +--- + hw/usb/bus.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/hw/usb/bus.c b/hw/usb/bus.c +index e0c3a77..9766b7f 100644 +--- a/hw/usb/bus.c ++++ b/hw/usb/bus.c +@@ -49,7 +49,9 @@ static int usb_device_post_load(void *opaque, int version_id) + } else { + dev->attached = 1; + } +- if (dev->setup_index >= sizeof(dev->data_buf) || ++ if (dev->setup_index < 0 || ++ dev->setup_len < 0 || ++ dev->setup_index >= sizeof(dev->data_buf) || + dev->setup_len >= sizeof(dev->data_buf)) { + return -EINVAL; + } +-- +1.7.1 + diff --git a/SOURCES/kvm-usb-sanity-check-setup_index-setup_len-in-post_load.patch b/SOURCES/kvm-usb-sanity-check-setup_index-setup_len-in-post_load.patch new file mode 100644 index 0000000..190ec3d --- /dev/null +++ b/SOURCES/kvm-usb-sanity-check-setup_index-setup_len-in-post_load.patch @@ -0,0 +1,49 @@ +From 586e92b335a98dcfbb4a797eb744753038da4374 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:26:14 +0200 +Subject: [PATCH 14/30] usb: sanity check setup_index+setup_len in post_load + +RH-Author: Michael S. Tsirkin +Message-id: <1400055942-6418-1-git-send-email-mst@redhat.com> +Patchwork-id: 58853 +O-Subject: [PATCH qemu-kvm RHEL7.0.z 1/2] usb: sanity check setup_index+setup_len in post_load +Bugzilla: 1095746 +RH-Acked-by: Marcel Apfelbaum +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Gerd Hoffmann + +From: Gerd Hoffmann + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit c60174e847082ab9f70720f86509a3353f816fad) + +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Tested: lightly on developer's box +Bugzilla: 1095743 +--- + hw/usb/bus.c | 4 ++++ + 1 file changed, 4 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + hw/usb/bus.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/hw/usb/bus.c b/hw/usb/bus.c +index fe6bd13..e0c3a77 100644 +--- a/hw/usb/bus.c ++++ b/hw/usb/bus.c +@@ -49,6 +49,10 @@ static int usb_device_post_load(void *opaque, int version_id) + } else { + dev->attached = 1; + } ++ if (dev->setup_index >= sizeof(dev->data_buf) || ++ dev->setup_len >= sizeof(dev->data_buf)) { ++ return -EINVAL; ++ } + return 0; + } + +-- +1.7.1 + diff --git a/SOURCES/kvm-virtio-allow-mapping-up-to-max-queue-size.patch b/SOURCES/kvm-virtio-allow-mapping-up-to-max-queue-size.patch new file mode 100644 index 0000000..415209d --- /dev/null +++ b/SOURCES/kvm-virtio-allow-mapping-up-to-max-queue-size.patch @@ -0,0 +1,54 @@ +From 7a967f4dd36ab8cba940bacda4c893829affcd8d Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:11:59 +0200 +Subject: [PATCH 09/30] virtio: allow mapping up to max queue size + +RH-Author: Michael S. Tsirkin +Message-id: <1400054952-6106-2-git-send-email-mst@redhat.com> +Patchwork-id: 58847 +O-Subject: [PATCH qemu-kvm RHEL7.0 2/2] virtio: allow mapping up to max queue size +Bugzilla: 1095765 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Xiao Wang +RH-Acked-by: Amos Kong + +It's a loop from i < num_sg and the array is VIRTQUEUE_MAX_SIZE - so +it's OK if the value read is VIRTQUEUE_MAX_SIZE. + +Not a big problem in practice as people don't use +such big queues, but it's inelegant. + +Reported-by: "Dr. David Alan Gilbert" +Cc: qemu-stable@nongnu.org +Signed-off-by: Michael S. Tsirkin + +Upstream status: 937251408051e0489f78e4db3c92e045b147b38b +(in maintainer's tree, PULL request sent) +Tested: lightly on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Bugzilla:1095765 +--- + hw/virtio/virtio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 2667390..44309c2 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -423,7 +423,7 @@ void virtqueue_map_sg(struct iovec *sg, hwaddr *addr, + unsigned int i; + hwaddr len; + +- if (num_sg >= VIRTQUEUE_MAX_SIZE) { ++ if (num_sg > VIRTQUEUE_MAX_SIZE) { + error_report("virtio: map attempt out of bounds: %zd > %d", + num_sg, VIRTQUEUE_MAX_SIZE); + exit(1); +-- +1.7.1 + diff --git a/SOURCES/kvm-virtio-avoid-buffer-overrun-on-incoming-migration.patch b/SOURCES/kvm-virtio-avoid-buffer-overrun-on-incoming-migration.patch new file mode 100644 index 0000000..d605897 --- /dev/null +++ b/SOURCES/kvm-virtio-avoid-buffer-overrun-on-incoming-migration.patch @@ -0,0 +1,61 @@ +From d1ada486bbdecd785762a192eae716a3484d4f16 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:07:52 +0200 +Subject: [PATCH 05/30] virtio: avoid buffer overrun on incoming migration + +RH-Author: Michael S. Tsirkin +Message-id: <1400054498-4366-10-git-send-email-mst@redhat.com> +Patchwork-id: 58843 +O-Subject: [PATCH qemu-kvm RHEL7.0] virtio: avoid buffer overrun on incoming migration +Bugzilla: 1095737 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Xiao Wang +RH-Acked-by: Amos Kong + +CVE-2013-6399 + +vdev->queue_sel is read from the wire, and later used in the +emulation code as an index into vdev->vq[]. If the value of +vdev->queue_sel exceeds the length of vdev->vq[], currently +allocated to be VIRTIO_PCI_QUEUE_MAX elements, subsequent PIO +operations such as VIRTIO_PCI_QUEUE_PFN can be used to overrun +the buffer with arbitrary data originating from the source. + +Fix this by failing migration if the value from the wire exceeds +VIRTIO_PCI_QUEUE_MAX. + +Signed-off-by: Michael Roth +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Peter Maydell +Signed-off-by: Juan Quintela +(cherry picked from commit 4b53c2c72cb5541cf394033b528a6fe2a86c0ac1) + +Tested: lightly on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Bugzilla:1095737 +--- + hw/virtio/virtio.c | 3 +++ + 1 file changed, 3 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 070d64e..9600a12 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -867,6 +867,9 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) + qemu_get_8s(f, &vdev->status); + qemu_get_8s(f, &vdev->isr); + qemu_get_be16s(f, &vdev->queue_sel); ++ if (vdev->queue_sel >= VIRTIO_PCI_QUEUE_MAX) { ++ return -1; ++ } + qemu_get_be32s(f, &features); + + if (virtio_set_features(vdev, features) < 0) { +-- +1.7.1 + diff --git a/SOURCES/kvm-virtio-net-fix-buffer-overflow-on-invalid-state-load.patch b/SOURCES/kvm-virtio-net-fix-buffer-overflow-on-invalid-state-load.patch new file mode 100644 index 0000000..7958f3d --- /dev/null +++ b/SOURCES/kvm-virtio-net-fix-buffer-overflow-on-invalid-state-load.patch @@ -0,0 +1,80 @@ +From fbae1c1a80fc0c1495c86695f5f48ee1003c2a1a Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:07:39 +0200 +Subject: [PATCH 01/30] virtio-net: fix buffer overflow on invalid state load + +RH-Author: Michael S. Tsirkin +Message-id: <1400054498-4366-1-git-send-email-mst@redhat.com> +Patchwork-id: 58839 +O-Subject: [PATCH qemu-kvm RHEL7.0] virtio-net: fix buffer overflow on invalid state load +Bugzilla: 1095677 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Xiao Wang +RH-Acked-by: Amos Kong + +CVE-2013-4148 QEMU 1.0 integer conversion in +virtio_net_load()@hw/net/virtio-net.c + +Deals with loading a corrupted savevm image. + +> n->mac_table.in_use = qemu_get_be32(f); + +in_use is int so it can get negative when assigned 32bit unsigned value. + +> /* MAC_TABLE_ENTRIES may be different from the saved image */ +> if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) { + +passing this check ^^^ + +> qemu_get_buffer(f, n->mac_table.macs, +> n->mac_table.in_use * ETH_ALEN); + +with good in_use value, "n->mac_table.in_use * ETH_ALEN" can get +positive and bigger than mac_table.macs. For example 0x81000000 +satisfies this condition when ETH_ALEN is 6. + +Fix it by making the value unsigned. +For consistency, change first_multi as well. + +Note: all call sites were audited to confirm that +making them unsigned didn't cause any issues: +it turns out we actually never do math on them, +so it's easy to validate because both values are +always <= MAC_TABLE_ENTRIES. + +Reviewed-by: Michael Roth +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Laszlo Ersek +Signed-off-by: Juan Quintela +(cherry picked from commit 71f7fe48e10a8437c9d42d859389f37157f59980) + +Bugzilla: 1095677 +Tested: on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +--- + include/hw/virtio/virtio-net.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + include/hw/virtio/virtio-net.h | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h +index 75723a8..a02fc50 100644 +--- a/include/hw/virtio/virtio-net.h ++++ b/include/hw/virtio/virtio-net.h +@@ -174,8 +174,8 @@ typedef struct VirtIONet { + uint8_t nobcast; + uint8_t vhost_started; + struct { +- int in_use; +- int first_multi; ++ uint32_t in_use; ++ uint32_t first_multi; + uint8_t multi_overflow; + uint8_t uni_overflow; + uint8_t *macs; +-- +1.7.1 + diff --git a/SOURCES/kvm-virtio-net-out-of-bounds-buffer-write-on-invalid-sta.patch b/SOURCES/kvm-virtio-net-out-of-bounds-buffer-write-on-invalid-sta.patch new file mode 100644 index 0000000..21e157d --- /dev/null +++ b/SOURCES/kvm-virtio-net-out-of-bounds-buffer-write-on-invalid-sta.patch @@ -0,0 +1,77 @@ +From 2b6768100640ef4b0387f42391f5e9e82cf67284 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:07:45 +0200 +Subject: [PATCH 03/30] virtio-net: out-of-bounds buffer write on invalid state load + +RH-Author: Michael S. Tsirkin +Message-id: <1400054498-4366-3-git-send-email-mst@redhat.com> +Patchwork-id: 58841 +O-Subject: [PATCH qemu-kvm RHEL7.0] virtio-net: out-of-bounds buffer write on invalid state load +Bugzilla: 1095689 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Juan Quintela +RH-Acked-by: Vlad Yasevich +RH-Acked-by: Xiao Wang + +CVE-2013-4150 QEMU 1.5.0 out-of-bounds buffer write in +virtio_net_load()@hw/net/virtio-net.c + +This code is in hw/net/virtio-net.c: + + if (n->max_queues > 1) { + if (n->max_queues != qemu_get_be16(f)) { + error_report("virtio-net: different max_queues "); + return -1; + } + + n->curr_queues = qemu_get_be16(f); + for (i = 1; i < n->curr_queues; i++) { + n->vqs[i].tx_waiting = qemu_get_be32(f); + } + } + +Number of vqs is max_queues, so if we get invalid input here, +for example if max_queues = 2, curr_queues = 3, we get +write beyond end of the buffer, with data that comes from +wire. + +This might be used to corrupt qemu memory in hard to predict ways. +Since we have lots of function pointers around, RCE might be possible. + +Signed-off-by: Michael S. Tsirkin +Acked-by: Jason Wang +Reviewed-by: Michael Roth +Signed-off-by: Juan Quintela +(cherry picked from commit eea750a5623ddac7a61982eec8f1c93481857578) + +Tested: lightly on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Bugzilla: 1095689 +--- + hw/net/virtio-net.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + hw/net/virtio-net.c | 5 +++++ + 1 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index f6ed241..f72be9f 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1334,6 +1334,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) + } + + n->curr_queues = qemu_get_be16(f); ++ if (n->curr_queues > n->max_queues) { ++ error_report("virtio-net: curr_queues %x > max_queues %x", ++ n->curr_queues, n->max_queues); ++ return -1; ++ } + for (i = 1; i < n->curr_queues; i++) { + n->vqs[i].tx_waiting = qemu_get_be32(f); + } +-- +1.7.1 + diff --git a/SOURCES/kvm-virtio-net-out-of-bounds-buffer-write-on-load.patch b/SOURCES/kvm-virtio-net-out-of-bounds-buffer-write-on-load.patch new file mode 100644 index 0000000..9100648 --- /dev/null +++ b/SOURCES/kvm-virtio-net-out-of-bounds-buffer-write-on-load.patch @@ -0,0 +1,76 @@ +From a3f3310a41ed5af1c701fea5dd7892dd9409e7d8 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:07:42 +0200 +Subject: [PATCH 02/30] virtio-net: out-of-bounds buffer write on load + +RH-Author: Michael S. Tsirkin +Message-id: <1400054498-4366-2-git-send-email-mst@redhat.com> +Patchwork-id: 58840 +O-Subject: [PATCH qemu-kvm RHEL7.0] virtio-net: out-of-bounds buffer write on load +Bugzilla: 1095684 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Xiao Wang +RH-Acked-by: Juan Quintela + +CVE-2013-4149 QEMU 1.3.0 out-of-bounds buffer write in +virtio_net_load()@hw/net/virtio-net.c + +> } else if (n->mac_table.in_use) { +> uint8_t *buf = g_malloc0(n->mac_table.in_use); + +We are allocating buffer of size n->mac_table.in_use + +> qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN); + +and read to the n->mac_table.in_use size buffer n->mac_table.in_use * +ETH_ALEN bytes, corrupting memory. + +If adversary controls state then memory written there is controlled +by adversary. + +Reviewed-by: Michael Roth +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Juan Quintela +(cherry picked from commit 98f93ddd84800f207889491e0b5d851386b459cf) + +Bugzilla: 1095684 +Tested: lightly on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +--- + hw/net/virtio-net.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + hw/net/virtio-net.c | 15 +++++++++++---- + 1 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 2d559e0..f6ed241 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1273,10 +1273,17 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) + if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) { + qemu_get_buffer(f, n->mac_table.macs, + n->mac_table.in_use * ETH_ALEN); +- } else if (n->mac_table.in_use) { +- uint8_t *buf = g_malloc0(n->mac_table.in_use); +- qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN); +- g_free(buf); ++ } else { ++ int64_t i; ++ ++ /* Overflow detected - can happen if source has a larger MAC table. ++ * We simply set overflow flag so there's no need to maintain the ++ * table of addresses, discard them all. ++ * Note: 64 bit math to avoid integer overflow. ++ */ ++ for (i = 0; i < (int64_t)n->mac_table.in_use * ETH_ALEN; ++i) { ++ qemu_get_byte(f); ++ } + n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1; + n->mac_table.in_use = 0; + } +-- +1.7.1 + diff --git a/SOURCES/kvm-virtio-out-of-bounds-buffer-write-on-invalid-state-l.patch b/SOURCES/kvm-virtio-out-of-bounds-buffer-write-on-invalid-state-l.patch new file mode 100644 index 0000000..4283207 --- /dev/null +++ b/SOURCES/kvm-virtio-out-of-bounds-buffer-write-on-invalid-state-l.patch @@ -0,0 +1,74 @@ +From 246b73b5e55eedcc30a213a685a46ad2f117862e Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:07:49 +0200 +Subject: [PATCH 04/30] virtio: out-of-bounds buffer write on invalid state load + +RH-Author: Michael S. Tsirkin +Message-id: <1400054498-4366-4-git-send-email-mst@redhat.com> +Patchwork-id: 58842 +O-Subject: [PATCH qemu-kvm RHEL7.0] virtio: out-of-bounds buffer write on invalid state load +Bugzilla: 1095694 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Juan Quintela +RH-Acked-by: Vlad Yasevich +RH-Acked-by: Xiao Wang + +CVE-2013-4151 QEMU 1.0 out-of-bounds buffer write in +virtio_load@hw/virtio/virtio.c + +So we have this code since way back when: + + num = qemu_get_be32(f); + + for (i = 0; i < num; i++) { + vdev->vq[i].vring.num = qemu_get_be32(f); + +array of vqs has size VIRTIO_PCI_QUEUE_MAX, so +on invalid input this will write beyond end of buffer. + +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Michael Roth +Signed-off-by: Juan Quintela +(cherry picked from commit cc45995294b92d95319b4782750a3580cabdbc0c) + +Tested: lightly on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Bugzilla: 1095694 +--- + hw/virtio/virtio.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio.c | 8 +++++++- + 1 files changed, 7 insertions(+), 1 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index b5bb0b6..070d64e 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -851,7 +851,8 @@ int virtio_set_features(VirtIODevice *vdev, uint32_t val) + + int virtio_load(VirtIODevice *vdev, QEMUFile *f) + { +- int num, i, ret; ++ int i, ret; ++ uint32_t num; + uint32_t features; + uint32_t supported_features; + BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); +@@ -879,6 +880,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) + + num = qemu_get_be32(f); + ++ if (num > VIRTIO_PCI_QUEUE_MAX) { ++ error_report("Invalid number of PCI queues: 0x%x", num); ++ return -1; ++ } ++ + for (i = 0; i < num; i++) { + vdev->vq[i].vring.num = qemu_get_be32(f); + vdev->vq[i].pa = qemu_get_be64(f); +-- +1.7.1 + diff --git a/SOURCES/kvm-virtio-scsi-fix-buffer-overrun-on-invalid-state-load.patch b/SOURCES/kvm-virtio-scsi-fix-buffer-overrun-on-invalid-state-load.patch new file mode 100644 index 0000000..c0b9dda --- /dev/null +++ b/SOURCES/kvm-virtio-scsi-fix-buffer-overrun-on-invalid-state-load.patch @@ -0,0 +1,88 @@ +From 1900368b14d425fdfe1b084892d7e2b86ba64903 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:07:55 +0200 +Subject: [PATCH 06/30] virtio-scsi: fix buffer overrun on invalid state load +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Michael S. Tsirkin +Message-id: <1400054498-4366-11-git-send-email-mst@redhat.com> +Patchwork-id: 58844 +O-Subject: [PATCH qemu-kvm RHEL7.0] virtio-scsi: fix buffer overrun on invalid state load +Bugzilla: 1095741 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Xiao Wang +RH-Acked-by: Amos Kong + +CVE-2013-4542 + +hw/scsi/scsi-bus.c invokes load_request. + + virtio_scsi_load_request does: + qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); + +this probably can make elem invalid, for example, +make in_num or out_num huge, then: + + virtio_scsi_parse_req(s, vs->cmd_vqs[n], req); + +will do: + + if (req->elem.out_num > 1) { + qemu_sgl_init_external(req, &req->elem.out_sg[1], + &req->elem.out_addr[1], + req->elem.out_num - 1); + } else { + qemu_sgl_init_external(req, &req->elem.in_sg[1], + &req->elem.in_addr[1], + req->elem.in_num - 1); + } + +and this will access out of array bounds. + +Note: this adds security checks within assert calls since +SCSIBusInfo's load_request cannot fail. +For now simply disable builds with NDEBUG - there seems +to be little value in supporting these. + +Cc: Andreas Färber +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Juan Quintela +(cherry picked from commit 3c3ce981423e0d6c18af82ee62f1850c2cda5976) + +Tested: lightly on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Bugzilla:1095741 +--- + hw/scsi/virtio-scsi.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/virtio-scsi.c | 9 +++++++++ + 1 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c +index 57541b4..7cf3e4b 100644 +--- a/hw/scsi/virtio-scsi.c ++++ b/hw/scsi/virtio-scsi.c +@@ -145,6 +145,15 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) + qemu_get_be32s(f, &n); + assert(n < vs->conf.num_queues); + qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); ++ /* TODO: add a way for SCSIBusInfo's load_request to fail, ++ * and fail migration instead of asserting here. ++ * When we do, we might be able to re-enable NDEBUG below. ++ */ ++#ifdef NDEBUG ++#error building with NDEBUG is not supported ++#endif ++ assert(req->elem.in_num <= ARRAY_SIZE(req->elem.in_sg)); ++ assert(req->elem.out_num <= ARRAY_SIZE(req->elem.out_sg)); + virtio_scsi_parse_req(s, vs->cmd_vqs[n], req); + + scsi_req_ref(sreq); +-- +1.7.1 + diff --git a/SOURCES/kvm-virtio-validate-config_len-on-load.patch b/SOURCES/kvm-virtio-validate-config_len-on-load.patch new file mode 100644 index 0000000..010d822 --- /dev/null +++ b/SOURCES/kvm-virtio-validate-config_len-on-load.patch @@ -0,0 +1,69 @@ +From 3a5fadc2341be9efd129aed5cd04ebdba2cdc36d Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:07:58 +0200 +Subject: [PATCH 07/30] virtio: validate config_len on load + +RH-Author: Michael S. Tsirkin +Message-id: <1400054498-4366-17-git-send-email-mst@redhat.com> +Patchwork-id: 58845 +O-Subject: [PATCH qemu-kvm RHEL7.0] virtio: validate config_len on load +Bugzilla: 1095782 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Juan Quintela +RH-Acked-by: Vlad Yasevich +RH-Acked-by: Xiao Wang + +Malformed input can have config_len in migration stream +exceed the array size allocated on destination, the +result will be heap overflow. + +To fix, that config_len matches on both sides. + +CVE-2014-0182 + +Reported-by: "Dr. David Alan Gilbert" +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Juan Quintela +(cherry picked from commit a890a2f9137ac3cf5b607649e66a6f3a5512d8dc) + +Tested: lightly on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Bugzilla:1095782 +--- + hw/virtio/virtio.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio.c | 8 +++++++- + 1 files changed, 7 insertions(+), 1 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 9600a12..686dfbb 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -852,6 +852,7 @@ int virtio_set_features(VirtIODevice *vdev, uint32_t val) + int virtio_load(VirtIODevice *vdev, QEMUFile *f) + { + int i, ret; ++ int32_t config_len; + uint32_t num; + uint32_t features; + uint32_t supported_features; +@@ -878,7 +879,12 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) + features, supported_features); + return -1; + } +- vdev->config_len = qemu_get_be32(f); ++ config_len = qemu_get_be32(f); ++ if (config_len != vdev->config_len) { ++ error_report("Unexpected config length 0x%x. Expected 0x%zx", ++ config_len, vdev->config_len); ++ return -1; ++ } + qemu_get_buffer(f, vdev->config, vdev->config_len); + + num = qemu_get_be32(f); +-- +1.7.1 + diff --git a/SOURCES/kvm-virtio-validate-num_sg-when-mapping.patch b/SOURCES/kvm-virtio-validate-num_sg-when-mapping.patch new file mode 100644 index 0000000..3d2fb95 --- /dev/null +++ b/SOURCES/kvm-virtio-validate-num_sg-when-mapping.patch @@ -0,0 +1,62 @@ +From 24625e2c2eb6e259b621c7ff11671977fa705578 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:11:56 +0200 +Subject: [PATCH 08/30] virtio: validate num_sg when mapping + +RH-Author: Michael S. Tsirkin +Message-id: <1400054952-6106-1-git-send-email-mst@redhat.com> +Patchwork-id: 58846 +O-Subject: [PATCH qemu-kvm RHEL7.0 1/2] virtio: validate num_sg when mapping +Bugzilla: 1095765 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Xiao Wang +RH-Acked-by: Amos Kong + +CVE-2013-4535 +CVE-2013-4536 + +Both virtio-block and virtio-serial read, +VirtQueueElements are read in as buffers, and passed to +virtqueue_map_sg(), where num_sg is taken from the wire and can force +writes to indicies beyond VIRTQUEUE_MAX_SIZE. + +To fix, validate num_sg. + +Reported-by: Michael Roth +Signed-off-by: Michael S. Tsirkin +Cc: Amit Shah +Signed-off-by: Juan Quintela +(cherry picked from commit 36cf2a37132c7f01fa9adb5f95f5312b27742fd4) + +Tested: lightly on developer's box +Brew build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=7450401 +Bugzilla:1095765 +--- + hw/virtio/virtio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 686dfbb..2667390 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -423,6 +423,12 @@ void virtqueue_map_sg(struct iovec *sg, hwaddr *addr, + unsigned int i; + hwaddr len; + ++ if (num_sg >= VIRTQUEUE_MAX_SIZE) { ++ error_report("virtio: map attempt out of bounds: %zd > %d", ++ num_sg, VIRTQUEUE_MAX_SIZE); ++ exit(1); ++ } ++ + for (i = 0; i < num_sg; i++) { + len = sg[i].iov_len; + sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write); +-- +1.7.1 + diff --git a/SOURCES/kvm-vmstate-add-VMSTATE_VALIDATE.patch b/SOURCES/kvm-vmstate-add-VMSTATE_VALIDATE.patch new file mode 100644 index 0000000..1c5da7e --- /dev/null +++ b/SOURCES/kvm-vmstate-add-VMSTATE_VALIDATE.patch @@ -0,0 +1,51 @@ +From 1886b0146de0847ff5f81e5d89ba3893bbab63fc Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:24:33 +0200 +Subject: [PATCH 11/30] vmstate: add VMSTATE_VALIDATE + +RH-Author: Michael S. Tsirkin +Message-id: <1400055633-6261-3-git-send-email-mst@redhat.com> +Patchwork-id: 58850 +O-Subject: [PATCH qemu-kvm RHEL7.0.z 3/5] vmstate: add VMSTATE_VALIDATE +Bugzilla: 1095706 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Marcel Apfelbaum +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Juan Quintela + +Validate state using VMS_ARRAY with num = 0 and VMS_MUST_EXIST + +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Juan Quintela +(cherry picked from commit 4082f0889ba04678fc14816c53e1b9251ea9207e) +--- + include/migration/vmstate.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + include/migration/vmstate.h | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h +index 95d1ce6..f2652e6 100644 +--- a/include/migration/vmstate.h ++++ b/include/migration/vmstate.h +@@ -202,6 +202,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), \ +-- +1.7.1 + diff --git a/SOURCES/kvm-vmstate-add-VMS_MUST_EXIST.patch b/SOURCES/kvm-vmstate-add-VMS_MUST_EXIST.patch new file mode 100644 index 0000000..a32264c --- /dev/null +++ b/SOURCES/kvm-vmstate-add-VMS_MUST_EXIST.patch @@ -0,0 +1,76 @@ +From 939cbb6cf8128369e0ca2ec21b33d2fc40699142 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Wed, 14 May 2014 08:24:29 +0200 +Subject: [PATCH 10/30] vmstate: add VMS_MUST_EXIST + +RH-Author: Michael S. Tsirkin +Message-id: <1400055633-6261-2-git-send-email-mst@redhat.com> +Patchwork-id: 58849 +O-Subject: [PATCH qemu-kvm RHEL7.0.z 2/5] vmstate: add VMS_MUST_EXIST +Bugzilla: 1095706 +RH-Acked-by: Dr. David Alan Gilbert (git) +RH-Acked-by: Marcel Apfelbaum +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Juan Quintela + +Can be used to verify a required field exists or validate +state in some other way. + +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Juan Quintela +(cherry picked from commit 5bf81c8d63db0216a4d29dc87f9ce530bb791dd1) +--- + include/migration/vmstate.h | 1 + + savevm.c | 10 ++++++++++ + 2 files changed, 11 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + include/migration/vmstate.h | 1 + + savevm.c | 10 ++++++++++ + 2 files changed, 11 insertions(+), 0 deletions(-) + +diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h +index 11d93e1..95d1ce6 100644 +--- a/include/migration/vmstate.h ++++ b/include/migration/vmstate.h +@@ -98,6 +98,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 6efbb75..5d1b563 100644 +--- a/savevm.c ++++ b/savevm.c +@@ -1740,6 +1740,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++; + } +@@ -1800,6 +1804,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++; + } +-- +1.7.1 + diff --git a/SOURCES/kvm-zero-initialize-KVM_SET_GSI_ROUTING-input.patch b/SOURCES/kvm-zero-initialize-KVM_SET_GSI_ROUTING-input.patch new file mode 100644 index 0000000..8876661 --- /dev/null +++ b/SOURCES/kvm-zero-initialize-KVM_SET_GSI_ROUTING-input.patch @@ -0,0 +1,110 @@ +From c878c42b892a18de84888766f14107005b4c4466 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Mon, 19 May 2014 09:57:37 +0200 +Subject: [PATCH 1/2] kvm: zero-initialize KVM_SET_GSI_ROUTING input + +RH-Author: Michael S. Tsirkin +Message-id: <1400493448-29146-2-git-send-email-mst@redhat.com> +Patchwork-id: 58948 +O-Subject: [PATCH qemu-kvm RHEL7.1 1/2] kvm: zero-initialize KVM_SET_GSI_ROUTING input +Bugzilla: 1110693 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Marcel Apfelbaum +RH-Acked-by: Alex Williamson + +kvm_add_routing_entry makes an attempt to +zero-initialize any new routing entry. +However, it fails to initialize padding +within the u field of the structure +kvm_irq_routing_entry. + +Other functions like kvm_irqchip_update_msi_route +also fail to initialize the padding field in +kvm_irq_routing_entry. + +It's better to just make sure all input is initialized. + +Once it is, we can also drop complex field by field assignment and just +do the simple *a = *b to update a route entry. + +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Gleb Natapov +(cherry picked from commit 0fbc20740342713f282b118b4a446c4c43df3f4a) +--- + kvm-all.c | 19 +++++++------------ + 1 file changed, 7 insertions(+), 12 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + kvm-all.c | 19 +++++++------------ + 1 files changed, 7 insertions(+), 12 deletions(-) + +diff --git a/kvm-all.c b/kvm-all.c +index adc0a8e..592301a 100644 +--- a/kvm-all.c ++++ b/kvm-all.c +@@ -988,11 +988,8 @@ static void kvm_add_routing_entry(KVMState *s, + } + n = s->irq_routes->nr++; + new = &s->irq_routes->entries[n]; +- memset(new, 0, sizeof(*new)); +- new->gsi = entry->gsi; +- new->type = entry->type; +- new->flags = entry->flags; +- new->u = entry->u; ++ ++ *new = *entry; + + set_gsi(s, entry->gsi); + +@@ -1011,9 +1008,7 @@ static int kvm_update_routing_entry(KVMState *s, + continue; + } + +- entry->type = new_entry->type; +- entry->flags = new_entry->flags; +- entry->u = new_entry->u; ++ *entry = *new_entry; + + kvm_irqchip_commit_routes(s); + +@@ -1025,7 +1020,7 @@ static int kvm_update_routing_entry(KVMState *s, + + void kvm_irqchip_add_irq_route(KVMState *s, int irq, int irqchip, int pin) + { +- struct kvm_irq_routing_entry e; ++ struct kvm_irq_routing_entry e = {}; + + assert(pin < s->gsi_count); + +@@ -1138,7 +1133,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) + return virq; + } + +- route = g_malloc(sizeof(KVMMSIRoute)); ++ route = g_malloc0(sizeof(KVMMSIRoute)); + route->kroute.gsi = virq; + route->kroute.type = KVM_IRQ_ROUTING_MSI; + route->kroute.flags = 0; +@@ -1159,7 +1154,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) + + int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) + { +- struct kvm_irq_routing_entry kroute; ++ struct kvm_irq_routing_entry kroute = {}; + int virq; + + if (!kvm_gsi_routing_enabled()) { +@@ -1185,7 +1180,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg) + + int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg) + { +- struct kvm_irq_routing_entry kroute; ++ struct kvm_irq_routing_entry kroute = {}; + + if (!kvm_irqchip_in_kernel()) { + return -ENOSYS; +-- +1.7.1 + diff --git a/SPECS/qemu-kvm.spec b/SPECS/qemu-kvm.spec index 310a600..6dd3fe0 100644 --- a/SPECS/qemu-kvm.spec +++ b/SPECS/qemu-kvm.spec @@ -73,7 +73,7 @@ Obsoletes: %1 < %{obsoletes_version} \ Summary: QEMU is a FAST! processor emulator Name: %{pkgname}%{?pkgsuffix} Version: 1.5.3 -Release: 60%{?dist}_0.2 +Release: 60%{?dist}.5 # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 10 License: GPLv2+ and LGPLv2+ and BSD @@ -2228,6 +2228,72 @@ Patch1089: kvm-uhci-UNfix-irq-routing-for-RHEL-6-machtypes-RHEL-onl.patch Patch1090: kvm-ide-Correct-improper-smart-self-test-counter-reset-i.patch # For bz#1094820 - Hot plug CPU not working with RHEL6 machine types running on RHEL7 host. Patch1091: kvm-pc-add-hot_add_cpu-callback-to-all-machine-types.patch +# For bz#1095677 - CVE-2013-4148 qemu-kvm: qemu: virtio-net: buffer overflow on invalid state load [rhel-7.0.z] +Patch1092: kvm-virtio-net-fix-buffer-overflow-on-invalid-state-load.patch +# For bz#1095684 - CVE-2013-4149 qemu-kvm: qemu: virtio-net: out-of-bounds buffer write on load [rhel-7.0.z] +Patch1093: kvm-virtio-net-out-of-bounds-buffer-write-on-load.patch +# For bz#1095689 - CVE-2013-4150 qemu-kvm: qemu: virtio-net: out-of-bounds buffer write on invalid state load [rhel-7.0.z] +Patch1094: kvm-virtio-net-out-of-bounds-buffer-write-on-invalid-sta.patch +# For bz#1095694 - CVE-2013-4151 qemu-kvm: qemu: virtio: out-of-bounds buffer write on invalid state load [rhel-7.0.z] +Patch1095: kvm-virtio-out-of-bounds-buffer-write-on-invalid-state-l.patch +# For bz#1095737 - CVE-2013-6399 qemu-kvm: qemu: virtio: buffer overrun on incoming migration [rhel-7.0.z] +Patch1096: kvm-virtio-avoid-buffer-overrun-on-incoming-migration.patch +# For bz#1095741 - CVE-2013-4542 qemu-kvm: qemu: virtio-scsi: buffer overrun on invalid state load [rhel-7.0.z] +Patch1097: kvm-virtio-scsi-fix-buffer-overrun-on-invalid-state-load.patch +# For bz#1095782 - CVE-2014-0182 qemu-kvm: qemu: virtio: out-of-bounds buffer write on state load with invalid config_len [rhel-7.0.z] +Patch1098: kvm-virtio-validate-config_len-on-load.patch +# For bz#1095765 - CVE-2013-4535 CVE-2013-4536 qemu-kvm: qemu: virtio: insufficient validation of num_sg when mapping [rhel-7.0.z] +Patch1099: kvm-virtio-validate-num_sg-when-mapping.patch +# For bz#1095765 - CVE-2013-4535 CVE-2013-4536 qemu-kvm: qemu: virtio: insufficient validation of num_sg when mapping [rhel-7.0.z] +Patch1100: kvm-virtio-allow-mapping-up-to-max-queue-size.patch +# For bz#1095706 - CVE-2013-4527 qemu-kvm: qemu: hpet: buffer overrun on invalid state load [rhel-7.0.z] +Patch1101: kvm-vmstate-add-VMS_MUST_EXIST.patch +# For bz#1095706 - CVE-2013-4527 qemu-kvm: qemu: hpet: buffer overrun on invalid state load [rhel-7.0.z] +Patch1102: kvm-vmstate-add-VMSTATE_VALIDATE.patch +# For bz#1095706 - CVE-2013-4527 qemu-kvm: qemu: hpet: buffer overrun on invalid state load [rhel-7.0.z] +Patch1103: kvm-hpet-fix-buffer-overrun-on-invalid-state-load.patch +# For bz#1095714 - CVE-2013-4529 qemu-kvm: qemu: hw/pci/pcie_aer.c: buffer overrun on invalid state load [rhel-7.0.z] +Patch1104: kvm-hw-pci-pcie_aer.c-fix-buffer-overruns-on-invalid-sta.patch +# For bz#1095746 - CVE-2013-4541 qemu-kvm: qemu: usb: insufficient sanity checking of setup_index+setup_len in post_load [rhel-7.0.z] +Patch1105: kvm-usb-sanity-check-setup_index-setup_len-in-post_load.patch +# For bz#1095746 - CVE-2013-4541 qemu-kvm: qemu: usb: insufficient sanity checking of setup_index+setup_len in post_load [rhel-7.0.z] +Patch1106: kvm-usb-sanity-check-setup_index-setup_len-in-post_l2.patch +# For bz#1096828 - CVE-2014-3461 qemu-kvm: Qemu: usb: fix up post load checks [rhel-7.0.z] +Patch1107: kvm-usb-fix-up-post-load-checks.patch +# For bz#1110191 - Reduce the migrate cache size during migration causes qemu segment fault +Patch1108: kvm-XBZRLE-Fix-qemu-crash-when-resize-the-xbzrle-cache.patch +# For bz#1110191 - Reduce the migrate cache size during migration causes qemu segment fault +Patch1109: kvm-Provide-init-function-for-ram-migration.patch +# For bz#1110191 - Reduce the migrate cache size during migration causes qemu segment fault +Patch1110: kvm-Init-the-XBZRLE.lock-in-ram_mig_init.patch +# For bz#1110191 - Reduce the migrate cache size during migration causes qemu segment fault +Patch1111: kvm-XBZRLE-Fix-one-XBZRLE-corruption-issues.patch +# For bz#1110189 - migration can not finish with 1024k 'remaining ram' left after hotunplug 4 nics +Patch1112: kvm-Count-used-RAMBlock-pages-for-migration_dirty_pages.patch +# For bz#1097229 - CVE-2014-0222 qemu-kvm: Qemu: qcow1: validate L2 table size to avoid integer overflows [rhel-7.0.z] +Patch1113: kvm-qcow-correctly-propagate-errors.patch +# For bz#1097229 - CVE-2014-0222 qemu-kvm: Qemu: qcow1: validate L2 table size to avoid integer overflows [rhel-7.0.z] +Patch1114: kvm-qcow1-Make-padding-in-the-header-explicit.patch +# For bz#1097229 - CVE-2014-0222 qemu-kvm: Qemu: qcow1: validate L2 table size to avoid integer overflows [rhel-7.0.z] +Patch1115: kvm-qcow1-Check-maximum-cluster-size.patch +# For bz#1097229 - CVE-2014-0222 qemu-kvm: Qemu: qcow1: validate L2 table size to avoid integer overflows [rhel-7.0.z] +Patch1116: kvm-qcow1-Validate-L2-table-size-CVE-2014-0222.patch +# For bz#1097236 - CVE-2014-0223 qemu-kvm: Qemu: qcow1: validate image size to avoid out-of-bounds memory access [rhel-7.0.z] +Patch1117: kvm-qcow1-Validate-image-size-CVE-2014-0223.patch +# For bz#1097236 - CVE-2014-0223 qemu-kvm: Qemu: qcow1: validate image size to avoid out-of-bounds memory access [rhel-7.0.z] +Patch1118: kvm-qcow1-Stricter-backing-file-length-check.patch +# For bz#1110219 - Guest can't receive any character transmitted from host after hot unplugging virtserialport then hot plugging again +Patch1119: kvm-char-restore-read-callback-on-a-reattached-hotplug-c.patch +# For bz#1110188 - qcow2 corruptions (leaked clusters after installing a rhel7 guest using virtio_scsi) +Patch1120: kvm-qcow2-Free-preallocated-zero-clusters.patch +# For bz#1110188 - qcow2 corruptions (leaked clusters after installing a rhel7 guest using virtio_scsi) +Patch1121: kvm-qemu-iotests-Discard-preallocated-zero-clusters.patch +# For bz#1110693 - 2x RHEL 5.10 VM running on RHEL 7 KVM have low TCP_STREAM throughput +Patch1122: kvm-zero-initialize-KVM_SET_GSI_ROUTING-input.patch +# For bz#1110693 - 2x RHEL 5.10 VM running on RHEL 7 KVM have low TCP_STREAM throughput +Patch1123: kvm-skip-system-call-when-msi-route-is-unchanged.patch +# For bz#1095782 - CVE-2014-0182 qemu-kvm: qemu: virtio: out-of-bounds buffer write on state load with invalid config_len [rhel-7.0.z] +Patch1124: kvm-Allow-mismatched-virtio-config-len.patch BuildRequires: zlib-devel @@ -3521,6 +3587,39 @@ cp %{SOURCE18} pc-bios # keep "make check" happy %patch1089 -p1 %patch1090 -p1 %patch1091 -p1 +%patch1092 -p1 +%patch1093 -p1 +%patch1094 -p1 +%patch1095 -p1 +%patch1096 -p1 +%patch1097 -p1 +%patch1098 -p1 +%patch1099 -p1 +%patch1100 -p1 +%patch1101 -p1 +%patch1102 -p1 +%patch1103 -p1 +%patch1104 -p1 +%patch1105 -p1 +%patch1106 -p1 +%patch1107 -p1 +%patch1108 -p1 +%patch1109 -p1 +%patch1110 -p1 +%patch1111 -p1 +%patch1112 -p1 +%patch1113 -p1 +%patch1114 -p1 +%patch1115 -p1 +%patch1116 -p1 +%patch1117 -p1 +%patch1118 -p1 +%patch1119 -p1 +%patch1120 -p1 +%patch1121 -p1 +%patch1122 -p1 +%patch1123 -p1 +%patch1124 -p1 %build buildarch="%{kvm_target}-softmmu" @@ -3937,6 +4036,85 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_libdir}/pkgconfig/libcacard.pc %changelog +* Wed Jul 02 2014 Miroslav Rezanina - 1.5.3-60.el7_0.5 +- kvm-Allow-mismatched-virtio-config-len.patch [bz#1095782] +- Resolves: bz#1095782 + (CVE-2014-0182 qemu-kvm: qemu: virtio: out-of-bounds buffer write on state load with invalid config_len [rhel-7.0.z]) + +* Wed Jun 18 2014 Miroslav Rezanina - 1.5.3-60.el7_0.4 +- kvm-zero-initialize-KVM_SET_GSI_ROUTING-input.patch [bz#1110693] +- kvm-skip-system-call-when-msi-route-is-unchanged.patch [bz#1110693] +- Resolves: bz#1110693 + (2x RHEL 5.10 VM running on RHEL 7 KVM have low TCP_STREAM throughput) + +* Tue Jun 17 2014 Miroslav Rezanina - 1.5.3-60.el7_0.3 +- kvm-virtio-net-fix-buffer-overflow-on-invalid-state-load.patch [bz#1095677] +- kvm-virtio-net-out-of-bounds-buffer-write-on-load.patch [bz#1095684] +- kvm-virtio-net-out-of-bounds-buffer-write-on-invalid-sta.patch [bz#1095689] +- kvm-virtio-out-of-bounds-buffer-write-on-invalid-state-l.patch [bz#1095694] +- kvm-virtio-avoid-buffer-overrun-on-incoming-migration.patch [bz#1095737] +- kvm-virtio-scsi-fix-buffer-overrun-on-invalid-state-load.patch [bz#1095741] +- kvm-virtio-validate-config_len-on-load.patch [bz#1095782] +- kvm-virtio-validate-num_sg-when-mapping.patch [bz#1095765] +- kvm-virtio-allow-mapping-up-to-max-queue-size.patch [bz#1095765] +- kvm-vmstate-add-VMS_MUST_EXIST.patch [bz#1095706] +- kvm-vmstate-add-VMSTATE_VALIDATE.patch [bz#1095706] +- kvm-hpet-fix-buffer-overrun-on-invalid-state-load.patch [bz#1095706] +- kvm-hw-pci-pcie_aer.c-fix-buffer-overruns-on-invalid-sta.patch [bz#1095714] +- kvm-usb-sanity-check-setup_index-setup_len-in-post_load.patch [bz#1095746] +- kvm-usb-sanity-check-setup_index-setup_len-in-post_l2.patch [bz#1095746] +- kvm-usb-fix-up-post-load-checks.patch [bz#1096828] +- kvm-XBZRLE-Fix-qemu-crash-when-resize-the-xbzrle-cache.patch [bz#1110191] +- kvm-Provide-init-function-for-ram-migration.patch [bz#1110191] +- kvm-Init-the-XBZRLE.lock-in-ram_mig_init.patch [bz#1110191] +- kvm-XBZRLE-Fix-one-XBZRLE-corruption-issues.patch [bz#1110191] +- kvm-Count-used-RAMBlock-pages-for-migration_dirty_pages.patch [bz#1110189] +- kvm-qcow-correctly-propagate-errors.patch [bz#1097229] +- kvm-qcow1-Make-padding-in-the-header-explicit.patch [bz#1097229] +- kvm-qcow1-Check-maximum-cluster-size.patch [bz#1097229] +- kvm-qcow1-Validate-L2-table-size-CVE-2014-0222.patch [bz#1097229] +- kvm-qcow1-Validate-image-size-CVE-2014-0223.patch [bz#1097236] +- kvm-qcow1-Stricter-backing-file-length-check.patch [bz#1097236] +- kvm-char-restore-read-callback-on-a-reattached-hotplug-c.patch [bz#1110219] +- kvm-qcow2-Free-preallocated-zero-clusters.patch [bz#1110188] +- kvm-qemu-iotests-Discard-preallocated-zero-clusters.patch [bz#1110188] +- Resolves: bz#1095677 + (CVE-2013-4148 qemu-kvm: qemu: virtio-net: buffer overflow on invalid state load [rhel-7.0.z]) +- Resolves: bz#1095684 + (CVE-2013-4149 qemu-kvm: qemu: virtio-net: out-of-bounds buffer write on load [rhel-7.0.z]) +- Resolves: bz#1095689 + (CVE-2013-4150 qemu-kvm: qemu: virtio-net: out-of-bounds buffer write on invalid state load [rhel-7.0.z]) +- Resolves: bz#1095694 + (CVE-2013-4151 qemu-kvm: qemu: virtio: out-of-bounds buffer write on invalid state load [rhel-7.0.z]) +- Resolves: bz#1095706 + (CVE-2013-4527 qemu-kvm: qemu: hpet: buffer overrun on invalid state load [rhel-7.0.z]) +- Resolves: bz#1095714 + (CVE-2013-4529 qemu-kvm: qemu: hw/pci/pcie_aer.c: buffer overrun on invalid state load [rhel-7.0.z]) +- Resolves: bz#1095737 + (CVE-2013-6399 qemu-kvm: qemu: virtio: buffer overrun on incoming migration [rhel-7.0.z]) +- Resolves: bz#1095741 + (CVE-2013-4542 qemu-kvm: qemu: virtio-scsi: buffer overrun on invalid state load [rhel-7.0.z]) +- Resolves: bz#1095746 + (CVE-2013-4541 qemu-kvm: qemu: usb: insufficient sanity checking of setup_index+setup_len in post_load [rhel-7.0.z]) +- Resolves: bz#1095765 + (CVE-2013-4535 CVE-2013-4536 qemu-kvm: qemu: virtio: insufficient validation of num_sg when mapping [rhel-7.0.z]) +- Resolves: bz#1095782 + (CVE-2014-0182 qemu-kvm: qemu: virtio: out-of-bounds buffer write on state load with invalid config_len [rhel-7.0.z]) +- Resolves: bz#1096828 + (CVE-2014-3461 qemu-kvm: Qemu: usb: fix up post load checks [rhel-7.0.z]) +- Resolves: bz#1097229 + (CVE-2014-0222 qemu-kvm: Qemu: qcow1: validate L2 table size to avoid integer overflows [rhel-7.0.z]) +- Resolves: bz#1097236 + (CVE-2014-0223 qemu-kvm: Qemu: qcow1: validate image size to avoid out-of-bounds memory access [rhel-7.0.z]) +- Resolves: bz#1110188 + (qcow2 corruptions (leaked clusters after installing a rhel7 guest using virtio_scsi)) +- Resolves: bz#1110189 + (migration can not finish with 1024k 'remaining ram' left after hotunplug 4 nics) +- Resolves: bz#1110191 + (Reduce the migrate cache size during migration causes qemu segment fault) +- Resolves: bz#1110219 + (Guest can't receive any character transmitted from host after hot unplugging virtserialport then hot plugging again) + * Wed May 07 2014 Miroslav Rezanina - 1.5.3-60.el7_0.2 - kvm-pc-add-hot_add_cpu-callback-to-all-machine-types.patch [bz#1094820] - Resolves: bz#1094820