Quantcast
Channel: BOT24
Viewing all articles
Browse latest Browse all 8064

Article 11

$
0
0

  Xen Security Advisory CVE-2013-1917 / XSA-44
                              version 3

                Xen PV DoS vulnerability with SYSENTER

UPDATES IN VERSION 3
====================

Backported patch for 4.0 now available.

ISSUE DESCRIPTION
=================

The SYSENTER instruction can be used by PV guests to accelerate system
call processing. This instruction, however, leaves the EFLAGS register
mostly unmodified - in particular, the NT flag doesn't get cleared. If
the hypervisor subsequently uses IRET to return to the guest (which it
will always do if the guest is a 32-bit one), that instruction will
cause a #GP fault to be raised, but the recovery code in the
hypervisor will again try to use IRET without intermediately clearing
the NT flag. The #GP fault raised on this second IRET is a fatal
event, causing the hypervisor to crash.

IMPACT
======

Malicious or buggy unprivileged user space can cause the entire host to crash.

VULNERABLE SYSTEMS
==================

All 64-bit Xen versions from 3.1 onwards running on Intel CPUs are
vulnerable.  32-bit Xen is not affected, as it doesn't permit the use
of SYSENTER by PV guests. 64-bit Xen run on AMD CPUs isn't affected
since AMD CPUs don't allow the use of SYSENTER in long mode.

The vulnerability is only exposed by PV guests.

MITIGATION
==========

Running only HVM guests, or running PV guests on only 32-bit hosts or only AMD
CPUs will avoid this vulnerability.

RESOLUTION
==========

Applying the appropriate attached patch resolves this issue.

xsa44-4.0.patch             Xen 4.0.x
xsa44-4.1.patch             Xen 4.1.x
xsa44-4.2.patch             Xen 4.2.x
xsa44-unstable.patch        xen-unstable

$ sha256sum xsa44*.patch
4de554d29adbae41a65d401becd9d074be27932ad9f3e0ed78ecb89de3ed35b5  xsa44-4.0.patch
3dbf47224be0f8fc66ba08d8a46b910bd9a3e672ffe864aa77c698bef0e27783  xsa44-4.1.patch
c6c3afa228426d78e0484b7ac34210f642f79add35c4a04ca5ff7db5f2539e49  xsa44-4.2.patch
0e6ad83da75dc207a165411844c0985fd7f9588d92c2c95911c245485351bf36  xsa44-unstable.patch
$

xsa44-4.0.patch
Description:

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.

On 32-bit we also need to make sure we clear SYSENTER_CS for all CPUs
(neither #RESET nor #INIT guarantee this).

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>
Signed-off-by: Ian Campbell <Ian.Campbell@citrix.com>

diff --git a/xen/arch/x86/acpi/suspend.c b/xen/arch/x86/acpi/suspend.c
index ddddbc8..7819b30 100644
--- a/xen/arch/x86/acpi/suspend.c
+++ b/xen/arch/x86/acpi/suspend.c
@@ -59,8 +59,12 @@ void restore_rest_processor_state(void)
         wrmsr(MSR_IA32_SYSENTER_CS, __HYPERVISOR_CS, 0);
     }
 #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 eda7534..cb3a7c2 100644
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -623,8 +623,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 9e9db33..e4c0fde 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -300,7 +300,14 @@ sysenter_eflags_saved:
         movl  $3,UREGS_cs(%rsp)  /* ring 3 null cs */
         movq  VCPU_sysenter_addr(%rbx),%rax
         setne %cl
+        testl $X86_EFLAGS_NT,UREGS_eflags(%rsp)
         leaq  VCPU_trap_bounce(%rbx),%rdx
+jz    sysenter_nt_not_set
+        pushfq
+        andl  $~X86_EFLAGS_NT,(%rsp)
+        popfq
+        xorl  %eax,%eax
+sysenter_nt_not_set:
         testq %rax,%rax
         leal  (,%rcx,TBF_INTERRUPT),%ecx
         jz    2f


xsa44-4.1.patch
Description:

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.

On 32-bit we also need to make sure we clear SYSENTER_CS for all CPUs
(neither #RESET nor #INIT guarantee this).

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>

--- 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. */
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -715,8 +715,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);
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -287,7 +287,14 @@ sysenter_eflags_saved:
         movl  $3,UREGS_cs(%rsp)  /* ring 3 null cs */
         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)


xsa44-4.2.patch
Description:


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.

On 32-bit we also need to make sure we clear SYSENTER_CS for all CPUs
(neither #RESET nor #INIT guarantee this).

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>

--- 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. */
--- 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);
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -284,7 +284,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)


xsa44-unstable.patch
Description:


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>

--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -281,7 +281,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)


Viewing all articles
Browse latest Browse all 8064

Trending Articles