From 4ca959b828e53b5937207fcbaa52c58728b9c722 Mon Sep 17 00:00:00 2001 From: Michael Young Date: May 03 2017 21:55:25 +0000 Subject: xen: various flaws (#1447345) x86: 64bit PV guest breakout via pagetable use-after-mode-change [XSA-213] grant transfer allows PV guest to elevate privileges [XSA-214] --- diff --git a/xen.spec b/xen.spec index 6c65f67..9e20de3 100644 --- a/xen.spec +++ b/xen.spec @@ -41,7 +41,7 @@ Summary: Xen is a virtual machine monitor Name: xen Version: 4.7.2 -Release: 5%{?dist} +Release: 6%{?dist} Group: Development/Libraries License: GPLv2+ and LGPLv2+ and BSD URL: http://xen.org/ @@ -169,6 +169,8 @@ Patch135: xsa206-4.70015-oxenstored-transaction-conflicts-improve-logging.patch Patch136: xsa206-4.70016-oxenstored-trim-history-in-the-frequent_ops-function.patch Patch137: qemu.git-d63fb193e71644a073b77ff5ac6f1216f2f6cf6e.patch Patch138: xsa212.patch +Patch139: xsa213-4.7.patch +Patch140: xsa214.patch @@ -413,6 +415,8 @@ manage Xen virtual machines. %patch135 -p1 %patch136 -p1 %patch138 -p1 +%patch139 -p1 +%patch140 -p1 # qemu-xen-traditional patches pushd tools/qemu-xen-traditional @@ -931,6 +935,11 @@ rm -rf %{buildroot} %endif %changelog +* Wed May 03 2017 Michael Young - 4.7.2-6 +- xen: various flaws (#1447345) + x86: 64bit PV guest breakout via pagetable use-after-mode-change [XSA-213] + grant transfer allows PV guest to elevate privileges [XSA-214] + * Wed Apr 05 2017 Michael Young - 4.7.2-5 - Qemu: 9pfs: host memory leakage via v9fs_create [CVE-2017-7377] (#1437873) - x86: broken check in memory_exchange() permits PV guest breakout diff --git a/xsa213-4.7.patch b/xsa213-4.7.patch new file mode 100644 index 0000000..6964b91 --- /dev/null +++ b/xsa213-4.7.patch @@ -0,0 +1,173 @@ +From: Jan Beulich +Subject: multicall: deal with early exit conditions + +In particular changes to guest privilege level require the multicall +sequence to be aborted, as hypercalls are permitted from kernel mode +only. While likely not very useful in a multicall, also properly handle +the return value in the HYPERVISOR_iret case (which should be the guest +specified value). + +This is XSA-213. + +Reported-by: Jann Horn +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper +Acked-by: Julien Grall + +--- a/xen/arch/arm/traps.c ++++ b/xen/arch/arm/traps.c +@@ -1529,30 +1529,33 @@ static bool_t check_multicall_32bit_clea + return true; + } + +-void do_multicall_call(struct multicall_entry *multi) ++enum mc_disposition do_multicall_call(struct multicall_entry *multi) + { + arm_hypercall_fn_t call = NULL; + + if ( multi->op >= ARRAY_SIZE(arm_hypercall_table) ) + { + multi->result = -ENOSYS; +- return; ++ return mc_continue; + } + + call = arm_hypercall_table[multi->op].fn; + if ( call == NULL ) + { + multi->result = -ENOSYS; +- return; ++ return mc_continue; + } + + if ( is_32bit_domain(current->domain) && + !check_multicall_32bit_clean(multi) ) +- return; ++ return mc_continue; + + multi->result = call(multi->args[0], multi->args[1], + multi->args[2], multi->args[3], + multi->args[4]); ++ ++ return likely(!psr_mode_is_user(guest_cpu_user_regs())) ++ ? mc_continue : mc_preempt; + } + + /* +--- a/xen/common/multicall.c ++++ b/xen/common/multicall.c +@@ -40,6 +40,7 @@ do_multicall( + struct mc_state *mcs = ¤t->mc_state; + uint32_t i; + int rc = 0; ++ enum mc_disposition disp = mc_continue; + + if ( unlikely(__test_and_set_bit(_MCSF_in_multicall, &mcs->flags)) ) + { +@@ -50,7 +51,7 @@ do_multicall( + if ( unlikely(!guest_handle_okay(call_list, nr_calls)) ) + rc = -EFAULT; + +- for ( i = 0; !rc && i < nr_calls; i++ ) ++ for ( i = 0; !rc && disp == mc_continue && i < nr_calls; i++ ) + { + if ( i && hypercall_preempt_check() ) + goto preempted; +@@ -63,7 +64,7 @@ do_multicall( + + trace_multicall_call(&mcs->call); + +- do_multicall_call(&mcs->call); ++ disp = do_multicall_call(&mcs->call); + + #ifndef NDEBUG + { +@@ -77,7 +78,14 @@ do_multicall( + } + #endif + +- if ( unlikely(__copy_field_to_guest(call_list, &mcs->call, result)) ) ++ if ( unlikely(disp == mc_exit) ) ++ { ++ if ( __copy_field_to_guest(call_list, &mcs->call, result) ) ++ /* nothing, best effort only */; ++ rc = mcs->call.result; ++ } ++ else if ( unlikely(__copy_field_to_guest(call_list, &mcs->call, ++ result)) ) + rc = -EFAULT; + else if ( mcs->flags & MCSF_call_preempted ) + { +@@ -93,6 +101,9 @@ do_multicall( + guest_handle_add_offset(call_list, 1); + } + ++ if ( unlikely(disp == mc_preempt) && i < nr_calls ) ++ goto preempted; ++ + perfc_incr(calls_to_multicall); + perfc_add(calls_from_multicall, i); + mcs->flags = 0; +--- a/xen/include/asm-arm/multicall.h ++++ b/xen/include/asm-arm/multicall.h +@@ -1,7 +1,11 @@ + #ifndef __ASM_ARM_MULTICALL_H__ + #define __ASM_ARM_MULTICALL_H__ + +-extern void do_multicall_call(struct multicall_entry *call); ++extern enum mc_disposition { ++ mc_continue, ++ mc_exit, ++ mc_preempt, ++} do_multicall_call(struct multicall_entry *call); + + #endif /* __ASM_ARM_MULTICALL_H__ */ + /* +--- a/xen/include/asm-x86/multicall.h ++++ b/xen/include/asm-x86/multicall.h +@@ -7,8 +7,21 @@ + + #include + ++enum mc_disposition { ++ mc_continue, ++ mc_exit, ++ mc_preempt, ++}; ++ ++#define multicall_ret(call) \ ++ (unlikely((call)->op == __HYPERVISOR_iret) \ ++ ? mc_exit \ ++ : likely(guest_kernel_mode(current, \ ++ guest_cpu_user_regs())) \ ++ ? mc_continue : mc_preempt) ++ + #define do_multicall_call(_call) \ +- do { \ ++ ({ \ + __asm__ __volatile__ ( \ + " movq %c1(%0),%%rax; " \ + " leaq hypercall_table(%%rip),%%rdi; " \ +@@ -37,9 +50,11 @@ + /* all the caller-saves registers */ \ + : "rax", "rcx", "rdx", "rsi", "rdi", \ + "r8", "r9", "r10", "r11" ); \ +- } while ( 0 ) ++ multicall_ret(_call); \ ++ }) + + #define compat_multicall_call(_call) \ ++ ({ \ + __asm__ __volatile__ ( \ + " movl %c1(%0),%%eax; " \ + " leaq compat_hypercall_table(%%rip),%%rdi; "\ +@@ -67,6 +82,8 @@ + "i" (-ENOSYS) \ + /* all the caller-saves registers */ \ + : "rax", "rcx", "rdx", "rsi", "rdi", \ +- "r8", "r9", "r10", "r11" ) \ ++ "r8", "r9", "r10", "r11" ); \ ++ multicall_ret(_call); \ ++ }) + + #endif /* __ASM_X86_MULTICALL_H__ */ diff --git a/xsa214.patch b/xsa214.patch new file mode 100644 index 0000000..46a3d3a --- /dev/null +++ b/xsa214.patch @@ -0,0 +1,41 @@ +From: Jan Beulich +Subject: x86: discard type information when stealing pages + +While a page having just a single general reference left necessarily +has a zero type reference count too, its type may still be valid (and +in validated state; at present this is only possible and relevant for +PGT_seg_desc_page, as page tables have their type forcibly zapped when +their type reference count drops to zero, and +PGT_{writable,shared}_page pages don't require any validation). In +such a case when the page is being re-used with the same type again, +validation is being skipped. As validation criteria differ between +32- and 64-bit guests, pages to be transferred between guests need to +have their validation indicator zapped (and with it we zap all other +type information at once). + +This is XSA-214. + +Reported-by: Jann Horn +Signed-off-by: Jan Beulich +Reviewed-by: Andrew Cooper + +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -4466,6 +4466,17 @@ int steal_page( + y = cmpxchg(&page->count_info, x, x & ~PGC_count_mask); + } while ( y != x ); + ++ /* ++ * With the sole reference dropped temporarily, no-one can update type ++ * information. Type count also needs to be zero in this case, but e.g. ++ * PGT_seg_desc_page may still have PGT_validated set, which we need to ++ * clear before transferring ownership (as validation criteria vary ++ * depending on domain type). ++ */ ++ BUG_ON(page->u.inuse.type_info & (PGT_count_mask | PGT_locked | ++ PGT_pinned)); ++ page->u.inuse.type_info = 0; ++ + /* Swizzle the owner then reinstate the PGC_allocated reference. */ + page_set_owner(page, NULL); + y = page->count_info;