From 32829f2e96b1f419d4c0acb7af4ab51002efeead Mon Sep 17 00:00:00 2001 From: Dmitrii Kuvaiskii Date: Wed, 16 Oct 2024 05:56:54 -0700 Subject: [PATCH 1/4] [PAL/Linux-SGX] Add AEX-Notify flows in exception handling This commit adds the AEX-Notify flows inside the enclave. The stage-1 signal handler is augmented as follows when AEX-Notify is enabled: manually restore SSA[0] context, invoke the EDECCSSA instruction instead of EEXIT (to go from SSA[1] to SSA[0] without exiting the enclave) and finally jump to SSA[0].GPRSGX.RIP to resume enclave execution (it will resume in stage-2 signal handler). The stage-2 signal handler is augmented as follows: set bit 0 of SSA[0].GPRSGX.AEXNOTIFY (so that AEX-Notify starts working again for this thread), then apply AEX-Notify mitigations and finally restore regular enclave execution. This commit does not add any real AEX-Notify mitigations. Instead, we count the number of AEX events reported inside the SGX enclave and print this number on enclave termination (if log level is at least "warning"). Note that current implementation of AEX-Notify does not use the checkpoint mechanism described in the official AEX-Notify whitepaper. That checkpoint mechanism allows to coalesce multiple AEX events that occur during the execution of mitigations. This saves some CPU cycles and some signal-handling stack space, but we leave implementing this optimization as future work. Signed-off-by: Dmitrii Kuvaiskii --- pal/src/host/linux-sgx/enclave_entry.S | 93 +++++++++++++++++++++- pal/src/host/linux-sgx/generated_offsets.c | 2 + pal/src/host/linux-sgx/host_entry.S | 10 +++ pal/src/host/linux-sgx/pal_exception.c | 30 +++++-- pal/src/host/linux-sgx/pal_linux.h | 1 + pal/src/host/linux-sgx/pal_process.c | 10 +++ 6 files changed, 138 insertions(+), 8 deletions(-) diff --git a/pal/src/host/linux-sgx/enclave_entry.S b/pal/src/host/linux-sgx/enclave_entry.S index faeb468db2..cf1d4be2b7 100644 --- a/pal/src/host/linux-sgx/enclave_entry.S +++ b/pal/src/host/linux-sgx/enclave_entry.S @@ -41,7 +41,12 @@ # Its sole purpose is to prepare the stage-2 handler by: # - copying the interrupted SSA[0] context on the stack ("CPU context") # - rewiring the SSA[0] context to point to _PalExceptionHandler() -# - invoking EEXIT (so that untrusted runtime can perform ERESUME) +# - handing over control to the SSA[0] context, in one of two ways: +# - AEX-Notify disabled or unavailable (legacy default flows): invoke EEXIT (so that untrusted +# runtime can perform ERESUME which will resume enclave execution in the SSA[0] context) +# - AEX-Notify enabled (explicit opt-in flows): manually restore SSA[0] context, invoke +# EDECCSSA instruction to go from SSA[1] to SSA[0] without exiting the enclave, and jump to +# SSA[0].GPRSGX.RIP to resume enclave execution #include "sgx_arch.h" #include "asm-offsets.h" @@ -544,6 +549,12 @@ enclave_entry: movq %r10, %rdx .Lcssa1_exception_eexit: + cmpq $0, %gs:SGX_READY_FOR_AEX_NOTIFY + jne .Lcssa1_exception_eexit_aexnotify + +.Lcssa1_exception_eexit_legacy: + # AEX-Notify is disabled/unavailable, stage-1 exception handler follows the normal EEXIT flow + # .Lcssa0_ocall_or_cssa1_exception_eexit has an ABI that uses RSI, RDI, RSP; clear the relevant # regs (note that stage-1 handler didn't clobber RSP -- which contains an untrusted pointer to # untrusted-runtime stack -- but this flow doesn't read/write RSP at all so there is no need to @@ -555,6 +566,70 @@ enclave_entry: movq %rdx, %rbx jmp .Lcssa0_ocall_or_cssa1_exception_eexit +.Lcssa1_exception_eexit_aexnotify: + # AEX-Notify is enabled, stage-1 exception handler doesn't invoke EEXIT but instead the new + # EDECCSSA instruction (before this, need to manually restore SSA[0] context) + + # After restoring SSA[0] context into GPRs, we'll need to jump to the stage-2 handler, so + # memorize SSA[0].GPRSGX.RIP in an otherwise-unused R11. There is a corner case of the stage-1 + # handler's final jmp instruction, see comment at .Lcssa1_exception_eexit_aexnotify_finaljmp. + leaq .Lcssa1_exception_eexit_aexnotify_finaljmp(%rip), %r11 + cmpq %r11, SGX_GPR_RIP(%rbx) + je 1f + + # not at the stage-1 handler's final jmp instruction, use SSA0's RIP directly + movq SGX_GPR_RIP(%rbx), %r11 + jmp 2f + +1: + # at the stage-1 handler's final jmp instruction, skip over this jmp instruction by directly + # jumping to the previously-saved SSA0's RIP (which was saved in R11) + movq SGX_GPR_R11(%rbx), %r11 + +2: + # Clear bit 0 within SSA[0].GPRSGX.AEXNOTIFY (so that ERESUME actually resumes stage-2 + # handler if it was interrupted by yet another AEX). The stage-2 handler, _PalExceptionHandler() + # func, will re-instate this bit before applying mitigations. + movb $0, SGX_GPR_AEXNOTIFY(%rbx) + + # restore context from SSA[0] (which was already modified above to jump to stage-2 C handler); + # note that XSAVE area (xregs) was already restored above, so only need to restore GPRs; + # note that we don't care about SSA[0].GPRSGX.{URSP,URBP,EXITINFO,RESERVED,GSBASE} + + leaq SGX_GPR_RFLAGS(%rbx), %rsp # trick to restore RFLAGS directly from SSA[0].GPRSGX.RFLAGS + popfq + + movq SGX_GPR_FSBASE(%rbx), %rdi + .byte 0xf3, 0x48, 0x0f, 0xae, 0xd7 # WRFSBASE %RDI + + movq SGX_GPR_RDI(%rbx), %rdi # 1st arg to _PalExceptionHandler() + movq SGX_GPR_RSI(%rbx), %rsi # 2nd arg to _PalExceptionHandler() + movq SGX_GPR_RDX(%rbx), %rdx # 3rd arg to _PalExceptionHandler() + movq SGX_GPR_RCX(%rbx), %rcx # 4th arg to _PalExceptionHandler() + movq SGX_GPR_R8(%rbx), %r8 # 5th arg to _PalExceptionHandler() + movq SGX_GPR_R9(%rbx), %r9 # not strictly needed + movq SGX_GPR_R10(%rbx), %r10 # not strictly needed + movq SGX_GPR_R12(%rbx), %r12 # not strictly needed + movq SGX_GPR_R13(%rbx), %r13 # not strictly needed + movq SGX_GPR_R14(%rbx), %r14 # not strictly needed + movq SGX_GPR_R15(%rbx), %r15 # not strictly needed + movq SGX_GPR_RBP(%rbx), %rbp # not strictly needed + movq SGX_GPR_RSP(%rbx), %rsp + xorq %rbx, %rbx # for sanity + + # go from SSA[1] to SSA[0] (more specifically, simply decrement CSSA from 1 to 0); + # must be careful after this ENCLU instruction because may be interrupted by new exceptions + movq $EDECCSSA, %rax + enclu + + # Finally jump to the stage-2 C exception handler. An async signal can arrive at this exact jmp + # instruction. At this point, SSA0 has the correct internally-consistent context for the + # "stage-2 exception handler", so in this corner case the stage-1 exception handler can skip + # over this jmp and rewire SSA0's RIP directly to _PalExceptionHandler(), which at this point is + # stored in SSA[0].GPRSGX.R11. See also code at .Lcssa1_exception_eexit_aexnotify. +.Lcssa1_exception_eexit_aexnotify_finaljmp: + jmp *%r11 + .cfi_endproc @@ -590,6 +665,15 @@ sgx_ocall: pushq %rbx .cfi_offset %rbx, -24 + # disable AEX-Notify during the ocall-exit assembly logic, as (1) there is no security benefit + # in mitigating AEX events during the ocall asm, and (2) AEX-Notify would otherwise clash with + # ocall-exit and return-from-ocall corner case flows (see .Lcssa1_exception_during_ocall_flows) + cmpq $0, %gs:SGX_READY_FOR_AEX_NOTIFY + je 1f + movq %gs:SGX_GPR, %rax + movb $0, SGX_GPR_AEXNOTIFY(%rax) + +1: CHECK_IF_SIGNAL_STACK_IS_USED %rsp, .Lon_signal_stack_ocall, .Lout_of_signal_stack_ocall .Lout_of_signal_stack_ocall: @@ -745,6 +829,13 @@ sgx_ocall: cmpq $PAL_EVENT_NUM_BOUND, %rsi jb 2f +1: + # re-enable AEX-Notify after return-from-ocall; see .Lcssa0_ocall for details + cmpq $0, %gs:SGX_READY_FOR_AEX_NOTIFY + je 1f + movq %gs:SGX_GPR, %rdi + movb $1, SGX_GPR_AEXNOTIFY(%rdi) + 1: # there was no event, simply call _restore_sgx_context(uc, xsave_area) movq %rsp, %rdi diff --git a/pal/src/host/linux-sgx/generated_offsets.c b/pal/src/host/linux-sgx/generated_offsets.c index 8ff89d06ec..d2c313df0f 100644 --- a/pal/src/host/linux-sgx/generated_offsets.c +++ b/pal/src/host/linux-sgx/generated_offsets.c @@ -56,6 +56,7 @@ const struct generated_offset generated_offsets[] = { OFFSET_T(SGX_GPR_RIP, sgx_pal_gpr_t, rip), OFFSET_T(SGX_GPR_EXITINFO, sgx_pal_gpr_t, exitinfo), OFFSET_T(SGX_GPR_AEXNOTIFY, sgx_pal_gpr_t, aexnotify), + OFFSET_T(SGX_GPR_FSBASE, sgx_pal_gpr_t, fsbase), DEFINE(SGX_GPR_SIZE, sizeof(sgx_pal_gpr_t)), /* sgx_cpu_context_t */ @@ -169,6 +170,7 @@ const struct generated_offset generated_offsets[] = { /* pal.h */ DEFINE(PAL_EVENT_NO_EVENT, PAL_EVENT_NO_EVENT), + DEFINE(PAL_EVENT_INTERRUPTED, PAL_EVENT_INTERRUPTED), DEFINE(PAL_EVENT_NUM_BOUND, PAL_EVENT_NUM_BOUND), /* errno */ diff --git a/pal/src/host/linux-sgx/host_entry.S b/pal/src/host/linux-sgx/host_entry.S index a6b24ab6df..fe9337da0f 100644 --- a/pal/src/host/linux-sgx/host_entry.S +++ b/pal/src/host/linux-sgx/host_entry.S @@ -134,6 +134,16 @@ async_exit_pointer: movb $0, %gs:PAL_HOST_TCB_IN_AEX .cfi_endproc + # In case of non-AEX-Notify flows, ERESUME never morphs into EENTER, so the value in RDI is + # ignored. Below code snippet becomes a no-op. + # In case of AEX-Notify flows, ERESUME will morph into EENTER. The only way we could arrive to + # this line of code is that there was no pending signal to handle inside the SGX enclave, i.e., + # maybe_raise_pending_signal() didn't do anything. Since there was no real pending signal (but + # AEX happened, so AEX-Notify must react to this), we put a dummy PAL_EVENT_INTERRUPTED (aka + # SIGCONT). By putting this dummy signal, we survive all checks inside Gramine's in-enclave + # logic, because SIGCONT can always arrive and is benign and side-effect-free. + movq $PAL_EVENT_INTERRUPTED, %rdi + # fall-through to ERESUME .global eresume_pointer diff --git a/pal/src/host/linux-sgx/pal_exception.c b/pal/src/host/linux-sgx/pal_exception.c index 79edcb3046..a52b6fcecc 100644 --- a/pal/src/host/linux-sgx/pal_exception.c +++ b/pal/src/host/linux-sgx/pal_exception.c @@ -23,6 +23,7 @@ #define ADDR_IN_PAL(addr) ((void*)(addr) > TEXT_START && (void*)(addr) < TEXT_END) bool g_aex_notify_enabled = false; +uint64_t g_aex_notify_counter = 0; void init_aex_notify_for_thread(void) { if (!g_aex_notify_enabled) @@ -30,12 +31,6 @@ void init_aex_notify_for_thread(void) { SET_ENCLAVE_TCB(ready_for_aex_notify, 1UL); MB(); -#if 0 - /* - * FIXME: Re-enable in the following commit, when all AEX-Notify flows are added. - * Currently this would fail, as the untrusted runtime expects AEX-Notify flows but - * in-enclave runtime doesn't yet implement AEX-Notify flows. - */ /* * Note that AEX-Notify is enabled only for SSA[0] (regular context), and is always disabled * for SSA[1] (stage-1 signal handling context). The disablement of AEX-Notify for SSA[1] is @@ -44,7 +39,6 @@ void init_aex_notify_for_thread(void) { */ GET_ENCLAVE_TCB(gpr)->aexnotify = 1U; MB(); -#endif } void fini_aex_notify_for_thread(void) { @@ -57,6 +51,18 @@ void fini_aex_notify_for_thread(void) { MB(); } +static void apply_aex_notify_mitigations(sgx_cpu_context_t* uc, PAL_XREGS_STATE* xregs_state) { + /* + * TODO: introduce mitigations like atomic prefetching of the working set, see proposed + * mitigations in academic paper "AEX-Notify: Thwarting Precise Single-Stepping + * Attacks through Interrupt Awareness for Intel SGX Enclaves" + */ + __UNUSED(uc); + __UNUSED(xregs_state); + + __atomic_fetch_add(&g_aex_notify_counter, 1, __ATOMIC_RELAXED); +} + /* Restore an sgx_cpu_context_t as generated by .Lhandle_exception. Execution will * continue as specified by the rip in the context. */ __attribute_no_sanitize_address @@ -71,6 +77,16 @@ noreturn static void restore_sgx_context(sgx_cpu_context_t* uc, PAL_XREGS_STATE* asan_unpoison_current_stack(sig_stack_low, sig_stack_high - sig_stack_low); #endif + if (g_aex_notify_enabled && GET_ENCLAVE_TCB(ready_for_aex_notify)) { + /* + * AEX-Notify must be re-enabled for this enclave thread before applying any mitigations + * (and consequently before restoring the regular execution of the enclave thread). For + * details, see e.g. the official whitepaper on AEX-Notify from Intel. + */ + GET_ENCLAVE_TCB(gpr)->aexnotify = 1; + apply_aex_notify_mitigations(uc, xregs_state); + } + _restore_sgx_context(uc, xregs_state); } diff --git a/pal/src/host/linux-sgx/pal_linux.h b/pal/src/host/linux-sgx/pal_linux.h index 97060e7bc3..59adc5281e 100644 --- a/pal/src/host/linux-sgx/pal_linux.h +++ b/pal/src/host/linux-sgx/pal_linux.h @@ -96,6 +96,7 @@ void restore_xregs(const PAL_XREGS_STATE* xsave_area); noreturn void _restore_sgx_context(sgx_cpu_context_t* uc, PAL_XREGS_STATE* xsave_area); extern bool g_aex_notify_enabled; +extern uint64_t g_aex_notify_counter; void init_aex_notify_for_thread(void); void fini_aex_notify_for_thread(void); diff --git a/pal/src/host/linux-sgx/pal_process.c b/pal/src/host/linux-sgx/pal_process.c index 9f060b9519..9fde9fa00f 100644 --- a/pal/src/host/linux-sgx/pal_process.c +++ b/pal/src/host/linux-sgx/pal_process.c @@ -246,6 +246,16 @@ int init_child_process(int parent_stream_fd, PAL_HANDLE* out_parent_handle, noreturn void _PalProcessExit(int exitcode) { if (exitcode) log_debug("PalProcessExit: Returning exit code %d", exitcode); + + /* + * FIXME: remove this when proper AEX-Notify mitigations are implemented; + * see pal_exception.c:apply_aex_notify_mitigations() + */ + if (g_aex_notify_enabled) { + uint64_t aex_notify_counter = __atomic_load_n(&g_aex_notify_counter, __ATOMIC_RELAXED); + log_warning("AEX-Notify counter at process exit: %lu", aex_notify_counter); + } + ocall_exit(exitcode, /*is_exitgroup=*/true); /* Unreachable. */ } From 4f1942210db32f32fb18d051736124739ce6c4ad Mon Sep 17 00:00:00 2001 From: Dmitrii Kuvaiskii Date: Thu, 17 Oct 2024 04:34:40 -0700 Subject: [PATCH 2/4] fixup! [PAL/Linux-SGX] Add AEX-Notify flows in exception handling Fixed GDB issue. Fixed a SIGSEGV data race on thread termination (ERESUME morphs into EENTER but then performs EEXIT). Added AEXNOTIFY envvar to LibOS regression tests (but only to a subset from `manifest.template`, simply because changing all manifest template files would be a huge git diff). Signed-off-by: Dmitrii Kuvaiskii --- libos/test/regression/manifest.template | 1 + libos/test/regression/test_libos.py | 3 +++ pal/src/host/linux-sgx/enclave_entry.S | 5 +++-- pal/src/host/linux-sgx/host_entry.S | 26 ++++++++++++++++++++++--- pal/src/host/linux-sgx/host_exception.c | 6 ++++++ pal/src/host/linux-sgx/pal_exception.c | 21 ++++++++++++++++++-- pal/src/host/linux-sgx/pal_tcb.h | 3 +++ python/graminelibos/regression.py | 1 + 8 files changed, 59 insertions(+), 7 deletions(-) diff --git a/libos/test/regression/manifest.template b/libos/test/regression/manifest.template index ab236b1cf2..51e8cf8528 100644 --- a/libos/test/regression/manifest.template +++ b/libos/test/regression/manifest.template @@ -24,6 +24,7 @@ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '16' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} sgx.use_exinfo = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.allowed_files = [ "file:tmp/", diff --git a/libos/test/regression/test_libos.py b/libos/test/regression/test_libos.py index 54ed0905d4..620b92a1d4 100644 --- a/libos/test/regression/test_libos.py +++ b/libos/test/regression/test_libos.py @@ -11,6 +11,7 @@ from graminelibos.regression import ( GDB_VERSION, + HAS_AEXNOTIFY, HAS_AVX, HAS_EDMM, HAS_SGX, @@ -1394,6 +1395,8 @@ def test_080_close_range(self): stdout, _ = self.run_binary(['close_range']) self.assertIn('TEST OK', stdout) +@unittest.skipIf(HAS_AEXNOTIFY, + 'AEX-Notify HW feature conflicts with debugging tools (in particular, with #BP exceptions)') class TC_50_GDB(RegressionTestCase): def setUp(self): if not self.has_debug(): diff --git a/pal/src/host/linux-sgx/enclave_entry.S b/pal/src/host/linux-sgx/enclave_entry.S index cf1d4be2b7..c9cdec8a85 100644 --- a/pal/src/host/linux-sgx/enclave_entry.S +++ b/pal/src/host/linux-sgx/enclave_entry.S @@ -256,8 +256,9 @@ enclave_entry: je .Lcssa1_exception_during_enclave_run # We are interrupted during the never-returning OCALL_EXIT. Because the thread is going to exit - # anyway, we can ignore this exception. - jmp .Lcssa1_exception_eexit + # anyway, we can ignore this exception. We also don't care about AEX-Notify mitigations at this + # point, that's why we don't jump to the .Lcssa1_exception_eexit label. + jmp .Lcssa1_exception_eexit_legacy .Lcssa1_exception_during_ocall_flows: # At this point, we are in the stage-1 exception handler (CSSA=1) and diff --git a/pal/src/host/linux-sgx/host_entry.S b/pal/src/host/linux-sgx/host_entry.S index fe9337da0f..72916a8533 100644 --- a/pal/src/host/linux-sgx/host_entry.S +++ b/pal/src/host/linux-sgx/host_entry.S @@ -134,15 +134,19 @@ async_exit_pointer: movb $0, %gs:PAL_HOST_TCB_IN_AEX .cfi_endproc - # In case of non-AEX-Notify flows, ERESUME never morphs into EENTER, so the value in RDI is - # ignored. Below code snippet becomes a no-op. + # In case of non-AEX-Notify flows, ERESUME never morphs into EENTER, so the values in RDI and + # RDX are ignored. Below code snippet becomes a no-op. # In case of AEX-Notify flows, ERESUME will morph into EENTER. The only way we could arrive to # this line of code is that there was no pending signal to handle inside the SGX enclave, i.e., # maybe_raise_pending_signal() didn't do anything. Since there was no real pending signal (but # AEX happened, so AEX-Notify must react to this), we put a dummy PAL_EVENT_INTERRUPTED (aka # SIGCONT). By putting this dummy signal, we survive all checks inside Gramine's in-enclave - # logic, because SIGCONT can always arrive and is benign and side-effect-free. + # logic, because SIGCONT can always arrive and is benign and side-effect-free. Additionally, + # we put a print-error-and-terminate EEXIT target for EENTER (into which ERESUME morphs) to + # improve error diagnostics (such flows must end with EDECCSSA instead of EEXIT, otherwise it + # indicates a bug in Gramine's AEX-Notify flows). movq $PAL_EVENT_INTERRUPTED, %rdi + leaq .Lsgx_fail_on_morphed_eresume(%rip), %rdx # fall-through to ERESUME @@ -219,3 +223,19 @@ sgx_raise: # RSI - external event jmp .Ldo_ecall .cfi_endproc + + +.Lsgx_fail_on_morphed_eresume: + .cfi_startproc + + pushq %rbp + .cfi_adjust_cfa_offset 8 + movq %rsp, %rbp + .cfi_offset %rbp, -16 + .cfi_def_cfa_register %rbp + + andq $~0xF, %rsp # Required by System V AMD64 ABI. + callq fail_on_morphed_eresume + ud2 + + .cfi_endproc diff --git a/pal/src/host/linux-sgx/host_exception.c b/pal/src/host/linux-sgx/host_exception.c index c551866ae2..1e79b05408 100644 --- a/pal/src/host/linux-sgx/host_exception.c +++ b/pal/src/host/linux-sgx/host_exception.c @@ -391,3 +391,9 @@ void maybe_raise_pending_signal(void) { return; } } + +noreturn void fail_on_morphed_eresume(void) { + log_error("Bug in AEX-Notify flows: ERESUME morphed into EENTER but then the enclave performed " + "EEXIT instead of EDECCSSA. Please debug."); + BUG(); +} diff --git a/pal/src/host/linux-sgx/pal_exception.c b/pal/src/host/linux-sgx/pal_exception.c index a52b6fcecc..9535d2415f 100644 --- a/pal/src/host/linux-sgx/pal_exception.c +++ b/pal/src/host/linux-sgx/pal_exception.c @@ -45,10 +45,26 @@ void fini_aex_notify_for_thread(void) { if (!g_aex_notify_enabled) return; - SET_ENCLAVE_TCB(ready_for_aex_notify, 0UL); + /* + * Order is important: first the stage-2 signal handler must be informed to *not* re-enable + * AEX-Notify for this thread, then AEX-Notify must be disabled for this thread from the HW + * perspective (so that it doesn't morph ERESUME into EENTER), and finally AEX-Notify must be + * disabled from the SW perspective (so that it doesn't try EDECCSSA instead of EEXIT). + * + * Without `stopping_aex_notify`, a signal could arrive and force `restore_sgx_context()` to + * re-enable AEX-Notify, even if unsetting `aexnotify` was executed in the meantime. + * + * If `ready_for_aex_notify` would be unset before unsetting `aexnotify`, then the HW could + * morph ERESUME into EENTER, and the flow enclave_entry.S:Lcssa1_exception_eexit would choose + * the no-AEX-Notify path and perform EEXIT, which is unsupported in Gramine (Gramine assumes + * that ERESUME never returns). + */ + SET_ENCLAVE_TCB(stopping_aex_notify, 1UL); MB(); GET_ENCLAVE_TCB(gpr)->aexnotify = 0U; MB(); + SET_ENCLAVE_TCB(ready_for_aex_notify, 0UL); + MB(); } static void apply_aex_notify_mitigations(sgx_cpu_context_t* uc, PAL_XREGS_STATE* xregs_state) { @@ -77,7 +93,8 @@ noreturn static void restore_sgx_context(sgx_cpu_context_t* uc, PAL_XREGS_STATE* asan_unpoison_current_stack(sig_stack_low, sig_stack_high - sig_stack_low); #endif - if (g_aex_notify_enabled && GET_ENCLAVE_TCB(ready_for_aex_notify)) { + if (g_aex_notify_enabled && GET_ENCLAVE_TCB(ready_for_aex_notify) + && !GET_ENCLAVE_TCB(stopping_aex_notify)) { /* * AEX-Notify must be re-enabled for this enclave thread before applying any mitigations * (and consequently before restoring the regular execution of the enclave thread). For diff --git a/pal/src/host/linux-sgx/pal_tcb.h b/pal/src/host/linux-sgx/pal_tcb.h index fa6886c029..c746082609 100644 --- a/pal/src/host/linux-sgx/pal_tcb.h +++ b/pal/src/host/linux-sgx/pal_tcb.h @@ -43,6 +43,7 @@ struct pal_enclave_tcb { uint64_t thread_started; uint64_t ready_for_exceptions; uint64_t ready_for_aex_notify; + uint64_t stopping_aex_notify; uint64_t manifest_size; void* heap_min; void* heap_max; @@ -126,4 +127,6 @@ void maybe_dump_and_reset_stats(void); void maybe_raise_pending_signal(void); +noreturn void fail_on_morphed_eresume(void); + #endif /* IN_ENCLAVE */ diff --git a/python/graminelibos/regression.py b/python/graminelibos/regression.py index 060c5661f6..077e1ab26f 100644 --- a/python/graminelibos/regression.py +++ b/python/graminelibos/regression.py @@ -16,6 +16,7 @@ # pylint: disable=subprocess-popen-preexec-fn,subprocess-run-check +HAS_AEXNOTIFY = os.environ.get('AEXNOTIFY') == '1' HAS_AVX = os.environ.get('AVX') == '1' HAS_EDMM = os.environ.get('EDMM') == '1' HAS_SGX = os.environ.get('SGX') == '1' From 0e99648404426d05b624647126ef2f9c609ea4c9 Mon Sep 17 00:00:00 2001 From: Dmitrii Kuvaiskii Date: Fri, 18 Oct 2024 01:40:24 -0700 Subject: [PATCH 3/4] fixup! [PAL/Linux-SGX] Add AEX-Notify flows in exception handling Fixed EDMM issue. Turned out to be a case of too many nested signal handlers inside Gramine's SGX PAL, which overflowed the SGX enclave signal stack. Signed-off-by: Dmitrii Kuvaiskii --- pal/src/host/linux-sgx/pal_exception.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pal/src/host/linux-sgx/pal_exception.c b/pal/src/host/linux-sgx/pal_exception.c index 9535d2415f..061aa6be7a 100644 --- a/pal/src/host/linux-sgx/pal_exception.c +++ b/pal/src/host/linux-sgx/pal_exception.c @@ -86,19 +86,27 @@ noreturn static void restore_sgx_context(sgx_cpu_context_t* uc, PAL_XREGS_STATE* if (xregs_state == NULL) xregs_state = (PAL_XREGS_STATE*)g_xsave_reset_state; -#ifdef ASAN - /* Unpoison the signal stack before leaving it */ uintptr_t sig_stack_low = GET_ENCLAVE_TCB(sig_stack_low); uintptr_t sig_stack_high = GET_ENCLAVE_TCB(sig_stack_high); + bool restored_context_is_sighandler = (uc->rsp >= sig_stack_low && uc->rsp < sig_stack_high); + +#ifdef ASAN + /* Unpoison the signal stack before leaving it */ asan_unpoison_current_stack(sig_stack_low, sig_stack_high - sig_stack_low); #endif if (g_aex_notify_enabled && GET_ENCLAVE_TCB(ready_for_aex_notify) - && !GET_ENCLAVE_TCB(stopping_aex_notify)) { + && !GET_ENCLAVE_TCB(stopping_aex_notify) && !restored_context_is_sighandler) { /* * AEX-Notify must be re-enabled for this enclave thread before applying any mitigations * (and consequently before restoring the regular execution of the enclave thread). For * details, see e.g. the official whitepaper on AEX-Notify from Intel. + * + * Note that we re-enable AEX-Notify only in the outermost signal handler (the one that will + * jump to the application code and stack). Otherwise, AEX-Notify would be enabled while + * inside this Gramine-internal signal handler, and exceptions like #PF would result in + * nested invocations of this signal handler, thus overflowing the signal stack. This is + * especially true for the EDMM flows where #PF exceptions are a norm. */ GET_ENCLAVE_TCB(gpr)->aexnotify = 1; apply_aex_notify_mitigations(uc, xregs_state); From 650458694137621398dc04b3e74e49d71aa6d4d7 Mon Sep 17 00:00:00 2001 From: Dmitrii Kuvaiskii Date: Fri, 18 Oct 2024 01:56:49 -0700 Subject: [PATCH 4/4] fixup! [PAL/Linux-SGX] Add AEX-Notify flows in exception handling This commit adds conditional AEX-Notify enablement to all Gramine tests. Run tests e.g. like this (on a machine that supports AEX-Notify both in hardware and in Linux kernel): $ EDMM=1 AEXNOTIFY=1 SGX=1 gramine-test pytest Signed-off-by: Dmitrii Kuvaiskii --- libos/test/abi/x86_64/manifest.template | 1 + libos/test/abi/x86_64/stack_arg.manifest.template | 1 + libos/test/abi/x86_64/stack_env.manifest.template | 1 + libos/test/fs/manifest.template | 1 + libos/test/ltp/manifest.template | 1 + libos/test/regression/argv_from_file.manifest.template | 1 + libos/test/regression/argv_from_manifest.manifest.template | 1 + libos/test/regression/attestation.manifest.template | 1 + libos/test/regression/bootstrap_cpp.manifest.template | 1 + libos/test/regression/debug_log_file.manifest.template | 1 + libos/test/regression/debug_log_inline.manifest.template | 1 + libos/test/regression/device_passthrough.manifest.template | 1 + libos/test/regression/env_from_file.manifest.template | 1 + libos/test/regression/env_from_host.manifest.template | 1 + libos/test/regression/env_passthrough.manifest.template | 1 + libos/test/regression/eventfd_fork.manifest.template | 1 + .../regression/eventfd_fork_allowed_failing.manifest.template | 1 + libos/test/regression/fcntl_lock_child_only.manifest.template | 1 + .../file_check_policy_allow_all_but_log.manifest.template | 1 + libos/test/regression/file_check_policy_strict.manifest.template | 1 + libos/test/regression/fork_and_access_file.manifest.template | 1 + libos/test/regression/fork_disallowed.manifest.template | 1 + libos/test/regression/host_root_fs.manifest.template | 1 + .../regression/hostname_extra_runtime_conf.manifest.template | 1 + libos/test/regression/init_fail.manifest.template | 1 + libos/test/regression/init_fail2.manifest.template | 1 + libos/test/regression/large_mmap.manifest.template | 1 + libos/test/regression/madvise.manifest.template | 1 + libos/test/regression/mmap_map_noreserve.manifest.template | 1 + libos/test/regression/mock_syscalls.manifest.template | 1 + libos/test/regression/multi_pthread.manifest.template | 1 + libos/test/regression/multi_pthread_exitless.manifest.template | 1 + libos/test/regression/openmp.manifest.template | 1 + libos/test/regression/rlimit_nofile_4k.manifest.template | 1 + libos/test/regression/rwlock.manifest.template | 1 + libos/test/regression/shadow_pseudo_fs.manifest.template | 1 + libos/test/regression/shebang_test_script.manifest.template | 1 + libos/test/regression/shm.manifest.template | 1 + libos/test/regression/sigterm_multithread.manifest.template | 1 + libos/test/regression/socket_ioctl.manifest.template | 1 + libos/test/regression/sysfs_common.manifest.template | 1 + libos/test/regression/toml_parsing.manifest.template | 1 + libos/test/regression/uid_gid.manifest.template | 1 + pal/regression/Bootstrap6.manifest.template | 1 + pal/regression/Bootstrap7.manifest.template | 1 + pal/regression/File.manifest.template | 1 + pal/regression/Thread2.manifest.template | 1 + pal/regression/Thread2_edmm.manifest.template | 1 + pal/regression/Thread2_exitless.manifest.template | 1 + pal/regression/manifest.template | 1 + 50 files changed, 50 insertions(+) diff --git a/libos/test/abi/x86_64/manifest.template b/libos/test/abi/x86_64/manifest.template index c130d46db0..9c1608dd2e 100644 --- a/libos/test/abi/x86_64/manifest.template +++ b/libos/test/abi/x86_64/manifest.template @@ -7,6 +7,7 @@ fs.mounts = [ sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '4' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ binary_dir }}/{{ entrypoint }}", diff --git a/libos/test/abi/x86_64/stack_arg.manifest.template b/libos/test/abi/x86_64/stack_arg.manifest.template index bc8658be3c..0b22a45104 100644 --- a/libos/test/abi/x86_64/stack_arg.manifest.template +++ b/libos/test/abi/x86_64/stack_arg.manifest.template @@ -12,6 +12,7 @@ fs.mounts = [ sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '4' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ binary_dir }}/{{ entrypoint }}", diff --git a/libos/test/abi/x86_64/stack_env.manifest.template b/libos/test/abi/x86_64/stack_env.manifest.template index ef892f68f8..c0d075a36c 100644 --- a/libos/test/abi/x86_64/stack_env.manifest.template +++ b/libos/test/abi/x86_64/stack_env.manifest.template @@ -12,6 +12,7 @@ fs.mounts = [ sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '4' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ binary_dir }}/{{ entrypoint }}", diff --git a/libos/test/fs/manifest.template b/libos/test/fs/manifest.template index 612873c068..f8d74543e6 100644 --- a/libos/test/fs/manifest.template +++ b/libos/test/fs/manifest.template @@ -22,6 +22,7 @@ fs.insecure__keys.default = "ffeeddccbbaa99887766554433221100" sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '16' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.allowed_files = [ "file:tmp/", diff --git a/libos/test/ltp/manifest.template b/libos/test/ltp/manifest.template index 40d17ea3b4..f1909baa89 100644 --- a/libos/test/ltp/manifest.template +++ b/libos/test/ltp/manifest.template @@ -26,6 +26,7 @@ sys.brk.max_size = "32M" sys.stack.size = "4M" sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} # for tests that require SIGSEGV handling (e.g., setrlimit01, mmap03) sgx.use_exinfo = true diff --git a/libos/test/regression/argv_from_file.manifest.template b/libos/test/regression/argv_from_file.manifest.template index 9739bdde5b..9a4a7291ac 100644 --- a/libos/test/regression/argv_from_file.manifest.template +++ b/libos/test/regression/argv_from_file.manifest.template @@ -13,6 +13,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.allowed_files = [ "file:argv_test_input", diff --git a/libos/test/regression/argv_from_manifest.manifest.template b/libos/test/regression/argv_from_manifest.manifest.template index 81a2107f2c..38c780c0b1 100644 --- a/libos/test/regression/argv_from_manifest.manifest.template +++ b/libos/test/regression/argv_from_manifest.manifest.template @@ -20,6 +20,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/attestation.manifest.template b/libos/test/regression/attestation.manifest.template index 8c950b332d..5ba14efef9 100644 --- a/libos/test/regression/attestation.manifest.template +++ b/libos/test/regression/attestation.manifest.template @@ -13,6 +13,7 @@ fs.insecure__keys.default = "ffeeddccbbaa99887766554433221100" sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.remote_attestation = "{{ env.get('RA_TYPE', 'none') }}" sgx.ra_client_spid = "{{ env.get('RA_CLIENT_SPID', '') }}" diff --git a/libos/test/regression/bootstrap_cpp.manifest.template b/libos/test/regression/bootstrap_cpp.manifest.template index ba5b53f9fa..9893a42808 100644 --- a/libos/test/regression/bootstrap_cpp.manifest.template +++ b/libos/test/regression/bootstrap_cpp.manifest.template @@ -15,6 +15,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/debug_log_file.manifest.template b/libos/test/regression/debug_log_file.manifest.template index 5ede40df3c..675bebcaa2 100644 --- a/libos/test/regression/debug_log_file.manifest.template +++ b/libos/test/regression/debug_log_file.manifest.template @@ -15,6 +15,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/debug_log_inline.manifest.template b/libos/test/regression/debug_log_inline.manifest.template index e91976b61d..477b864897 100644 --- a/libos/test/regression/debug_log_inline.manifest.template +++ b/libos/test/regression/debug_log_inline.manifest.template @@ -14,6 +14,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/device_passthrough.manifest.template b/libos/test/regression/device_passthrough.manifest.template index 50bbe276b9..80d037f562 100644 --- a/libos/test/regression/device_passthrough.manifest.template +++ b/libos/test/regression/device_passthrough.manifest.template @@ -11,6 +11,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/env_from_file.manifest.template b/libos/test/regression/env_from_file.manifest.template index 66c624225d..52ff0054fa 100644 --- a/libos/test/regression/env_from_file.manifest.template +++ b/libos/test/regression/env_from_file.manifest.template @@ -13,6 +13,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.allowed_files = [ "file:env_test_input", diff --git a/libos/test/regression/env_from_host.manifest.template b/libos/test/regression/env_from_host.manifest.template index 5020055c70..98988609d1 100644 --- a/libos/test/regression/env_from_host.manifest.template +++ b/libos/test/regression/env_from_host.manifest.template @@ -13,6 +13,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/env_passthrough.manifest.template b/libos/test/regression/env_passthrough.manifest.template index 29d9df8051..2c18f34b59 100644 --- a/libos/test/regression/env_passthrough.manifest.template +++ b/libos/test/regression/env_passthrough.manifest.template @@ -18,6 +18,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/eventfd_fork.manifest.template b/libos/test/regression/eventfd_fork.manifest.template index da5dbd81fb..7861cf4464 100644 --- a/libos/test/regression/eventfd_fork.manifest.template +++ b/libos/test/regression/eventfd_fork.manifest.template @@ -12,6 +12,7 @@ sys.insecure__allow_eventfd = true sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/eventfd_fork_allowed_failing.manifest.template b/libos/test/regression/eventfd_fork_allowed_failing.manifest.template index d4886916cf..75bfbf4dc4 100644 --- a/libos/test/regression/eventfd_fork_allowed_failing.manifest.template +++ b/libos/test/regression/eventfd_fork_allowed_failing.manifest.template @@ -18,6 +18,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/fcntl_lock_child_only.manifest.template b/libos/test/regression/fcntl_lock_child_only.manifest.template index da56373055..5537f40ef9 100644 --- a/libos/test/regression/fcntl_lock_child_only.manifest.template +++ b/libos/test/regression/fcntl_lock_child_only.manifest.template @@ -14,6 +14,7 @@ fs.insecure__keys.default = "ffeeddccbbaa99887766554433221100" sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/file_check_policy_allow_all_but_log.manifest.template b/libos/test/regression/file_check_policy_allow_all_but_log.manifest.template index c569c2b26d..40f1193fb9 100644 --- a/libos/test/regression/file_check_policy_allow_all_but_log.manifest.template +++ b/libos/test/regression/file_check_policy_allow_all_but_log.manifest.template @@ -15,6 +15,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.file_check_policy = "allow_all_but_log" diff --git a/libos/test/regression/file_check_policy_strict.manifest.template b/libos/test/regression/file_check_policy_strict.manifest.template index 04907cae76..2e4cef08c6 100644 --- a/libos/test/regression/file_check_policy_strict.manifest.template +++ b/libos/test/regression/file_check_policy_strict.manifest.template @@ -15,6 +15,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.file_check_policy = "strict" diff --git a/libos/test/regression/fork_and_access_file.manifest.template b/libos/test/regression/fork_and_access_file.manifest.template index 8f63bf4106..30cdaadfbf 100644 --- a/libos/test/regression/fork_and_access_file.manifest.template +++ b/libos/test/regression/fork_and_access_file.manifest.template @@ -10,6 +10,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '16' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} # this is only to test that `sgx.enable_stats` works (it can only be specified for debug-mode tests) sgx.enable_stats = true diff --git a/libos/test/regression/fork_disallowed.manifest.template b/libos/test/regression/fork_disallowed.manifest.template index 2408e58606..8a0b757143 100644 --- a/libos/test/regression/fork_disallowed.manifest.template +++ b/libos/test/regression/fork_disallowed.manifest.template @@ -16,6 +16,7 @@ sys.disallow_subprocesses = true sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/host_root_fs.manifest.template b/libos/test/regression/host_root_fs.manifest.template index 3e2c0e6956..3a55314559 100644 --- a/libos/test/regression/host_root_fs.manifest.template +++ b/libos/test/regression/host_root_fs.manifest.template @@ -13,6 +13,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/hostname_extra_runtime_conf.manifest.template b/libos/test/regression/hostname_extra_runtime_conf.manifest.template index bdbd06e0b6..770bcf7c2a 100644 --- a/libos/test/regression/hostname_extra_runtime_conf.manifest.template +++ b/libos/test/regression/hostname_extra_runtime_conf.manifest.template @@ -15,6 +15,7 @@ sys.enable_extra_runtime_domain_names_conf = true sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/init_fail.manifest.template b/libos/test/regression/init_fail.manifest.template index f58d8f38bc..30f2b2c2fe 100644 --- a/libos/test/regression/init_fail.manifest.template +++ b/libos/test/regression/init_fail.manifest.template @@ -12,6 +12,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/init_fail2.manifest.template b/libos/test/regression/init_fail2.manifest.template index a225a2dba0..e8f9b0b662 100644 --- a/libos/test/regression/init_fail2.manifest.template +++ b/libos/test/regression/init_fail2.manifest.template @@ -12,6 +12,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} # this is an impossible combination of options, LibOS must fail very early in init process sgx.enclave_size = "256M" diff --git a/libos/test/regression/large_mmap.manifest.template b/libos/test/regression/large_mmap.manifest.template index 28641fc504..d264bc7781 100644 --- a/libos/test/regression/large_mmap.manifest.template +++ b/libos/test/regression/large_mmap.manifest.template @@ -15,6 +15,7 @@ sgx.enclave_size = "8G" sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.allowed_files = [ "file:testfile", diff --git a/libos/test/regression/madvise.manifest.template b/libos/test/regression/madvise.manifest.template index 185365c189..b2cac3b6a1 100644 --- a/libos/test/regression/madvise.manifest.template +++ b/libos/test/regression/madvise.manifest.template @@ -10,6 +10,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '4' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} # `use_exinfo = true` is needed because `madvise(MADV_DONTNEED)` is used in this test. When EDMM is # enabled, it will free the committed pages but automatically recommit them on subsequent accesses diff --git a/libos/test/regression/mmap_map_noreserve.manifest.template b/libos/test/regression/mmap_map_noreserve.manifest.template index 372e485ed9..ee3cf8075e 100644 --- a/libos/test/regression/mmap_map_noreserve.manifest.template +++ b/libos/test/regression/mmap_map_noreserve.manifest.template @@ -16,6 +16,7 @@ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '20' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} sgx.use_exinfo = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.allowed_files = [ "file:testfile_map_noreserve", diff --git a/libos/test/regression/mock_syscalls.manifest.template b/libos/test/regression/mock_syscalls.manifest.template index 08edf98ec9..962bfe1719 100644 --- a/libos/test/regression/mock_syscalls.manifest.template +++ b/libos/test/regression/mock_syscalls.manifest.template @@ -34,6 +34,7 @@ sys.debug__mock_syscalls = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.libos }}", diff --git a/libos/test/regression/multi_pthread.manifest.template b/libos/test/regression/multi_pthread.manifest.template index 2c6240bd7a..884c234811 100644 --- a/libos/test/regression/multi_pthread.manifest.template +++ b/libos/test/regression/multi_pthread.manifest.template @@ -12,6 +12,7 @@ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/multi_pthread_exitless.manifest.template b/libos/test/regression/multi_pthread_exitless.manifest.template index f2f92753db..64216c24d1 100644 --- a/libos/test/regression/multi_pthread_exitless.manifest.template +++ b/libos/test/regression/multi_pthread_exitless.manifest.template @@ -13,6 +13,7 @@ sgx.insecure__rpc_thread_num = 8 sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/openmp.manifest.template b/libos/test/regression/openmp.manifest.template index a723a31f56..c0bbd1b5f7 100644 --- a/libos/test/regression/openmp.manifest.template +++ b/libos/test/regression/openmp.manifest.template @@ -25,6 +25,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '32' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/rlimit_nofile_4k.manifest.template b/libos/test/regression/rlimit_nofile_4k.manifest.template index 6f6fe02396..31ce232140 100644 --- a/libos/test/regression/rlimit_nofile_4k.manifest.template +++ b/libos/test/regression/rlimit_nofile_4k.manifest.template @@ -15,6 +15,7 @@ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '4' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} sgx.use_exinfo = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/rwlock.manifest.template b/libos/test/regression/rwlock.manifest.template index 3900ba9dba..a7aac5b7a6 100644 --- a/libos/test/regression/rwlock.manifest.template +++ b/libos/test/regression/rwlock.manifest.template @@ -11,6 +11,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '200' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/shadow_pseudo_fs.manifest.template b/libos/test/regression/shadow_pseudo_fs.manifest.template index a501166c3f..b19cfc16d7 100644 --- a/libos/test/regression/shadow_pseudo_fs.manifest.template +++ b/libos/test/regression/shadow_pseudo_fs.manifest.template @@ -16,6 +16,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ binary_dir }}/{{ entrypoint }}", diff --git a/libos/test/regression/shebang_test_script.manifest.template b/libos/test/regression/shebang_test_script.manifest.template index 1b3b4e3b55..2abfe305cc 100644 --- a/libos/test/regression/shebang_test_script.manifest.template +++ b/libos/test/regression/shebang_test_script.manifest.template @@ -12,6 +12,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '16' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/shm.manifest.template b/libos/test/regression/shm.manifest.template index 11dcea23cc..7cf55f24b0 100644 --- a/libos/test/regression/shm.manifest.template +++ b/libos/test/regression/shm.manifest.template @@ -11,6 +11,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.allowed_files = [ "dev:/dev/shm/shm_test", diff --git a/libos/test/regression/sigterm_multithread.manifest.template b/libos/test/regression/sigterm_multithread.manifest.template index 16bf962025..620050e0f1 100644 --- a/libos/test/regression/sigterm_multithread.manifest.template +++ b/libos/test/regression/sigterm_multithread.manifest.template @@ -12,6 +12,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '16' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/socket_ioctl.manifest.template b/libos/test/regression/socket_ioctl.manifest.template index 33201f5b38..7459b71337 100644 --- a/libos/test/regression/socket_ioctl.manifest.template +++ b/libos/test/regression/socket_ioctl.manifest.template @@ -10,6 +10,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '4' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/sysfs_common.manifest.template b/libos/test/regression/sysfs_common.manifest.template index bfd1e2c835..c88bb2b8ac 100644 --- a/libos/test/regression/sysfs_common.manifest.template +++ b/libos/test/regression/sysfs_common.manifest.template @@ -10,6 +10,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/libos/test/regression/toml_parsing.manifest.template b/libos/test/regression/toml_parsing.manifest.template index c63440736e..67963dc95b 100644 --- a/libos/test/regression/toml_parsing.manifest.template +++ b/libos/test/regression/toml_parsing.manifest.template @@ -20,6 +20,7 @@ libos.check_invalid_pointers = false sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} # the manifest options below added only so that they have any test coverage sgx.seal_key.flags_mask = "0xffffffffffffffff" diff --git a/libos/test/regression/uid_gid.manifest.template b/libos/test/regression/uid_gid.manifest.template index e1c48f34e5..dfd7c07302 100644 --- a/libos/test/regression/uid_gid.manifest.template +++ b/libos/test/regression/uid_gid.manifest.template @@ -13,6 +13,7 @@ fs.mounts = [ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '8' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.runtimedir(libc) }}/", diff --git a/pal/regression/Bootstrap6.manifest.template b/pal/regression/Bootstrap6.manifest.template index 08bda1f2b3..a5852e7375 100644 --- a/pal/regression/Bootstrap6.manifest.template +++ b/pal/regression/Bootstrap6.manifest.template @@ -6,3 +6,4 @@ loader.log_level = "debug" sgx.enclave_size = "8192M" sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} diff --git a/pal/regression/Bootstrap7.manifest.template b/pal/regression/Bootstrap7.manifest.template index 177285ef56..0505c7dc09 100644 --- a/pal/regression/Bootstrap7.manifest.template +++ b/pal/regression/Bootstrap7.manifest.template @@ -2,6 +2,7 @@ loader.entrypoint.uri = "file:{{ binary_dir }}/{{ entrypoint }}" sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} loader.env.key1 = "na" loader.env.key2 = "na" diff --git a/pal/regression/File.manifest.template b/pal/regression/File.manifest.template index 59eb3e3c07..9d366b1f31 100644 --- a/pal/regression/File.manifest.template +++ b/pal/regression/File.manifest.template @@ -3,6 +3,7 @@ loader.log_level = "debug" sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} sgx.allowed_files = [ "file:{{ entrypoint }}.manifest", diff --git a/pal/regression/Thread2.manifest.template b/pal/regression/Thread2.manifest.template index 8e9926f044..4d3fb9a1f5 100644 --- a/pal/regression/Thread2.manifest.template +++ b/pal/regression/Thread2.manifest.template @@ -3,3 +3,4 @@ loader.entrypoint.uri = "file:{{ binary_dir }}/{{ entrypoint }}" sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '2' }} sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} diff --git a/pal/regression/Thread2_edmm.manifest.template b/pal/regression/Thread2_edmm.manifest.template index 0efd657eea..b8a06c33ea 100644 --- a/pal/regression/Thread2_edmm.manifest.template +++ b/pal/regression/Thread2_edmm.manifest.template @@ -5,3 +5,4 @@ loader.entrypoint.uri = "file:{{ binary_dir }}/{{ entrypoint }}" sgx.max_threads = 1 sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} diff --git a/pal/regression/Thread2_exitless.manifest.template b/pal/regression/Thread2_exitless.manifest.template index d416edd8d2..b65a2dc3d9 100644 --- a/pal/regression/Thread2_exitless.manifest.template +++ b/pal/regression/Thread2_exitless.manifest.template @@ -6,3 +6,4 @@ sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '2' }} sgx.insecure__rpc_thread_num = 2 sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} diff --git a/pal/regression/manifest.template b/pal/regression/manifest.template index 2a388e510a..4761bfa92f 100644 --- a/pal/regression/manifest.template +++ b/pal/regression/manifest.template @@ -4,6 +4,7 @@ loader.insecure__use_cmdline_argv = true sgx.debug = true sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.experimental_enable_aex_notify = {{ 'true' if env.get('AEXNOTIFY', '0') == '1' else 'false' }} # for Exception test (memfault handler) sgx.use_exinfo = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }}