All of lore.kernel.org
 help / color / mirror / Atom feed
* Xen Security Advisory 156 (CVE-2015-5307, CVE-2015-8104) - x86: CPU lockup during exception delivery
@ 2015-11-10  0:08 Xen.org security team
  0 siblings, 0 replies; only message in thread
From: Xen.org security team @ 2015-11-10  0:08 UTC (permalink / raw)
  To: xen-announce, xen-devel, xen-users, oss-security; +Cc: Xen.org security team

[-- Attachment #1: Type: text/plain, Size: 6885 bytes --]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

      Xen Security Advisory CVE-2015-5307,CVE-2015-8104 / XSA-156
                              version 2

              x86: CPU lockup during exception delivery

UPDATES IN VERSION 2
====================

Minor title and text adjustment.

CVE-2015-8104 has been assigned for the problem with #DB.
(The #AC issue remains CVE-2015-5307.)

Public release.

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

When a benign exception occurs while delivering another benign
exception, it is architecturally specified that these would be
delivered sequentially. There are, however, cases where this results in
an infinite loop inside the CPU, which (in the virtualized case) can be
broken only by intercepting delivery of the respective exception.

Architecturally, at least some of these cases should also be
resolvable by an arriving NMI or external interrupt, but empirically
this has been determined to not be the case.

The cases affecting Xen are:

#AC (Alignment Check Exception, CVE-2015-5307): When a 32-bit guest
sets up the IDT entry corresponding to this exception to reference a
ring-3 handler, and when ring 3 code triggers the exception while
running with an unaligned stack pointer, delivering the exception will
re-encounter #AC, ending in an infinite loop.

#DB (Debug Exception, CVE-2015-8104): When a guest sets up a hardware
breakpoint covering a data structure involved in delivering #DB, upon
completion of the delivery of the first exception another #DB will
need to be delivered. The effects slightly differ depending on further
guest characteristics:

- - Guests running in 32-bit mode would be expected to sooner or later
  encounter another fault due to the stack pointer decreasing during
  each iteration of the loop. The most likely case would be #PF (Page
  Fault) due to running into unmapped virtual space. However, an
  infinite loop cannot be excluded (e.g. when the guest is running with
  paging disabled).

- - Guests running in long mode, but not using the IST (Interrupt Stack
  Table) feature for the IDT entry corresponding to #DB would behave
  similarly to guests running in 32-bit mode, just that the larger
  virtual address space allows for a much longer loop. The loop can't,
  however, be infinite, as eventually the stack pointer would move into
  non-canonical address space, causing #SS (Stack Fault) instead.

- - Guests running in long mode and using IST for the IDT entry
  corresponding to #DB would enter an infinite loop, as the stack
  pointer wouldn't change between #DB instances.

IMPACT
======

A malicious HVM guest administrator can cause a denial of service.
Specifically, prevent use of a physical CPU for a significant, perhaps
indefinite period.

If a host watchdog (Xen or dom0) is in use, this can lead to a
watchdog timeout and consequently a reboot of the host.  If another,
innocent, guest, is configured with a watchdog, this issue can lead to
a reboot of such a guest.

It is possible that a guest kernel might expose the #AC vulnerability
to malicious unprivileged guest users (by permitting #AC to be handled
in guest user mode).  However, we believe that almost all ordinary
operating system kernels do not permit this; we are not aware of any
exceptions.  (A guest kernel which exposed the #AC vulnerability to
guest userspace would be vulnerable when running on baremetal, without
Xen involved.)


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

The vulnerability is exposed to any x86 HVM guest.

ARM is not vulnerable.  x86 PV VMs are not vulnerable.

All versions of Xen are affected.

x86 CPUs from all manufacturers are affected.

MITIGATION
==========

Running only PV guests will avoid this issue.

Running only kernels which avoid exposing the #AC problem to userspace
(as discussed in Impact) will prevent untrusted guest users from
exploiting this issue.

With such good kernels, the vulnerability can be avoided altogether if
the guest kernel is controlled by the host rather than guest
administrator, provided that further steps are taken to prevent the
guest administrator from loading code into the kernel (e.g. by
disabling loadable modules etc) or from using other mechanisms which
allow them to run code at kernel privilege.  In Xen HVM, controlling
the guest's kernel would involve locking down the bootloader.


CREDITS
=======

These issues were discovered by Ben Serebrin from Google and
Jan Beulich from SUSE.

RESOLUTION
==========

To correctly support the intended uses of the relevant CPU features
would require architectural changes to the CPU specification, design
and implementation.  This is not practical as a security response.

Applying the appropriate attached patch works around the issue in
software.

xsa156.patch        xen-unstable, Xen 4.6.x
xsa156-4.5.patch    Xen 4.5.x
xsa156-4.4.patch    Xen 4.4.x
xsa156-4.3.patch    Xen 4.3.x

$ sha256sum xsa156*.patch
ffc8153cdf4e69ff2feced6ea4988b594b5cb724e9909300209f9ae35fe0e618  xsa156-4.3.patch
c2001aed46840b044a066b9ca79a8c53aca26fc637125016ccfebafa5ace5475  xsa156-4.4.patch
af8edc5cfb2fe54d8c195b8748e80ffad0f32c37c50a16fa5005fec461cdb6ff  xsa156-4.5.patch
d92729ca9174f7d1d8c6fd31321d1a58696c0630e87420539c32f7718b9e8ee8  xsa156.patch
$


NOTE REGARDING EMBARGO DURATION
===============================

We have released this advisory as soon as possible after we obtained
firm confirmation of the embargo end date from the discoverer.


DEPLOYMENT DURING EMBARGO
=========================

Deployment of the patches and/or mitigations described above (or
others which are substantially similar) is permitted during the
embargo, even on public-facing systems with untrusted guest users and
administrators.

But: Distribution of updated software is prohibited (except to other
members of the predisclosure list).

Predisclosure list members who wish to deploy significantly different
patches and/or mitigations, please contact the Xen Project Security
Team.


(Note: this during-embargo deployment notice is retained in
post-embargo publicly released Xen Project advisories, even though it
is then no longer applicable.  This is to enable the community to have
oversight of the Xen Project Security Team's decisionmaking.)

For more information about permissible uses of embargoed information,
consult the Xen Project community's agreed Security Policy:
  http://www.xenproject.org/security-policy.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)

iQEcBAEBAgAGBQJWQTU6AAoJEIP+FMlX6CvZpQMH/iNmCRPVz4H54WdWgiRJuNZV
PrJFEITwxfOeaD84bQhxd0dXWqGnQvzPVScG5+qmWM6Bn533Gh2gkjKALHF8nltf
usAuIgiXcHC0jv5m9/Z7+9t62mJkfnVhq0qdz/UEFO2VM8GbWCCArpUStvb/GetS
sY7Rh1HV8p4nA5LOgvUgQc0yjCHoSfooyxkCNBBy31t5A33H4Se65pnKH/aRPH10
o4nX9NXxw2jN6XZ9bjACzm1KNPjDn1P5y/Zx5ccoHDQZHVYYHXMEgVSVnKEgriFL
xPaFe0Att3RfBQtj9HAZJEE8YNy74m+28/GMIoCWU2FCwY6R86dDoVHU5hKiWRc=
=z+MW
-----END PGP SIGNATURE-----

[-- Attachment #2: xsa156-4.3.patch --]
[-- Type: application/octet-stream, Size: 4897 bytes --]

x86/HVM: always intercept #AC and #DB

Both being benign exceptions, and both being possible to get triggered
by exception delivery, this is required to prevent a guest from locking
up a CPU (resulting from no other VM exits occurring once getting into
such a loop).

The specific scenarios:

1) #AC may be raised during exception delivery if the handler is set to
be a ring-3 one by a 32-bit guest, and the stack is misaligned.

2) #DB may be raised during exception delivery when a breakpoint got
placed on a data structure involved in delivering the exception. This
can result in an endless loop when a 64-bit guest uses a non-zero IST
for the vector 1 IDT entry, but even without use of IST the time it
takes until a contributory fault would get raised (results depending
on the handler) may be quite long.

This is XSA-156.

Reported-by: Benjamin Serebrin <serebrin@google.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Tested-by: Andrew Cooper <andrew.cooper3@citrix.com>

--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -941,10 +941,11 @@ static void svm_do_resume(struct vcpu *v
         unlikely(v->arch.hvm_vcpu.debug_state_latch != debug_state) )
     {
         uint32_t intercepts = vmcb_get_exception_intercepts(vmcb);
-        uint32_t mask = (1U << TRAP_debug) | (1U << TRAP_int3);
+
         v->arch.hvm_vcpu.debug_state_latch = debug_state;
         vmcb_set_exception_intercepts(
-            vmcb, debug_state ? (intercepts | mask) : (intercepts & ~mask));
+            vmcb, debug_state ? (intercepts | (1U << TRAP_int3))
+                              : (intercepts & ~(1U << TRAP_int3)));
     }
 
     if ( v->arch.hvm_svm.launch_core != smp_processor_id() )
@@ -2223,8 +2224,9 @@ void svm_vmexit_handler(struct cpu_user_
 
     case VMEXIT_EXCEPTION_DB:
         if ( !v->domain->debugger_attached )
-            goto unexpected_exit_type;
-        domain_pause_for_debugger();
+            hvm_inject_hw_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE);
+        else
+            domain_pause_for_debugger();
         break;
 
     case VMEXIT_EXCEPTION_BP:
@@ -2272,6 +2274,11 @@ void svm_vmexit_handler(struct cpu_user_
         break;
     }
 
+    case VMEXIT_EXCEPTION_AC:
+        HVMTRACE_1D(TRAP, TRAP_alignment_check);
+        hvm_inject_hw_exception(TRAP_alignment_check, vmcb->exitinfo1);
+        break;
+
     case VMEXIT_EXCEPTION_UD:
         svm_vmexit_ud_intercept(regs);
         break;
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1122,18 +1122,12 @@ static void vmx_update_host_cr3(struct v
 
 void vmx_update_debug_state(struct vcpu *v)
 {
-    unsigned long mask;
-
     ASSERT(v == current);
 
-    mask = 1u << TRAP_int3;
-    if ( !cpu_has_monitor_trap_flag )
-        mask |= 1u << TRAP_debug;
-
     if ( v->arch.hvm_vcpu.debug_state_latch )
-        v->arch.hvm_vmx.exception_bitmap |= mask;
+        v->arch.hvm_vmx.exception_bitmap |= 1U << TRAP_int3;
     else
-        v->arch.hvm_vmx.exception_bitmap &= ~mask;
+        v->arch.hvm_vmx.exception_bitmap &= ~(1U << TRAP_int3);
     vmx_update_exception_bitmap(v);
 }
 
@@ -2616,9 +2610,10 @@ void vmx_vmexit_handler(struct cpu_user_
             exit_qualification = __vmread(EXIT_QUALIFICATION);
             HVMTRACE_1D(TRAP_DEBUG, exit_qualification);
             write_debugreg(6, exit_qualification | 0xffff0ff0);
-            if ( !v->domain->debugger_attached || cpu_has_monitor_trap_flag )
-                goto exit_and_crash;
-            domain_pause_for_debugger();
+            if ( !v->domain->debugger_attached )
+                hvm_inject_hw_exception(vector, HVM_DELIVER_NO_ERROR_CODE);
+            else
+                domain_pause_for_debugger();
             break;
         case TRAP_int3: 
         {
@@ -2679,6 +2674,11 @@ void vmx_vmexit_handler(struct cpu_user_
 
             hvm_inject_page_fault(regs->error_code, exit_qualification);
             break;
+        case TRAP_alignment_check:
+            HVMTRACE_1D(TRAP, vector);
+            hvm_inject_hw_exception(vector,
+                                    __vmread(VM_EXIT_INTR_ERROR_CODE));
+            break;
         case TRAP_nmi:
             if ( (intr_info & INTR_INFO_INTR_TYPE_MASK) !=
                  (X86_EVENTTYPE_NMI << 8) )
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -389,7 +389,10 @@ static inline bool_t hvm_vcpu_has_smep(v
 })
 
 /* These exceptions must always be intercepted. */
-#define HVM_TRAP_MASK ((1U << TRAP_machine_check) | (1U << TRAP_invalid_op))
+#define HVM_TRAP_MASK ((1U << TRAP_debug)           | \
+                       (1U << TRAP_invalid_op)      | \
+                       (1U << TRAP_alignment_check) | \
+                       (1U << TRAP_machine_check))
 
 /*
  * x86 event types. This enumeration is valid for:

[-- Attachment #3: xsa156-4.4.patch --]
[-- Type: application/octet-stream, Size: 4880 bytes --]

x86/HVM: always intercept #AC and #DB

Both being benign exceptions, and both being possible to get triggered
by exception delivery, this is required to prevent a guest from locking
up a CPU (resulting from no other VM exits occurring once getting into
such a loop).

The specific scenarios:

1) #AC may be raised during exception delivery if the handler is set to
be a ring-3 one by a 32-bit guest, and the stack is misaligned.

2) #DB may be raised during exception delivery when a breakpoint got
placed on a data structure involved in delivering the exception. This
can result in an endless loop when a 64-bit guest uses a non-zero IST
for the vector 1 IDT entry, but even without use of IST the time it
takes until a contributory fault would get raised (results depending
on the handler) may be quite long.

This is XSA-156.

Reported-by: Benjamin Serebrin <serebrin@google.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Tested-by: Andrew Cooper <andrew.cooper3@citrix.com>

--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -941,10 +941,11 @@ static void noreturn svm_do_resume(struc
         unlikely(v->arch.hvm_vcpu.debug_state_latch != debug_state) )
     {
         uint32_t intercepts = vmcb_get_exception_intercepts(vmcb);
-        uint32_t mask = (1U << TRAP_debug) | (1U << TRAP_int3);
+
         v->arch.hvm_vcpu.debug_state_latch = debug_state;
         vmcb_set_exception_intercepts(
-            vmcb, debug_state ? (intercepts | mask) : (intercepts & ~mask));
+            vmcb, debug_state ? (intercepts | (1U << TRAP_int3))
+                              : (intercepts & ~(1U << TRAP_int3)));
     }
 
     if ( v->arch.hvm_svm.launch_core != smp_processor_id() )
@@ -2225,8 +2226,9 @@ void svm_vmexit_handler(struct cpu_user_
 
     case VMEXIT_EXCEPTION_DB:
         if ( !v->domain->debugger_attached )
-            goto unexpected_exit_type;
-        domain_pause_for_debugger();
+            hvm_inject_hw_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE);
+        else
+            domain_pause_for_debugger();
         break;
 
     case VMEXIT_EXCEPTION_BP:
@@ -2274,6 +2276,11 @@ void svm_vmexit_handler(struct cpu_user_
         break;
     }
 
+    case VMEXIT_EXCEPTION_AC:
+        HVMTRACE_1D(TRAP, TRAP_alignment_check);
+        hvm_inject_hw_exception(TRAP_alignment_check, vmcb->exitinfo1);
+        break;
+
     case VMEXIT_EXCEPTION_UD:
         svm_vmexit_ud_intercept(regs);
         break;
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1132,16 +1132,10 @@ static void vmx_update_host_cr3(struct v
 
 void vmx_update_debug_state(struct vcpu *v)
 {
-    unsigned long mask;
-
-    mask = 1u << TRAP_int3;
-    if ( !cpu_has_monitor_trap_flag )
-        mask |= 1u << TRAP_debug;
-
     if ( v->arch.hvm_vcpu.debug_state_latch )
-        v->arch.hvm_vmx.exception_bitmap |= mask;
+        v->arch.hvm_vmx.exception_bitmap |= 1U << TRAP_int3;
     else
-        v->arch.hvm_vmx.exception_bitmap &= ~mask;
+        v->arch.hvm_vmx.exception_bitmap &= ~(1U << TRAP_int3);
 
     vmx_vmcs_enter(v);
     vmx_update_exception_bitmap(v);
@@ -2678,9 +2672,10 @@ void vmx_vmexit_handler(struct cpu_user_
             __vmread(EXIT_QUALIFICATION, &exit_qualification);
             HVMTRACE_1D(TRAP_DEBUG, exit_qualification);
             write_debugreg(6, exit_qualification | 0xffff0ff0);
-            if ( !v->domain->debugger_attached || cpu_has_monitor_trap_flag )
-                goto exit_and_crash;
-            domain_pause_for_debugger();
+            if ( !v->domain->debugger_attached )
+                hvm_inject_hw_exception(vector, HVM_DELIVER_NO_ERROR_CODE);
+            else
+                domain_pause_for_debugger();
             break;
         case TRAP_int3: 
         {
@@ -2745,6 +2740,11 @@ void vmx_vmexit_handler(struct cpu_user_
 
             hvm_inject_page_fault(regs->error_code, exit_qualification);
             break;
+        case TRAP_alignment_check:
+            HVMTRACE_1D(TRAP, vector);
+            __vmread(VM_EXIT_INTR_ERROR_CODE, &ecode);
+            hvm_inject_hw_exception(vector, ecode);
+            break;
         case TRAP_nmi:
             if ( (intr_info & INTR_INFO_INTR_TYPE_MASK) !=
                  (X86_EVENTTYPE_NMI << 8) )
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -393,7 +393,10 @@ static inline int hvm_event_pending(stru
 })
 
 /* These exceptions must always be intercepted. */
-#define HVM_TRAP_MASK ((1U << TRAP_machine_check) | (1U << TRAP_invalid_op))
+#define HVM_TRAP_MASK ((1U << TRAP_debug)           | \
+                       (1U << TRAP_invalid_op)      | \
+                       (1U << TRAP_alignment_check) | \
+                       (1U << TRAP_machine_check))
 
 /*
  * x86 event types. This enumeration is valid for:

[-- Attachment #4: xsa156-4.5.patch --]
[-- Type: application/octet-stream, Size: 4927 bytes --]

x86/HVM: always intercept #AC and #DB

Both being benign exceptions, and both being possible to get triggered
by exception delivery, this is required to prevent a guest from locking
up a CPU (resulting from no other VM exits occurring once getting into
such a loop).

The specific scenarios:

1) #AC may be raised during exception delivery if the handler is set to
be a ring-3 one by a 32-bit guest, and the stack is misaligned.

2) #DB may be raised during exception delivery when a breakpoint got
placed on a data structure involved in delivering the exception. This
can result in an endless loop when a 64-bit guest uses a non-zero IST
for the vector 1 IDT entry, but even without use of IST the time it
takes until a contributory fault would get raised (results depending
on the handler) may be quite long.

This is XSA-156.

Reported-by: Benjamin Serebrin <serebrin@google.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Tested-by: Andrew Cooper <andrew.cooper3@citrix.com>

--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -1045,10 +1045,11 @@ static void noreturn svm_do_resume(struc
         unlikely(v->arch.hvm_vcpu.debug_state_latch != debug_state) )
     {
         uint32_t intercepts = vmcb_get_exception_intercepts(vmcb);
-        uint32_t mask = (1U << TRAP_debug) | (1U << TRAP_int3);
+
         v->arch.hvm_vcpu.debug_state_latch = debug_state;
         vmcb_set_exception_intercepts(
-            vmcb, debug_state ? (intercepts | mask) : (intercepts & ~mask));
+            vmcb, debug_state ? (intercepts | (1U << TRAP_int3))
+                              : (intercepts & ~(1U << TRAP_int3)));
     }
 
     if ( v->arch.hvm_svm.launch_core != smp_processor_id() )
@@ -2435,8 +2436,9 @@ void svm_vmexit_handler(struct cpu_user_
 
     case VMEXIT_EXCEPTION_DB:
         if ( !v->domain->debugger_attached )
-            goto unexpected_exit_type;
-        domain_pause_for_debugger();
+            hvm_inject_hw_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE);
+        else
+            domain_pause_for_debugger();
         break;
 
     case VMEXIT_EXCEPTION_BP:
@@ -2484,6 +2486,11 @@ void svm_vmexit_handler(struct cpu_user_
         break;
     }
 
+    case VMEXIT_EXCEPTION_AC:
+        HVMTRACE_1D(TRAP, TRAP_alignment_check);
+        hvm_inject_hw_exception(TRAP_alignment_check, vmcb->exitinfo1);
+        break;
+
     case VMEXIT_EXCEPTION_UD:
         svm_vmexit_ud_intercept(regs);
         break;
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1186,16 +1186,10 @@ static void vmx_update_host_cr3(struct v
 
 void vmx_update_debug_state(struct vcpu *v)
 {
-    unsigned long mask;
-
-    mask = 1u << TRAP_int3;
-    if ( !cpu_has_monitor_trap_flag )
-        mask |= 1u << TRAP_debug;
-
     if ( v->arch.hvm_vcpu.debug_state_latch )
-        v->arch.hvm_vmx.exception_bitmap |= mask;
+        v->arch.hvm_vmx.exception_bitmap |= 1U << TRAP_int3;
     else
-        v->arch.hvm_vmx.exception_bitmap &= ~mask;
+        v->arch.hvm_vmx.exception_bitmap &= ~(1U << TRAP_int3);
 
     vmx_vmcs_enter(v);
     vmx_update_exception_bitmap(v);
@@ -2801,9 +2795,10 @@ void vmx_vmexit_handler(struct cpu_user_
             __vmread(EXIT_QUALIFICATION, &exit_qualification);
             HVMTRACE_1D(TRAP_DEBUG, exit_qualification);
             write_debugreg(6, exit_qualification | 0xffff0ff0);
-            if ( !v->domain->debugger_attached || cpu_has_monitor_trap_flag )
-                goto exit_and_crash;
-            domain_pause_for_debugger();
+            if ( !v->domain->debugger_attached )
+                hvm_inject_hw_exception(vector, HVM_DELIVER_NO_ERROR_CODE);
+            else
+                domain_pause_for_debugger();
             break;
         case TRAP_int3: 
         {
@@ -2868,6 +2863,11 @@ void vmx_vmexit_handler(struct cpu_user_
 
             hvm_inject_page_fault(regs->error_code, exit_qualification);
             break;
+        case TRAP_alignment_check:
+            HVMTRACE_1D(TRAP, vector);
+            __vmread(VM_EXIT_INTR_ERROR_CODE, &ecode);
+            hvm_inject_hw_exception(vector, ecode);
+            break;
         case TRAP_nmi:
             if ( (intr_info & INTR_INFO_INTR_TYPE_MASK) !=
                  (X86_EVENTTYPE_NMI << 8) )
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -378,7 +378,10 @@ static inline int hvm_event_pending(stru
     (X86_CR4_VMXE | X86_CR4_PAE | X86_CR4_MCE))
 
 /* These exceptions must always be intercepted. */
-#define HVM_TRAP_MASK ((1U << TRAP_machine_check) | (1U << TRAP_invalid_op))
+#define HVM_TRAP_MASK ((1U << TRAP_debug)           | \
+                       (1U << TRAP_invalid_op)      | \
+                       (1U << TRAP_alignment_check) | \
+                       (1U << TRAP_machine_check))
 
 /*
  * x86 event types. This enumeration is valid for:

[-- Attachment #5: xsa156.patch --]
[-- Type: application/octet-stream, Size: 4940 bytes --]

x86/HVM: always intercept #AC and #DB

Both being benign exceptions, and both being possible to get triggered
by exception delivery, this is required to prevent a guest from locking
up a CPU (resulting from no other VM exits occurring once getting into
such a loop).

The specific scenarios:

1) #AC may be raised during exception delivery if the handler is set to
be a ring-3 one by a 32-bit guest, and the stack is misaligned.

2) #DB may be raised during exception delivery when a breakpoint got
placed on a data structure involved in delivering the exception. This
can result in an endless loop when a 64-bit guest uses a non-zero IST
for the vector 1 IDT entry, but even without use of IST the time it
takes until a contributory fault would get raised (results depending
on the handler) may be quite long.

This is XSA-156.

Reported-by: Benjamin Serebrin <serebrin@google.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Tested-by: Andrew Cooper <andrew.cooper3@citrix.com>

--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -1043,10 +1043,11 @@ static void noreturn svm_do_resume(struc
         unlikely(v->arch.hvm_vcpu.debug_state_latch != debug_state) )
     {
         uint32_t intercepts = vmcb_get_exception_intercepts(vmcb);
-        uint32_t mask = (1U << TRAP_debug) | (1U << TRAP_int3);
+
         v->arch.hvm_vcpu.debug_state_latch = debug_state;
         vmcb_set_exception_intercepts(
-            vmcb, debug_state ? (intercepts | mask) : (intercepts & ~mask));
+            vmcb, debug_state ? (intercepts | (1U << TRAP_int3))
+                              : (intercepts & ~(1U << TRAP_int3)));
     }
 
     if ( v->arch.hvm_svm.launch_core != smp_processor_id() )
@@ -2434,8 +2435,9 @@ void svm_vmexit_handler(struct cpu_user_
 
     case VMEXIT_EXCEPTION_DB:
         if ( !v->domain->debugger_attached )
-            goto unexpected_exit_type;
-        domain_pause_for_debugger();
+            hvm_inject_hw_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE);
+        else
+            domain_pause_for_debugger();
         break;
 
     case VMEXIT_EXCEPTION_BP:
@@ -2483,6 +2485,11 @@ void svm_vmexit_handler(struct cpu_user_
         break;
     }
 
+    case VMEXIT_EXCEPTION_AC:
+        HVMTRACE_1D(TRAP, TRAP_alignment_check);
+        hvm_inject_hw_exception(TRAP_alignment_check, vmcb->exitinfo1);
+        break;
+
     case VMEXIT_EXCEPTION_UD:
         svm_vmexit_ud_intercept(regs);
         break;
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1224,16 +1224,10 @@ static void vmx_update_host_cr3(struct v
 
 void vmx_update_debug_state(struct vcpu *v)
 {
-    unsigned long mask;
-
-    mask = 1u << TRAP_int3;
-    if ( !cpu_has_monitor_trap_flag )
-        mask |= 1u << TRAP_debug;
-
     if ( v->arch.hvm_vcpu.debug_state_latch )
-        v->arch.hvm_vmx.exception_bitmap |= mask;
+        v->arch.hvm_vmx.exception_bitmap |= 1U << TRAP_int3;
     else
-        v->arch.hvm_vmx.exception_bitmap &= ~mask;
+        v->arch.hvm_vmx.exception_bitmap &= ~(1U << TRAP_int3);
 
     vmx_vmcs_enter(v);
     vmx_update_exception_bitmap(v);
@@ -3060,9 +3054,10 @@ void vmx_vmexit_handler(struct cpu_user_
             __vmread(EXIT_QUALIFICATION, &exit_qualification);
             HVMTRACE_1D(TRAP_DEBUG, exit_qualification);
             write_debugreg(6, exit_qualification | DR_STATUS_RESERVED_ONE);
-            if ( !v->domain->debugger_attached || cpu_has_monitor_trap_flag )
-                goto exit_and_crash;
-            domain_pause_for_debugger();
+            if ( !v->domain->debugger_attached )
+                hvm_inject_hw_exception(vector, HVM_DELIVER_NO_ERROR_CODE);
+            else
+                domain_pause_for_debugger();
             break;
         case TRAP_int3: 
         {
@@ -3127,6 +3122,11 @@ void vmx_vmexit_handler(struct cpu_user_
 
             hvm_inject_page_fault(regs->error_code, exit_qualification);
             break;
+        case TRAP_alignment_check:
+            HVMTRACE_1D(TRAP, vector);
+            __vmread(VM_EXIT_INTR_ERROR_CODE, &ecode);
+            hvm_inject_hw_exception(vector, ecode);
+            break;
         case TRAP_nmi:
             if ( MASK_EXTR(intr_info, INTR_INFO_INTR_TYPE_MASK) !=
                  X86_EVENTTYPE_NMI )
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -385,7 +385,10 @@ static inline int hvm_event_pending(stru
     (X86_CR4_VMXE | X86_CR4_PAE | X86_CR4_MCE))
 
 /* These exceptions must always be intercepted. */
-#define HVM_TRAP_MASK ((1U << TRAP_machine_check) | (1U << TRAP_invalid_op))
+#define HVM_TRAP_MASK ((1U << TRAP_debug)           | \
+                       (1U << TRAP_invalid_op)      | \
+                       (1U << TRAP_alignment_check) | \
+                       (1U << TRAP_machine_check))
 
 /*
  * x86 event types. This enumeration is valid for:

[-- Attachment #6: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2015-11-10  0:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-10  0:08 Xen Security Advisory 156 (CVE-2015-5307, CVE-2015-8104) - x86: CPU lockup during exception delivery Xen.org security team

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.