From 5e4552de3e15b4843d980a7ddd87346214d62d9e Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Dec 01 2014 00:25:31 +0000 Subject: Fix qemu-img convert corruption for unflushed files (bz #1167249) Fix SLES11 migration issue (bz #1109427) CVE-2014-7840: insufficient parameter validation during ram load (bz #1163080) --- diff --git a/0015-block-raw-posix-Fix-disk-corruption-in-try_fiemap.patch b/0015-block-raw-posix-Fix-disk-corruption-in-try_fiemap.patch new file mode 100644 index 0000000..4d4f0f5 --- /dev/null +++ b/0015-block-raw-posix-Fix-disk-corruption-in-try_fiemap.patch @@ -0,0 +1,41 @@ +From: Tony Breeds +Date: Fri, 26 Sep 2014 09:14:11 +1000 +Subject: [PATCH] block/raw-posix: Fix disk corruption in try_fiemap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Using fiemap without FIEMAP_FLAG_SYNC is a known corrupter. + +Add the FIEMAP_FLAG_SYNC flag to the FS_IOC_FIEMAP ioctl. This has +the downside of significantly reducing performance. + +Reported-By: Michael Steffens +Signed-off-by: Tony Breeds +Cc: Kevin Wolf +Cc: Markus Armbruster +Cc: Stefan Hajnoczi +Cc: Max Reitz +Cc: Pádraig Brady +Cc: Eric Blake +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 38c4d0aea3e1264c86e282d99560330adf2b6e25) +--- + block/raw-posix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/raw-posix.c b/block/raw-posix.c +index 87fc170..9fbc3eb 100644 +--- a/block/raw-posix.c ++++ b/block/raw-posix.c +@@ -1419,7 +1419,7 @@ static int64_t try_fiemap(BlockDriverState *bs, off_t start, off_t *data, + + f.fm.fm_start = start; + f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE; +- f.fm.fm_flags = 0; ++ f.fm.fm_flags = FIEMAP_FLAG_SYNC; + f.fm.fm_extent_count = 1; + f.fm.fm_reserved = 0; + if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) { diff --git a/0016-block-raw-posix-use-seek_hole-ahead-of-fiemap.patch b/0016-block-raw-posix-use-seek_hole-ahead-of-fiemap.patch new file mode 100644 index 0000000..b1d4869 --- /dev/null +++ b/0016-block-raw-posix-use-seek_hole-ahead-of-fiemap.patch @@ -0,0 +1,46 @@ +From: Tony Breeds +Date: Fri, 26 Sep 2014 09:14:12 +1000 +Subject: [PATCH] block/raw-posix: use seek_hole ahead of fiemap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +try_fiemap() uses FIEMAP_FLAG_SYNC which has a significant performance +impact. + +Prefer seek_hole() over fiemap() to avoid this impact where possible. +seek_hole is more widely used and, arguably, has potential to be +optimised in the kernel. + +Reported-By: Michael Steffens +Signed-off-by: Tony Breeds +Cc: Kevin Wolf +Cc: Markus Armbruster +Cc: Stefan Hajnoczi +Cc: Max Reitz +Cc: Pádraig Brady +Cc: Eric Blake +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 7c15903789953ead14a417882657d52dc0c19a24) +--- + block/raw-posix.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/block/raw-posix.c b/block/raw-posix.c +index 9fbc3eb..75c9507 100644 +--- a/block/raw-posix.c ++++ b/block/raw-posix.c +@@ -1508,9 +1508,9 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, + + start = sector_num * BDRV_SECTOR_SIZE; + +- ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum); ++ ret = try_seek_hole(bs, start, &data, &hole, pnum); + if (ret < 0) { +- ret = try_seek_hole(bs, start, &data, &hole, pnum); ++ ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum); + if (ret < 0) { + /* Assume everything is allocated. */ + data = 0; diff --git a/0017-kvm-run-cpu-state-synchronization-on-target-vcpu-thr.patch b/0017-kvm-run-cpu-state-synchronization-on-target-vcpu-thr.patch new file mode 100644 index 0000000..25854c9 --- /dev/null +++ b/0017-kvm-run-cpu-state-synchronization-on-target-vcpu-thr.patch @@ -0,0 +1,59 @@ +From: David Hildenbrand +Date: Wed, 20 Aug 2014 14:55:25 +0200 +Subject: [PATCH] kvm: run cpu state synchronization on target vcpu thread + +As already done for kvm_cpu_synchronize_state(), let's trigger +kvm_arch_put_registers() via run_on_cpu() for kvm_cpu_synchronize_post_reset() +and kvm_cpu_synchronize_post_init(). + +This way, we make sure that the register synchronizing ioctls are +called from the proper vcpu thread; this avoids calls to +synchronize_rcu() in the kernel. + +Reviewed-by: Cornelia Huck +Signed-off-by: David Hildenbrand +Signed-off-by: Paolo Bonzini +(cherry picked from commit c8e2085d8e7a64d753eb2a43e4aeae674a99d2ff) +--- + kvm-all.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/kvm-all.c b/kvm-all.c +index 1402f4f..b240bf8 100644 +--- a/kvm-all.c ++++ b/kvm-all.c +@@ -1669,18 +1669,32 @@ void kvm_cpu_synchronize_state(CPUState *cpu) + } + } + +-void kvm_cpu_synchronize_post_reset(CPUState *cpu) ++static void do_kvm_cpu_synchronize_post_reset(void *arg) + { ++ CPUState *cpu = arg; ++ + kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE); + cpu->kvm_vcpu_dirty = false; + } + +-void kvm_cpu_synchronize_post_init(CPUState *cpu) ++void kvm_cpu_synchronize_post_reset(CPUState *cpu) ++{ ++ run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, cpu); ++} ++ ++static void do_kvm_cpu_synchronize_post_init(void *arg) + { ++ CPUState *cpu = arg; ++ + kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE); + cpu->kvm_vcpu_dirty = false; + } + ++void kvm_cpu_synchronize_post_init(CPUState *cpu) ++{ ++ run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, cpu); ++} ++ + int kvm_cpu_exec(CPUState *cpu) + { + struct kvm_run *run = cpu->kvm_run; diff --git a/0018-Introduce-cpu_clean_all_dirty.patch b/0018-Introduce-cpu_clean_all_dirty.patch new file mode 100644 index 0000000..2b25112 --- /dev/null +++ b/0018-Introduce-cpu_clean_all_dirty.patch @@ -0,0 +1,92 @@ +From: Marcelo Tosatti +Date: Fri, 5 Sep 2014 10:52:46 -0300 +Subject: [PATCH] Introduce cpu_clean_all_dirty + +Introduce cpu_clean_all_dirty, to force subsequent cpu_synchronize_all_states +to read in-kernel register state. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Marcelo Tosatti +Signed-off-by: Paolo Bonzini +(cherry picked from commit de9d61e83d43be9069e6646fa9d57a3f47779d28) +--- + cpus.c | 9 +++++++++ + include/sysemu/cpus.h | 1 + + include/sysemu/kvm.h | 8 ++++++++ + kvm-all.c | 5 +++++ + 4 files changed, 23 insertions(+) + +diff --git a/cpus.c b/cpus.c +index 5e7f2cf..492defe 100644 +--- a/cpus.c ++++ b/cpus.c +@@ -523,6 +523,15 @@ void cpu_synchronize_all_post_init(void) + } + } + ++void cpu_clean_all_dirty(void) ++{ ++ CPUState *cpu; ++ ++ CPU_FOREACH(cpu) { ++ cpu_clean_state(cpu); ++ } ++} ++ + static int do_vm_stop(RunState state) + { + int ret = 0; +diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h +index 4f79081..3f162a9 100644 +--- a/include/sysemu/cpus.h ++++ b/include/sysemu/cpus.h +@@ -10,6 +10,7 @@ void cpu_stop_current(void); + void cpu_synchronize_all_states(void); + void cpu_synchronize_all_post_reset(void); + void cpu_synchronize_all_post_init(void); ++void cpu_clean_all_dirty(void); + + void qtest_clock_warp(int64_t dest); + +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index 174ea36..777dc66 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -348,6 +348,7 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr, + void kvm_cpu_synchronize_state(CPUState *cpu); + void kvm_cpu_synchronize_post_reset(CPUState *cpu); + void kvm_cpu_synchronize_post_init(CPUState *cpu); ++void kvm_cpu_clean_state(CPUState *cpu); + + /* generic hooks - to be moved/refactored once there are more users */ + +@@ -372,6 +373,13 @@ static inline void cpu_synchronize_post_init(CPUState *cpu) + } + } + ++static inline void cpu_clean_state(CPUState *cpu) ++{ ++ if (kvm_enabled()) { ++ kvm_cpu_clean_state(cpu); ++ } ++} ++ + int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg); + int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg); + void kvm_irqchip_release_virq(KVMState *s, int virq); +diff --git a/kvm-all.c b/kvm-all.c +index b240bf8..e18d4ce 100644 +--- a/kvm-all.c ++++ b/kvm-all.c +@@ -1695,6 +1695,11 @@ void kvm_cpu_synchronize_post_init(CPUState *cpu) + run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, cpu); + } + ++void kvm_cpu_clean_state(CPUState *cpu) ++{ ++ cpu->kvm_vcpu_dirty = false; ++} ++ + int kvm_cpu_exec(CPUState *cpu) + { + struct kvm_run *run = cpu->kvm_run; diff --git a/0019-kvmclock-Ensure-time-in-migration-never-goes-backwar.patch b/0019-kvmclock-Ensure-time-in-migration-never-goes-backwar.patch new file mode 100644 index 0000000..d3facf3 --- /dev/null +++ b/0019-kvmclock-Ensure-time-in-migration-never-goes-backwar.patch @@ -0,0 +1,98 @@ +From: Alexander Graf +Date: Fri, 5 Sep 2014 10:52:45 -0300 +Subject: [PATCH] kvmclock: Ensure time in migration never goes backward + +When we migrate we ask the kernel about its current belief on what the guest +time would be. However, I've seen cases where the kvmclock guest structure +indicates a time more recent than the kvm returned time. + +To make sure we never go backwards, calculate what the guest would have seen as time at the point of migration and use that value instead of the kernel returned one when it's more recent. +This bases the view of the kvmclock after migration on the +same foundation in host as well as guest. + +Signed-off-by: Alexander Graf +Cc: qemu-stable@nongnu.org +Reviewed-by: Marcelo Tosatti +Signed-off-by: Paolo Bonzini +(cherry picked from commit 9a48bcd1b82494671c111109b0eefdb882581499) +--- + hw/i386/kvm/clock.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c +index 07b9c0e..7c1dc58 100644 +--- a/hw/i386/kvm/clock.c ++++ b/hw/i386/kvm/clock.c +@@ -14,6 +14,7 @@ + */ + + #include "qemu-common.h" ++#include "qemu/host-utils.h" + #include "sysemu/sysemu.h" + #include "sysemu/kvm.h" + #include "hw/sysbus.h" +@@ -34,6 +35,48 @@ typedef struct KVMClockState { + bool clock_valid; + } KVMClockState; + ++struct pvclock_vcpu_time_info { ++ uint32_t version; ++ uint32_t pad0; ++ uint64_t tsc_timestamp; ++ uint64_t system_time; ++ uint32_t tsc_to_system_mul; ++ int8_t tsc_shift; ++ uint8_t flags; ++ uint8_t pad[2]; ++} __attribute__((__packed__)); /* 32 bytes */ ++ ++static uint64_t kvmclock_current_nsec(KVMClockState *s) ++{ ++ CPUState *cpu = first_cpu; ++ CPUX86State *env = cpu->env_ptr; ++ hwaddr kvmclock_struct_pa = env->system_time_msr & ~1ULL; ++ uint64_t migration_tsc = env->tsc; ++ struct pvclock_vcpu_time_info time; ++ uint64_t delta; ++ uint64_t nsec_lo; ++ uint64_t nsec_hi; ++ uint64_t nsec; ++ ++ if (!(env->system_time_msr & 1ULL)) { ++ /* KVM clock not active */ ++ return 0; ++ } ++ ++ cpu_physical_memory_read(kvmclock_struct_pa, &time, sizeof(time)); ++ ++ assert(time.tsc_timestamp <= migration_tsc); ++ delta = migration_tsc - time.tsc_timestamp; ++ if (time.tsc_shift < 0) { ++ delta >>= -time.tsc_shift; ++ } else { ++ delta <<= time.tsc_shift; ++ } ++ ++ mulu64(&nsec_lo, &nsec_hi, delta, time.tsc_to_system_mul); ++ nsec = (nsec_lo >> 32) | (nsec_hi << 32); ++ return nsec + time.system_time; ++} + + static void kvmclock_vm_state_change(void *opaque, int running, + RunState state) +@@ -45,9 +88,15 @@ static void kvmclock_vm_state_change(void *opaque, int running, + + if (running) { + struct kvm_clock_data data; ++ uint64_t time_at_migration = kvmclock_current_nsec(s); + + s->clock_valid = false; + ++ /* We can't rely on the migrated clock value, just discard it */ ++ if (time_at_migration) { ++ s->clock = time_at_migration; ++ } ++ + data.clock = s->clock; + data.flags = 0; + ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data); diff --git a/0020-kvmclock-Ensure-proper-env-tsc-value-for-kvmclock_cu.patch b/0020-kvmclock-Ensure-proper-env-tsc-value-for-kvmclock_cu.patch new file mode 100644 index 0000000..269f58f --- /dev/null +++ b/0020-kvmclock-Ensure-proper-env-tsc-value-for-kvmclock_cu.patch @@ -0,0 +1,42 @@ +From: Marcelo Tosatti +Date: Fri, 5 Sep 2014 10:52:47 -0300 +Subject: [PATCH] kvmclock: Ensure proper env->tsc value for + kvmclock_current_nsec calculation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Ensure proper env->tsc value for kvmclock_current_nsec calculation. + +Reported-by: Marcin Gibuła +Analyzed-by: Marcin Gibuła +Cc: qemu-stable@nongnu.org +Signed-off-by: Marcelo Tosatti +Signed-off-by: Paolo Bonzini +(cherry picked from commit 317b0a6d8ba44e9bf8f9c3dbd776c4536843d82c) +--- + hw/i386/kvm/clock.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c +index 7c1dc58..1ac60d6 100644 +--- a/hw/i386/kvm/clock.c ++++ b/hw/i386/kvm/clock.c +@@ -17,6 +17,7 @@ + #include "qemu/host-utils.h" + #include "sysemu/sysemu.h" + #include "sysemu/kvm.h" ++#include "sysemu/cpus.h" + #include "hw/sysbus.h" + #include "hw/kvm/clock.h" + +@@ -124,6 +125,9 @@ static void kvmclock_vm_state_change(void *opaque, int running, + if (s->clock_valid) { + return; + } ++ ++ cpu_synchronize_all_states(); ++ cpu_clean_all_dirty(); + ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data); + if (ret < 0) { + fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret)); diff --git a/0021-migration-fix-parameter-validation-on-ram-load.patch b/0021-migration-fix-parameter-validation-on-ram-load.patch new file mode 100644 index 0000000..1556bdd --- /dev/null +++ b/0021-migration-fix-parameter-validation-on-ram-load.patch @@ -0,0 +1,51 @@ +From: "Michael S. Tsirkin" +Date: Wed, 12 Nov 2014 11:44:39 +0200 +Subject: [PATCH] migration: fix parameter validation on ram load + +During migration, the values read from migration stream during ram load +are not validated. Especially offset in host_from_stream_offset() and +also the length of the writes in the callers of said function. + +To fix this, we need to make sure that the [offset, offset + length] +range fits into one of the allocated memory regions. + +Validating addr < len should be sufficient since data seems to always be +managed in TARGET_PAGE_SIZE chunks. + +Fixes: CVE-2014-7840 + +Note: follow-up patches add extra checks on each block->host access. + +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Paolo Bonzini +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Amit Shah +(cherry picked from commit 0be839a2701369f669532ea5884c15bead1c6e08) +--- + arch_init.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/arch_init.c b/arch_init.c +index 8ddaf35..e2fd574 100644 +--- a/arch_init.c ++++ b/arch_init.c +@@ -1004,7 +1004,7 @@ static inline void *host_from_stream_offset(QEMUFile *f, + uint8_t len; + + if (flags & RAM_SAVE_FLAG_CONTINUE) { +- if (!block) { ++ if (!block || block->length <= offset) { + error_report("Ack, bad migration stream!"); + return NULL; + } +@@ -1017,8 +1017,9 @@ static inline void *host_from_stream_offset(QEMUFile *f, + id[len] = 0; + + QTAILQ_FOREACH(block, &ram_list.blocks, next) { +- if (!strncmp(id, block->idstr, sizeof(id))) ++ if (!strncmp(id, block->idstr, sizeof(id)) && block->length > offset) { + return memory_region_get_ram_ptr(block->mr) + offset; ++ } + } + + error_report("Can't find block %s!", id); diff --git a/qemu.spec b/qemu.spec index 89d34f3..f973600 100644 --- a/qemu.spec +++ b/qemu.spec @@ -152,7 +152,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 2.1.2 -Release: 6%{?dist} +Release: 7%{?dist} Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD Group: Development/Tools @@ -214,6 +214,17 @@ Patch0011: 0011-vmware-vga-add-vmsvga_verify_rect.patch Patch0012: 0012-vmware-vga-use-vmsvga_verify_rect-in-vmsvga_update_r.patch Patch0013: 0013-vmware-vga-use-vmsvga_verify_rect-in-vmsvga_copy_rec.patch Patch0014: 0014-vmware-vga-use-vmsvga_verify_rect-in-vmsvga_fill_rec.patch +# Fix qemu-img convert corruption for unflushed files (bz #1167249) +Patch0015: 0015-block-raw-posix-Fix-disk-corruption-in-try_fiemap.patch +Patch0016: 0016-block-raw-posix-use-seek_hole-ahead-of-fiemap.patch +# Fix SLES11 migration issue (bz #1109427) +Patch0017: 0017-kvm-run-cpu-state-synchronization-on-target-vcpu-thr.patch +Patch0018: 0018-Introduce-cpu_clean_all_dirty.patch +Patch0019: 0019-kvmclock-Ensure-time-in-migration-never-goes-backwar.patch +Patch0020: 0020-kvmclock-Ensure-proper-env-tsc-value-for-kvmclock_cu.patch +# CVE-2014-7840: insufficient parameter validation during ram load (bz +# #1163080) +Patch0021: 0021-migration-fix-parameter-validation-on-ram-load.patch BuildRequires: SDL2-devel BuildRequires: zlib-devel @@ -762,6 +773,17 @@ CAC emulation development files. %patch0012 -p1 %patch0013 -p1 %patch0014 -p1 +# Fix qemu-img convert corruption for unflushed files (bz #1167249) +%patch0015 -p1 +%patch0016 -p1 +# Fix SLES11 migration issue (bz #1109427) +%patch0017 -p1 +%patch0018 -p1 +%patch0019 -p1 +%patch0020 -p1 +# CVE-2014-7840: insufficient parameter validation during ram load (bz +# #1163080) +%patch0021 -p1 %build @@ -1541,6 +1563,12 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Sun Nov 30 2014 Cole Robinson - 2:2.1.2-7 +- Fix qemu-img convert corruption for unflushed files (bz #1167249) +- Fix SLES11 migration issue (bz #1109427) +- CVE-2014-7840: insufficient parameter validation during ram load (bz + #1163080) + * Wed Oct 29 2014 Cole Robinson - 2:2.1.2-6 - CVE-2014-7815 vnc: insufficient bits_per_pixel from the client sanitization (bz #1157647, bz #1157641)