All of lore.kernel.org
 help / color / mirror / Atom feed
* Xen Security Advisory 204 - x86: Mishandling of SYSCALL singlestep during emulation
@ 2016-12-19 15:37 Xen.org security team
  0 siblings, 0 replies; only message in thread
From: Xen.org security team @ 2016-12-19 15:37 UTC (permalink / raw)
  To: xen-announce, xen-devel, xen-users, oss-security; +Cc: Xen.org security team

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

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

                    Xen Security Advisory XSA-204

        x86: Mishandling of SYSCALL singlestep during emulation

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

The typical behaviour of singlestepping exceptions is determined at the
start of the instruction, with a #DB trap being raised at the end of the
instruction.

SYSCALL (and SYSRET, although we don't implement it) behave differently
because the typical behaviour allows userspace to escalate its
privilege.  (This difference in behaviour seems to be undocumented.)

Xen wrongly raised the exception based on the flags at the start of
the instruction.

IMPACT
======

Guest userspace which can invoke the instruction emulator can use this
flaw to escalate its privilege to that of the guest kernel.

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

All Xen versions are affected.

The vulnerability is only exposed to 64-bit x86 HVM guests.

On Xen 4.6 and earlier the vulnerability is exposed to all guest user
processes, including unprivileged processes, in such guests.

On Xen 4.7 and later, the vulnerability is exposed only to guest user
processes granted a degree of privilege (such as direct hardware access)
by the guest administrator; or, to all user processes when the VM has
been explicitly configured with a non-default cpu vendor string (in
xm/xl, this would be done with a `cpuid=' domain config option).

A 64-bit guest kernel which uses an IST for #DB handling will most likely
mitigate the issue, but will have a single unexpected #DB exception
frame to deal with.  This in practice means that Linux is not
vulnerable.

The vulnerability is not exposed to 32-bit HVM guests.  This is because
the emulation bug also matches real hardware behaviour, and a 32-bit
guest kernel using SYSCALL will already have to be using a Task Gate for
handling #DB to avoid being susceptible to an escalation of privilege.

The vulnerability is not exposed to PV guests.

ARM systems are not vulnerable.

MITIGATION
==========

There is no known mitigation.

RESOLUTION
==========

Applying the appropriate attached patch resolves this issue.

xsa204.patch           xen-unstable
xsa204-4.8.patch       Xen 4.8.x
xsa204-4.7.patch       Xen 4.7.x, Xen 4.6.x
xsa204-4.5.patch       Xen 4.5.x, Xen 4.4.x

$ sha256sum xsa204*
251c33905f86d386cc07240041108ec0664e5e9dddb2b88685d9b4b8ca7fdc24  xsa204.patch
e523b65ba122c8e22d32004d2035facaf06295094fdc8b67c151b6f44799ef0b  xsa204-4.5.patch
d0359f26e9be783672896200e14d85a3111c29d7da580313b593fca04688fef2  xsa204-4.7.patch
fa2a69682868104b6263655abbfc6b326f76deebdac3273b4b65da6673f5d977  xsa204-4.8.patch
$

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

This issue was discussed publicly on qemu-devel before its impact was
realised.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBAgAGBQJYV/5uAAoJEIP+FMlX6CvZnxgIAMXcpEN0qejTe50dAP/gSzzP
edi76o/LNGaQBdFRVLvIasRna2TZSXhBNbHPEcAQLPq6pTfQG/HiqdVtftaaaoaG
dvNhuDBdZaa1/fmhCV1P+t9vaipp3U3yK2s0eiSJLXp3nGqkgjSSmZloYY0bevDN
DJ0uZ7uWkvyN6Tkl6R/h3h9PsgIKPIQBIyBuT2zYPf/JAjBD27ZYX11F9JvVMmt3
JH/AbvJwUsaqNG3teLg+tioQPwHwkZCdxOhG+v2Y3CeqQ1bvNCb5emLtpXFO9h0w
kZNh88gT1mwbxDWbF3Ek/OhHbOHosfxi9kn8ib5Yu0P8xRmvYhQHMeQDa/rt9Y0=
=OVcU
-----END PGP SIGNATURE-----

[-- Attachment #2: xsa204.patch --]
[-- Type: application/octet-stream, Size: 2719 bytes --]

From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Sun, 18 Dec 2016 15:42:59 +0000
Subject: [PATCH] x86/emul: Correct the handling of eflags with SYSCALL

A singlestep #DB is determined by the resulting eflags value from the
execution of SYSCALL, not the original eflags value.

By using the original eflags value, we negate the guest kernels attempt to
protect itself from a privilege escalation by masking TF.

(re)introduce a singlestep boolean, defaulting to the original eflags state,
but have the SYSCALL emulation recalculate it after masking has occurred.

This is XSA-204

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 xen/arch/x86/x86_emulate/x86_emulate.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c
index f69dece..165eebb 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -2502,6 +2502,7 @@ x86_emulate(
     struct x86_emulate_state state;
     int rc;
     uint8_t b, d;
+    bool singlestep = ctxt->regs->eflags & EFLG_TF;
     struct operand src = { .reg = PTR_POISON };
     struct operand dst = { .reg = PTR_POISON };
     enum x86_swint_type swint_type;
@@ -4678,6 +4679,23 @@ x86_emulate(
              (rc = ops->write_segment(x86_seg_ss, &sreg, ctxt)) )
             goto done;
 
+        /*
+         * SYSCALL (unlike most instructions) evaluates its singlestep action
+         * based on the resulting EFLG_TF, not the starting EFLG_TF.
+         *
+         * As the #DB is raised after the CPL change and before the OS can
+         * switch stack, it is a large risk for privilege escalation.
+         *
+         * 64bit kernels should mask EFLG_TF in MSR_FMASK to avoid any
+         * vulnerability.  Running the #DB handler on an IST stack is also a
+         * mitigation.
+         *
+         * 32bit kernels have no ability to mask EFLG_TF at all.  Their only
+         * mitigation is to use a task gate for handling #DB (or to not use
+         * enable EFER.SCE to start with).
+         */
+        singlestep = _regs.eflags & EFLG_TF;
+
         break;
     }
 
@@ -5580,9 +5598,9 @@ x86_emulate(
     if ( !mode_64bit() )
         _regs.eip = (uint32_t)_regs.eip;
 
-    /* Was singestepping active at the start of this instruction? */
-    if ( (rc == X86EMUL_OKAY) && (ctxt->regs->eflags & EFLG_TF) )
-        ctxt->retire.singlestep = true;
+    /* Should a singlestep #DB be raised? */
+    if ( rc == X86EMUL_OKAY )
+        ctxt->retire.singlestep = singlestep;
 
     if ( rc != X86EMUL_DONE )
         *ctxt->regs = _regs;

[-- Attachment #3: xsa204-4.5.patch --]
[-- Type: application/octet-stream, Size: 2754 bytes --]

From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Sun, 18 Dec 2016 15:42:59 +0000
Subject: [PATCH] x86/emul: Correct the handling of eflags with SYSCALL

A singlestep #DB is determined by the resulting eflags value from the
execution of SYSCALL, not the original eflags value.

By using the original eflags value, we negate the guest kernels attempt to
protect itself from a privilege escalation by masking TF.

Introduce a tf boolean and have the SYSCALL emulation recalculate it
after the instruction is complete.

This is XSA-204

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 xen/arch/x86/x86_emulate/x86_emulate.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c
index 0c43fe1..f675dc9 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -1537,6 +1537,7 @@ x86_emulate(
     union vex vex = {};
     unsigned int op_bytes, def_op_bytes, ad_bytes, def_ad_bytes;
     bool_t lock_prefix = 0;
+    bool_t tf = !!(ctxt->regs->eflags & EFLG_TF);
     int override_seg = -1, rc = X86EMUL_OKAY;
     struct operand src = { .reg = REG_POISON };
     struct operand dst = { .reg = REG_POISON };
@@ -3881,9 +3882,8 @@ x86_emulate(
         break;
     }
 
-    /* Inject #DB if single-step tracing was enabled at instruction start. */
-    if ( (ctxt->regs->eflags & EFLG_TF) && (rc == X86EMUL_OKAY) &&
-         (ops->inject_hw_exception != NULL) )
+    /* Should a singlestep #DB be raised? */
+    if ( tf && (rc == X86EMUL_OKAY) && (ops->inject_hw_exception != NULL) )
         rc = ops->inject_hw_exception(EXC_DB, -1, ctxt) ? : X86EMUL_EXCEPTION;
 
     /* Commit shadow register state. */
@@ -4068,6 +4068,23 @@ x86_emulate(
              (rc = ops->write_segment(x86_seg_ss, &ss, ctxt)) )
             goto done;
 
+        /*
+         * SYSCALL (unlike most instructions) evaluates its singlestep action
+         * based on the resulting EFLG_TF, not the starting EFLG_TF.
+         *
+         * As the #DB is raised after the CPL change and before the OS can
+         * switch stack, it is a large risk for privilege escalation.
+         *
+         * 64bit kernels should mask EFLG_TF in MSR_FMASK to avoid any
+         * vulnerability.  Running the #DB handler on an IST stack is also a
+         * mitigation.
+         *
+         * 32bit kernels have no ability to mask EFLG_TF at all.  Their only
+         * mitigation is to use a task gate for handling #DB (or to not use
+         * enable EFER.SCE to start with).
+         */
+        tf = !!(_regs.eflags & EFLG_TF);
+
         break;
     }
 

[-- Attachment #4: xsa204-4.7.patch --]
[-- Type: application/octet-stream, Size: 2754 bytes --]

From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Sun, 18 Dec 2016 15:42:59 +0000
Subject: [PATCH] x86/emul: Correct the handling of eflags with SYSCALL

A singlestep #DB is determined by the resulting eflags value from the
execution of SYSCALL, not the original eflags value.

By using the original eflags value, we negate the guest kernels attempt to
protect itself from a privilege escalation by masking TF.

Introduce a tf boolean and have the SYSCALL emulation recalculate it
after the instruction is complete.

This is XSA-204

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 xen/arch/x86/x86_emulate/x86_emulate.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c
index bca7045..abe442e 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -1582,6 +1582,7 @@ x86_emulate(
     union vex vex = {};
     unsigned int op_bytes, def_op_bytes, ad_bytes, def_ad_bytes;
     bool_t lock_prefix = 0;
+    bool_t tf = !!(ctxt->regs->eflags & EFLG_TF);
     int override_seg = -1, rc = X86EMUL_OKAY;
     struct operand src = { .reg = REG_POISON };
     struct operand dst = { .reg = REG_POISON };
@@ -3910,9 +3911,8 @@ x86_emulate(
     }
 
  no_writeback:
-    /* Inject #DB if single-step tracing was enabled at instruction start. */
-    if ( (ctxt->regs->eflags & EFLG_TF) && (rc == X86EMUL_OKAY) &&
-         (ops->inject_hw_exception != NULL) )
+    /* Should a singlestep #DB be raised? */
+    if ( tf && (rc == X86EMUL_OKAY) && (ops->inject_hw_exception != NULL) )
         rc = ops->inject_hw_exception(EXC_DB, -1, ctxt) ? : X86EMUL_EXCEPTION;
 
     /* Commit shadow register state. */
@@ -4143,6 +4143,23 @@ x86_emulate(
              (rc = ops->write_segment(x86_seg_ss, &ss, ctxt)) )
             goto done;
 
+        /*
+         * SYSCALL (unlike most instructions) evaluates its singlestep action
+         * based on the resulting EFLG_TF, not the starting EFLG_TF.
+         *
+         * As the #DB is raised after the CPL change and before the OS can
+         * switch stack, it is a large risk for privilege escalation.
+         *
+         * 64bit kernels should mask EFLG_TF in MSR_FMASK to avoid any
+         * vulnerability.  Running the #DB handler on an IST stack is also a
+         * mitigation.
+         *
+         * 32bit kernels have no ability to mask EFLG_TF at all.  Their only
+         * mitigation is to use a task gate for handling #DB (or to not use
+         * enable EFER.SCE to start with).
+         */
+        tf = !!(_regs.eflags & EFLG_TF);
+
         break;
     }
 

[-- Attachment #5: xsa204-4.8.patch --]
[-- Type: application/octet-stream, Size: 2208 bytes --]

From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Sun, 18 Dec 2016 15:42:59 +0000
Subject: [PATCH] x86/emul: Correct the handling of eflags with SYSCALL

A singlestep #DB is determined by the resulting eflags value from the
execution of SYSCALL, not the original eflags value.

By using the original eflags value, we negate the guest kernels attempt to
protect itself from a privilege escalation by masking TF.

Have the SYSCALL emulation recalculate tf after the instruction is complete.

This is XSA-204

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 xen/arch/x86/x86_emulate/x86_emulate.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c
index d82e85d..ff952a9 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -4561,6 +4561,23 @@ x86_emulate(
              (rc = ops->write_segment(x86_seg_ss, &sreg, ctxt)) )
             goto done;
 
+        /*
+         * SYSCALL (unlike most instructions) evaluates its singlestep action
+         * based on the resulting EFLG_TF, not the starting EFLG_TF.
+         *
+         * As the #DB is raised after the CPL change and before the OS can
+         * switch stack, it is a large risk for privilege escalation.
+         *
+         * 64bit kernels should mask EFLG_TF in MSR_FMASK to avoid any
+         * vulnerability.  Running the #DB handler on an IST stack is also a
+         * mitigation.
+         *
+         * 32bit kernels have no ability to mask EFLG_TF at all.  Their only
+         * mitigation is to use a task gate for handling #DB (or to not use
+         * enable EFER.SCE to start with).
+         */
+        tf = _regs.eflags & EFLG_TF;
+
         break;
     }
 
@@ -5412,7 +5429,7 @@ x86_emulate(
 
     *ctxt->regs = _regs;
 
-    /* Inject #DB if single-step tracing was enabled at instruction start. */
+    /* Should a singlestep #DB be raised? */
     if ( tf && (rc == X86EMUL_OKAY) && ops->inject_hw_exception )
         rc = ops->inject_hw_exception(EXC_DB, -1, ctxt) ? : X86EMUL_EXCEPTION;
 

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

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

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

only message in thread, other threads:[~2016-12-19 15:37 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-19 15:37 Xen Security Advisory 204 - x86: Mishandling of SYSCALL singlestep during emulation 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.