1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
$NetBSD: patch-XSA-204,v 1.1 2016/12/20 10:22:28 bouyer Exp $
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
--- xen/arch/x86/x86_emulate/x86_emulate.c.orig 2016-12-19 22:02:25.000000000 +0100
+++ xen/arch/x86/x86_emulate/x86_emulate.c 2016-12-19 22:05:31.000000000 +0100
@@ -1233,6 +1233,7 @@
#define REPE_PREFIX 1
#define REPNE_PREFIX 2
unsigned int lock_prefix = 0, rep_prefix = 0;
+ bool_t tf = !!(ctxt->regs->eflags & EFLG_TF);
int override_seg = -1, rc = X86EMUL_OKAY;
struct operand src, dst;
@@ -3498,9 +3499,8 @@
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. */
@@ -3685,6 +3685,23 @@
(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;
}
|