Skip to content

Commit 441499e

Browse files
mingweishihradhikaj
authored andcommitted
Security fix for AC flag poisoning and MCDT
This PR does the following - Ensuring the AC flag along with other system/control flags are always cleared upon enclave enter - Update the inital MXCSR value to 0x1FBF and put lfence after MXCSR load (via LDMXCSR, XRSTOR, or FXRSTOR) for the MCDT mitigation Signed-off-by: Ming-Wei Shih <mishih@microsoft.com>
1 parent dcf2ba2 commit 441499e

File tree

9 files changed

+109
-40
lines changed

9 files changed

+109
-40
lines changed

enclave/core/sgx/asmcommon.inc

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//
1212
// - The legacy SSE state:
1313
// - Initializes the FPU control word to ABI-specified value 0x037F
14-
// - Initializes MXCSR to ABI-specified value 0x1F80 and MXCSR_MASK to 0xFFFF
14+
// - Initializes MXCSR to ABI-specified value 0x1FBF and MXCSR_MASK to 0xFFFF
1515
// - Clears FPU Status, Tag, OpCode, and FIP words
1616
// - Clears all FDP bits
1717
// - Clears all MMX/FPU registers
@@ -46,6 +46,9 @@
4646
// Restore initial enclave legacy SSE state
4747
fxrstor64 OE_XSAVE_INITIAL_STATE(%rip)
4848
2:
49+
// Put a lfence after changing MXCSR for MXCSR Configuration Dependent
50+
// Timing (MCDT) mitigation
51+
lfence
4952
// Restore the registers
5053
mov %r8, %rax
5154
mov %r9, %rdx
@@ -80,17 +83,36 @@
8083
xor %r14, %r14
8184
xor %r15, %r15
8285

83-
// Zero out the RFLAGS except for system flags and
84-
// reserved bits that are not writable by the enclave
86+
// Zero out the status flags (CF, PF, AF, SF, OF) that could leak
87+
// information about instructions executed by the enclave without using stack.
88+
// Doing so avoiding using untrusted host stack when cleaning up registers
89+
// during enclave enter and exit routines.
90+
// To clear system and control flags, see oe_cleanup_flags_on_enclave_stack
91+
// for more detail.
8592
mov %rax, %r8
8693
xor %rax, %rax
8794
test %al, %al // Clear OF
88-
cld // Clear DF
8995
sahf // Clear SF, ZF AF, PF, and CF
9096
mov %r8, %rax
9197

9298
// No need to clear r8, which equals to rax (return value to the host)
9399

94100
.endm
95101

102+
//==============================================================================
103+
//
104+
// This macro is used to clean up the enclave FLAGS register, including not only
105+
// status but also system and control flags.
106+
//
107+
// The macro does not reserve r15 and require consuming stack. Please make sure
108+
// using the macro within the enclave stack. Currently, the macro is only used
109+
// during oe_enter.
110+
//
111+
//==============================================================================
112+
.macro oe_cleanup_flags_on_enclave_stack
113+
xor %r15, %r15
114+
pushq %r15
115+
popfq
116+
.endm
117+
96118
#endif

enclave/core/sgx/asmdefs.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ OE_XSAVE_INITIAL_STATE[OE_MINIMAL_XSTATE_AREA_SIZE/sizeof(uint32_t)] = {
1616
* clear Status, Tag, OpCode, FIP words */
1717
0x037F, 0, 0, 0,
1818

19-
/* Clear FDP bits, set MXCSR to ABI init value of 0x1F80
19+
/* Clear FDP bits, set MXCSR to ABI init value of 0x1FBF
2020
* and MXCSR_MASK to all bits (0XFFFF) */
21-
0, 0, 0x1F80, 0xFFFF,
21+
0, 0, 0x1FBF, 0xFFFF,
2222

2323
/* Clear ST/MM0-7 */
2424
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -35,10 +35,12 @@ OE_XSAVE_INITIAL_STATE[OE_MINIMAL_XSTATE_AREA_SIZE/sizeof(uint32_t)] = {
3535
0, 0, 0, 0, 0, 0, 0, 0,
3636

3737
/* XSAVE Header */
38-
/* Clear XSTATE_BV. Note that this means we don't support
39-
* compaction mode (XCOMP_BV[63]) to accommodate running
40-
* the same code in simulation mode on older CPUs. */
41-
0, 0, 0, 0,
38+
/* Set XSTATE_BV[1] to 1 (SSE state) */
39+
2, 0,
40+
/* Set XCOMP_BV[1] to 1 (SSE state), allowing non-default
41+
* MXCSR value to be restored.
42+
* Also, set XCOMP_BV[63] to 1 for compaction mode */
43+
2, 0x80000000,
4244

4345
/* Reserved XSAVE header bits */
4446
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

enclave/core/sgx/calls.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -641,15 +641,17 @@ OE_INLINE void _handle_oret(
641641
td->oret_arg = arg;
642642

643643
/* Restore the FXSTATE and flags */
644-
asm volatile("pushq %[rflags] \n\t" // Restore flags.
645-
"popfq \n\t"
646-
"fldcw %[fcw] \n\t" // Restore x87 control word
647-
"ldmxcsr %[mxcsr] \n\t" // Restore MXCSR
648-
: [mxcsr] "=m"(callsite->mxcsr),
649-
[fcw] "=m"(callsite->fcw),
650-
[rflags] "=m"(callsite->rflags)
651-
:
652-
: "cc");
644+
asm volatile(
645+
"pushq %[rflags] \n\t" // Restore flags.
646+
"popfq \n\t"
647+
"fldcw %[fcw] \n\t" // Restore x87 control word
648+
"ldmxcsr %[mxcsr] \n\t" // Restore MXCSR
649+
"lfence \n\t" // MXCSR Configuration Dependent Timing (MCDT) mitigation
650+
: [mxcsr] "=m"(callsite->mxcsr),
651+
[fcw] "=m"(callsite->fcw),
652+
[rflags] "=m"(callsite->rflags)
653+
:
654+
: "cc");
653655

654656
oe_longjmp(&callsite->jmpbuf, 1);
655657
}

enclave/core/sgx/context.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ oe_continue_execution:
106106
// oe_snap_current_context.
107107
ldmxcsr OE_CONTEXT_MXCSR(%rdi)
108108

109+
// For MXCSR Configuration Dependent Timing (MCDT) mitigation
110+
lfence
111+
109112
// Restore general registers.
110113
// Restore rax, rbx, rcx, rdx.
111114
movq OE_CONTEXT_RAX(%rdi), %rax

enclave/core/sgx/enter.S

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,13 @@ oe_enter:
314314
xor %r11, %r11
315315
oe_cleanup_registers
316316

317+
// Clear the flags not covered by oe_cleanup_registers (i.e., control and system
318+
// flags) that requires using (enclave) stack. Given that these flags are not
319+
// affected instructions and persistent throughout the enclave lifetime, we only
320+
// clear them once during the enter routine, which prevents poisoning attack from
321+
// the host.
322+
oe_cleanup_flags_on_enclave_stack
323+
317324
// Call __oe_handle_main(ARG1=RDI, ARG2=RSI, CSSA=RDX, TCS=RCX, OUTPUTARG1=R8, OUTPUTARG2=R9)
318325
mov %rax, %rdx
319326
mov %rbx, %rcx

tests/abi/abi_utils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ OE_EXTERNC_END
2424
// Set FTZ, Truncation RC and DAZ, clear all exception masks
2525
#define TEST_MXCSR 0xE040
2626

27-
// Initial MXCSR value as defined by Linux/Window ABIs
28-
#define INIT_MXCSR 0x1F80
27+
// Default MXCSR value used by OE for MCDT mitigation
28+
#define INIT_MXCSR 0x1FBF
2929

3030
// Set RC to RNE, PC to SP, clear all exception masks (11 00 01 000000)
3131
#define TEST_FCW 0xC40

tests/abi/enc/enc.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,25 @@ double enclave_check_abi()
7676
.deepcopy_out_buffer_size = 0,
7777
._retval = 0}};
7878

79+
flat_ocall_args_t* args = NULL;
80+
81+
/* Get the FLAGS */
82+
uint64_t flags = 0xffffffff;
83+
asm volatile("pushfq\n\t"
84+
"popq %0"
85+
: "=r"(flags)
86+
:
87+
: "r8");
88+
89+
/* Validate bit 10 (DF) and 16 - 31 bits are cleared by the
90+
* oe_enter routine.
91+
* Skip checks against other bits given that they could be impacted
92+
* by branch or memory access executed until this point */
93+
if (flags & 0xffff0400)
94+
goto done;
95+
7996
/* Alloc and initialize host_check_abi OCALL args buffer */
80-
flat_ocall_args_t* args =
81-
(flat_ocall_args_t*)oe_allocate_ocall_buffer(sizeof(args_template));
97+
args = (flat_ocall_args_t*)oe_allocate_ocall_buffer(sizeof(args_template));
8298
if (!args)
8399
goto done;
84100

tests/abi/host/host.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,23 @@ oe_result_t test_abi_roundtrip(oe_enclave_t* enclave)
145145
set_test_abi_state();
146146
read_abi_state(&before_ecall_state);
147147

148+
#ifndef _WIN32
149+
/* Explicitly poison FLAGS bits 10 (DF) and 15-31 while reserving the
150+
* others
151+
*/
152+
uint64_t flags = 0xffff0400;
153+
#else
154+
/* Do not set DF on Windows, which will affect the behavior of
155+
* memset_repmovs that is invoked in the critical path on the host */
156+
uint64_t flags = 0xffff0000;
157+
#endif
158+
asm volatile("pushfq\n\t"
159+
"or %0, (%%rsp)\n\t"
160+
"popfq\n\t"
161+
:
162+
: "r"(flags)
163+
: "r8");
164+
148165
/* Invoke oe_enter directly to test the ocall transition ABI handling */
149166
oe_enter(tcs, OE_AEP_ADDRESS, arg1, arg2, &arg3, &arg4, enclave);
150167

tests/libc/enc/enc.c

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,25 @@
3232
void _reset_fxsave_state()
3333
{
3434
/* Initialize the FXSAVE state values to Linux x86-64 ABI defined values:
35-
* FCW = 0x037F, MXCSR = 0x1F80, MXCSR mask = 0xFFFF */
35+
* FCW = 0x037F, MXCSR = 0x1FBF, MXCSR mask = 0xFFFF */
3636
static OE_ALIGNED(OE_FXSAVE_ALIGNMENT) const uint64_t
3737
_initial_fxstate[OE_FXSAVE_AREA_SIZE / sizeof(uint64_t)] = {
38-
0x037F, 0, 0, 0xFFFF00001F80,
39-
0, 0, 0, 0,
40-
0, 0, 0, 0,
41-
0, 0, 0, 0,
42-
0, 0, 0, 0,
43-
0, 0, 0, 0,
44-
0, 0, 0, 0,
45-
0, 0, 0, 0,
46-
0, 0, 0, 0,
47-
0, 0, 0, 0,
48-
0, 0, 0, 0,
49-
0, 0, 0, 0,
50-
0, 0, 0, 0,
51-
0, 0, 0, 0,
52-
0, 0, 0, 0,
53-
0, 0, 0, 0,
38+
0x037F, 0, 0, 0xFFFF00001FBF,
39+
0, 0, 0, 0,
40+
0, 0, 0, 0,
41+
0, 0, 0, 0,
42+
0, 0, 0, 0,
43+
0, 0, 0, 0,
44+
0, 0, 0, 0,
45+
0, 0, 0, 0,
46+
0, 0, 0, 0,
47+
0, 0, 0, 0,
48+
0, 0, 0, 0,
49+
0, 0, 0, 0,
50+
0, 0, 0, 0,
51+
0, 0, 0, 0,
52+
2, 0x80000002, 0, 0,
53+
0, 0, 0, 0,
5454
};
5555

5656
asm volatile("fxrstor %[fx_state] \n\t"

0 commit comments

Comments
 (0)