diff options
author | Jan Beulich <jbeulich@suse.com> | 2013-04-18 16:18:42 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2013-04-18 16:18:42 +0200 |
commit | 68a30a91bad2d4ff1f7c0d4302ec1060d573f6da (patch) | |
tree | 858b96abf3b49f9ba73647e43cba4d0114ee5a3f | |
parent | 2d03bb04de8718bb6519ab3023db22c80ffd0360 (diff) | |
download | xen-68a30a91bad2d4ff1f7c0d4302ec1060d573f6da.tar.gz xen-68a30a91bad2d4ff1f7c0d4302ec1060d573f6da.tar.bz2 xen-68a30a91bad2d4ff1f7c0d4302ec1060d573f6da.zip |
x86: clear EFLAGS.NT in SYSENTER entry path
... as it causes problems if we happen to exit back via IRET: In the
course of trying to handle the fault, the hypervisor creates a stack
frame by hand, and uses PUSHFQ to set the respective EFLAGS field, but
expects to be able to IRET through that stack frame to the second
portion of the fixup code (which causes a #GP due to the stored EFLAGS
having NT set).
And even if this worked (e.g if we cleared NT in that path), it would
then (through the fail safe callback) cause a #GP in the guest with the
SYSENTER handler's first instruction as the source, which in turn would
allow guest user mode code to crash the guest kernel.
Inject a #GP on the fake (NULL) address of the SYSENTER instruction
instead, just like in the case where the guest kernel didn't register
a corresponding entry point.
This is CVE-2013-1917 / XSA-44.
Reported-by: Andrew Cooper <andrew.cooper3@citirx.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
master commit: fdac9515607b757c044e7ef0d61b1453ef999b08
master date: 2013-04-18 16:00:35 +0200
-rw-r--r-- | xen/arch/x86/acpi/suspend.c | 8 | ||||
-rw-r--r-- | xen/arch/x86/cpu/common.c | 5 | ||||
-rw-r--r-- | xen/arch/x86/x86_64/entry.S | 7 |
3 files changed, 17 insertions, 3 deletions
diff --git a/xen/arch/x86/acpi/suspend.c b/xen/arch/x86/acpi/suspend.c index d13bed0c6b..f2e21337ad 100644 --- a/xen/arch/x86/acpi/suspend.c +++ b/xen/arch/x86/acpi/suspend.c @@ -81,8 +81,12 @@ void restore_rest_processor_state(void) } #else /* !defined(CONFIG_X86_64) */ - if ( supervisor_mode_kernel && cpu_has_sep ) - wrmsr(MSR_IA32_SYSENTER_ESP, &this_cpu(init_tss).esp1, 0); + if ( cpu_has_sep ) + { + wrmsr(MSR_IA32_SYSENTER_CS, 0, 0); + if ( supervisor_mode_kernel ) + wrmsr(MSR_IA32_SYSENTER_ESP, &this_cpu(init_tss).esp1, 0); + } #endif /* Maybe load the debug registers. */ diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c index a28781643b..321d942fbe 100644 --- a/xen/arch/x86/cpu/common.c +++ b/xen/arch/x86/cpu/common.c @@ -655,8 +655,11 @@ void __cpuinit cpu_init(void) #if defined(CONFIG_X86_32) t->ss0 = __HYPERVISOR_DS; t->esp0 = get_stack_bottom(); - if ( supervisor_mode_kernel && cpu_has_sep ) + if ( cpu_has_sep ) { + wrmsr(MSR_IA32_SYSENTER_CS, 0, 0); + if ( supervisor_mode_kernel ) wrmsr(MSR_IA32_SYSENTER_ESP, &t->esp1, 0); + } #elif defined(CONFIG_X86_64) /* Bottom-of-stack must be 16-byte aligned! */ BUG_ON((get_stack_bottom() & 15) != 0); diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 8390db2ee6..c606599edd 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -285,7 +285,14 @@ sysenter_eflags_saved: cmpb $0,VCPU_sysenter_disables_events(%rbx) movq VCPU_sysenter_addr(%rbx),%rax setne %cl + testl $X86_EFLAGS_NT,UREGS_eflags(%rsp) leaq VCPU_trap_bounce(%rbx),%rdx +UNLIKELY_START(nz, sysenter_nt_set) + pushfq + andl $~X86_EFLAGS_NT,(%rsp) + popfq + xorl %eax,%eax +UNLIKELY_END(sysenter_nt_set) testq %rax,%rax leal (,%rcx,TBF_INTERRUPT),%ecx UNLIKELY_START(z, sysenter_gpf) |