diff --git a/.gitmodules b/.gitmodules index 3703d34a4..a4e439761 100644 --- a/.gitmodules +++ b/.gitmodules @@ -17,3 +17,7 @@ path = external/protobuf/protobuf_code url = https://github.com/protocolbuffers/protobuf.git branch = 3.14.x +[submodule "external/sgx-emm/emm_src"] + path = external/sgx-emm/emm_src + url = https://github.com/intel/sgx-emm + branch = dev diff --git a/SampleCode/SampleEnclave/Enclave/Enclave.config.xml b/SampleCode/SampleEnclave/Enclave/Enclave.config.xml index e94c9bc50..83ec0679f 100644 --- a/SampleCode/SampleEnclave/Enclave/Enclave.config.xml +++ b/SampleCode/SampleEnclave/Enclave/Enclave.config.xml @@ -1,12 +1,23 @@ 0 0 - 0x40000 - 0x100000 - 10 + 1 + 5 1 + 13 + + + + 0x4000 + 0x2000 + 0x5000 + 0x50000 + 0 - 0 + 1 0xFFFFFFFF diff --git a/SampleCode/SampleEnclave/Enclave/config.01.xml b/SampleCode/SampleEnclave/Enclave/config.01.xml index ca652963f..2e1354499 100644 --- a/SampleCode/SampleEnclave/Enclave/config.01.xml +++ b/SampleCode/SampleEnclave/Enclave/config.01.xml @@ -23,6 +23,6 @@ 0 - 0 + 1 0xFFFFFFFF diff --git a/SampleCode/SampleEnclave/Enclave/config.02.xml b/SampleCode/SampleEnclave/Enclave/config.02.xml index 126eac07b..59b267388 100644 --- a/SampleCode/SampleEnclave/Enclave/config.02.xml +++ b/SampleCode/SampleEnclave/Enclave/config.02.xml @@ -20,6 +20,6 @@ 1 0 - 0 + 1 0xFFFFFFFF diff --git a/SampleCode/SampleEnclave/Enclave/config.03.xml b/SampleCode/SampleEnclave/Enclave/config.03.xml index ef642799b..3ccf61abc 100644 --- a/SampleCode/SampleEnclave/Enclave/config.03.xml +++ b/SampleCode/SampleEnclave/Enclave/config.03.xml @@ -22,6 +22,6 @@ 0 - 0 + 1 0xFFFFFFFF diff --git a/SampleCode/SampleEnclave/Enclave/config.04.xml b/SampleCode/SampleEnclave/Enclave/config.04.xml index a72d611b5..028445402 100644 --- a/SampleCode/SampleEnclave/Enclave/config.04.xml +++ b/SampleCode/SampleEnclave/Enclave/config.04.xml @@ -18,6 +18,6 @@ 0 - 0 + 1 0xFFFFFFFF diff --git a/common/inc/internal/arch.h b/common/inc/internal/arch.h index 54f31ded6..8cfa683e6 100644 --- a/common/inc/internal/arch.h +++ b/common/inc/internal/arch.h @@ -124,6 +124,8 @@ typedef struct _exit_info_t #define SE_VECTOR_BP 3 #define SE_VECTOR_BR 5 #define SE_VECTOR_UD 6 +#define SE_VECTOR_GP 13 +#define SE_VECTOR_PF 14 #define SE_VECTOR_MF 16 #define SE_VECTOR_AC 17 #define SE_VECTOR_XM 19 @@ -156,6 +158,15 @@ typedef struct _ssa_gpr_t uint64_t gs; /* (176) GS register */ } ssa_gpr_t; +typedef struct _misc_exinfo +{ + uint64_t maddr; // address for #PF, #GP. + uint32_t errcd; + uint32_t reserved; +} misc_exinfo_t; + +#define MISC_BYTE_SIZE sizeof(misc_exinfo_t) + typedef uint64_t si_flags_t; #define SI_FLAG_NONE 0x0 diff --git a/common/inc/internal/bit_array.h b/common/inc/internal/bit_array.h new file mode 120000 index 000000000..8b14d3a15 --- /dev/null +++ b/common/inc/internal/bit_array.h @@ -0,0 +1 @@ +../../../external/sgx-emm/emm_src/include/bit_array.h \ No newline at end of file diff --git a/common/inc/internal/bit_array_imp.h b/common/inc/internal/bit_array_imp.h new file mode 120000 index 000000000..c30a510f2 --- /dev/null +++ b/common/inc/internal/bit_array_imp.h @@ -0,0 +1 @@ +../../../external/sgx-emm/emm_src/include/bit_array_imp.h \ No newline at end of file diff --git a/common/inc/internal/ema.h b/common/inc/internal/ema.h new file mode 120000 index 000000000..1cd936219 --- /dev/null +++ b/common/inc/internal/ema.h @@ -0,0 +1 @@ +../../../external/sgx-emm/emm_src/include/ema.h \ No newline at end of file diff --git a/common/inc/internal/ema_imp.h b/common/inc/internal/ema_imp.h new file mode 120000 index 000000000..41b8b3d22 --- /dev/null +++ b/common/inc/internal/ema_imp.h @@ -0,0 +1 @@ +../../../external/sgx-emm/emm_src/include/ema_imp.h \ No newline at end of file diff --git a/common/inc/internal/emm_private.h b/common/inc/internal/emm_private.h new file mode 120000 index 000000000..cf6d63de1 --- /dev/null +++ b/common/inc/internal/emm_private.h @@ -0,0 +1 @@ +../../../external/sgx-emm/emm_src/include/emm_private.h \ No newline at end of file diff --git a/common/inc/internal/enclave_creator.h b/common/inc/internal/enclave_creator.h index 4b5328055..8fde80547 100644 --- a/common/inc/internal/enclave_creator.h +++ b/common/inc/internal/enclave_creator.h @@ -81,10 +81,10 @@ class EnclaveCreator : private Uncopyable virtual uint32_t handle_page_fault(uint64_t pf_address) { UNUSED(pf_address); return (uint32_t)SGX_ERROR_UNEXPECTED; } #endif virtual int emodpr(uint64_t addr, uint64_t size, uint64_t flag) = 0; + virtual int alloc(uint64_t addr, uint64_t size, int flag) = 0; virtual int mktcs(uint64_t tcs_addr) = 0; virtual int trim_range(uint64_t fromaddr, uint64_t toaddr) = 0; virtual int trim_accept(uint64_t addr) = 0; - virtual int remove_range(uint64_t fromaddr, uint64_t numpages) = 0; // destructor virtual ~EnclaveCreator() {}; diff --git a/common/inc/internal/inst.h b/common/inc/internal/inst.h index 4f2b35756..aa22de72f 100644 --- a/common/inc/internal/inst.h +++ b/common/inc/internal/inst.h @@ -46,7 +46,9 @@ typedef enum { SE_ERESUME, SE_EEXIT, SE_EACCEPT, - SE_EVERIFYREPORT2 = 0x8, + SE_EMODPE, + SE_EACCEPTCOPY, + SE_EVERIFYREPORT2, SE_LAST_RING3, SE_ECREATE = 0x0, diff --git a/common/inc/internal/linux/linux-regs.h b/common/inc/internal/linux/linux-regs.h index 48a206d3b..8741edc2e 100644 --- a/common/inc/internal/linux/linux-regs.h +++ b/common/inc/internal/linux/linux-regs.h @@ -88,6 +88,7 @@ #define SE_EEXIT 4 #define SE_EACCEPT 5 #define SE_EMODPE 6 +#define SE_EACCEPTCOPY 7 #define SE_EVERIFYREPORT2 8 diff --git a/common/inc/internal/metadata.h b/common/inc/internal/metadata.h index ec121a730..dac267a81 100644 --- a/common/inc/internal/metadata.h +++ b/common/inc/internal/metadata.h @@ -37,10 +37,10 @@ #pragma pack(1) /* version of metadata */ -#define MAJOR_VERSION 2 //MAJOR_VERSION should not larger than 0ffffffff -#define MINOR_VERSION 4 //MINOR_VERSION should not larger than 0ffffffff +#define MAJOR_VERSION 3 //MAJOR_VERSION should not larger than 0ffffffff +#define MINOR_VERSION 0 //MINOR_VERSION should not larger than 0ffffffff -#define SGX_2_ELRANGE_MAJOR_VERSION 12 +#define SGX_2_ELRANGE_MAJOR_VERSION 13 #define SGX_1_ELRANGE_MAJOR_VERSION 11 #define SGX_MAJOR_VERSION_GAP 10 @@ -84,6 +84,7 @@ #define HEAP_SIZE_MAX 0x1000000 /* 16 MB */ #define RSRV_SIZE_MIN 0x0000000 /* 0 KB */ #define RSRV_SIZE_MAX 0x0000000 /* 0 KB */ +#define USER_REGION_SIZE 0x0000000 /* 0 KB */ #define DEFAULT_MISC_SELECT 0 #define DEFAULT_MISC_MASK 0xFFFFFFFF #define ISVFAMILYID_MAX 0xFFFFFFFFFFFFFFFFULL @@ -128,6 +129,7 @@ typedef enum #define LAYOUT_ID_RSRV_MIN (20) #define LAYOUT_ID_RSRV_INIT (21) #define LAYOUT_ID_RSRV_MAX (22) +#define LAYOUT_ID_USER_REGION (23) extern const char * layout_id_str[]; diff --git a/common/inc/internal/rts.h b/common/inc/internal/rts.h index e94ad56be..612cd8454 100644 --- a/common/inc/internal/rts.h +++ b/common/inc/internal/rts.h @@ -65,7 +65,8 @@ typedef enum SDK_VERSION_2_0, SDK_VERSION_2_1, SDK_VERSION_2_2, - SDK_VERSION_2_3 + SDK_VERSION_2_3, + SDK_VERSION_3_0, } sdk_version_t; typedef struct _system_features @@ -95,6 +96,8 @@ typedef struct _system_features #define BUILTIN_OCALL_2 -3 #define BUILTIN_OCALL_3 -4 #define BUILTIN_OCALL_4 -5 +#define BUILTIN_OCALL_5 -6 +#define BUILTIN_OCALL_6 -7 typedef enum { @@ -102,10 +105,12 @@ typedef enum EDMM_TRIM_COMMIT = BUILTIN_OCALL_2, EDMM_MODPR = BUILTIN_OCALL_3, EDMM_MPROTECT = BUILTIN_OCALL_4, + EDMM_ALLOC = BUILTIN_OCALL_5, + EDMM_MODIFY = BUILTIN_OCALL_6, }edmm_ocall_t; -#define is_builtin_ocall(ocall_val) (((int)ocall_val >= BUILTIN_OCALL_4) && ((int)ocall_val <= BUILTIN_OCALL_1)) +#define is_builtin_ocall(ocall_val) (((int)ocall_val >= BUILTIN_OCALL_6) && ((int)ocall_val <= BUILTIN_OCALL_1)) #pragma pack(pop) diff --git a/common/inc/internal/rts_cmd.h b/common/inc/internal/rts_cmd.h index 725e34dc6..d0fabdfd6 100644 --- a/common/inc/internal/rts_cmd.h +++ b/common/inc/internal/rts_cmd.h @@ -40,6 +40,8 @@ #define ECMD_ECALL_PTHREAD (-6) +#define ECMD_INTERRUPT (-32) + /* Reserved for 3rd party usage */ #define RESERVED_FOR_3RD_PARTY_START -100 #define RESERVED_FOR_3RD_PARTY_END -1000 diff --git a/common/inc/internal/se_event.h b/common/inc/internal/se_event.h index 99fb4de8a..b4e6bd81a 100644 --- a/common/inc/internal/se_event.h +++ b/common/inc/internal/se_event.h @@ -34,6 +34,8 @@ # include # include +# include +# include # include typedef void * se_handle_t; @@ -53,6 +55,7 @@ se_handle_t SGXAPI se_event_init(void); void SGXAPI se_event_destroy(se_handle_t); int SGXAPI se_event_wait(se_handle_t); +int SGXAPI se_event_timeout_wait(se_handle_t, int, const struct timespec *, int, int *); int SGXAPI se_event_wait_timeout(se_handle_t se_event, uint64_t timeout); int SGXAPI se_event_wake(se_handle_t); diff --git a/common/inc/internal/sethread_spinlock.h b/common/inc/internal/sethread_spinlock.h new file mode 100644 index 000000000..2c7a1863a --- /dev/null +++ b/common/inc/internal/sethread_spinlock.h @@ -0,0 +1,59 @@ + +/* + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _SE_THREAD_SPINLOCK_H_ +#define _SE_THREAD_SPINLOCK_H_ +#include "sgx_thread.h" +/** a recursive spin lock */ +typedef struct _sgx_thread_spinlock_t +{ + size_t m_refcount; /* number of recursive calls */ + volatile uint32_t m_lock; /* use sgx_spinlock_t */ + sgx_thread_t m_owner; +} sgx_thread_spinlock_t; + +#define SGX_THREAD_RECURSIVE_SPINLOCK_INITIALIZER \ + {0, 0, SGX_THREAD_T_NULL} +#ifdef __cplusplus +extern "C" { +#endif + +int sgx_thread_spin_init(sgx_thread_spinlock_t *mutex); +int sgx_thread_spin_destroy(sgx_thread_spinlock_t *mutex); + +int sgx_thread_spin_trylock(sgx_thread_spinlock_t *mutex); +int sgx_thread_spin_unlock(sgx_thread_spinlock_t *mutex); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/common/inc/internal/sgx_mm_rt_abstraction.h b/common/inc/internal/sgx_mm_rt_abstraction.h new file mode 120000 index 000000000..c396ee7b4 --- /dev/null +++ b/common/inc/internal/sgx_mm_rt_abstraction.h @@ -0,0 +1 @@ +../../../external/sgx-emm/emm_src/include/sgx_mm_rt_abstraction.h \ No newline at end of file diff --git a/common/inc/internal/trts_inst.h b/common/inc/internal/trts_inst.h index 354148dcc..ffb7f80a2 100644 --- a/common/inc/internal/trts_inst.h +++ b/common/inc/internal/trts_inst.h @@ -74,17 +74,13 @@ struct ms_tcs extern "C" { #endif -int sgx_accept_forward(si_flags_t sfl, size_t lo, size_t hi); int do_ereport(const sgx_target_info_t *target_info, const sgx_report_data_t *report_data, sgx_report_t *report); int do_everifyreport2(const sgx_report2_mac_struct_t *report2_mac_struct); int do_egetkey(const sgx_key_request_t *key_request, sgx_key_128bit_t *key); uint32_t do_rdrand(uint32_t *rand); int do_eaccept(const sec_info_t *, size_t); +int do_eacceptcopy(const sec_info_t *, size_t, size_t); int do_emodpe(const sec_info_t*, size_t); -int apply_EPC_pages(void *start_address, size_t page_number); -int apply_pages_within_exception(void *start_address, size_t page_count); -int trim_EPC_pages(void *start_address, size_t page_number); -sgx_status_t SGXAPI trts_mprotect(size_t start, size_t size, uint64_t perms); sgx_status_t do_add_thread(void *ms); int is_dynamic_thread(void *tcs); int is_dynamic_thread_exist(void); diff --git a/common/inc/sgx_attributes.h b/common/inc/sgx_attributes.h index 4f5e18008..955e69595 100644 --- a/common/inc/sgx_attributes.h +++ b/common/inc/sgx_attributes.h @@ -49,7 +49,7 @@ #define SGX_XFRM_MPX 0x0000000000000018ULL /* MPX XFRM - not supported */ #define SGX_XFRM_PKRU 0x0000000000000200ULL /* PKRU state */ -#define SGX_XFRM_RESERVED (~(SGX_XFRM_LEGACY | SGX_XFRM_AVX | SGX_XFRM_AVX512 | SGX_XFRM_PKRU)) +#define SGX_XFRM_RESERVED (~(SGX_XFRM_LEGACY | SGX_XFRM_AVX | SGX_XFRM_AVX512 | SGX_XFRM_MPX | SGX_XFRM_PKRU)) typedef struct _attributes_t { diff --git a/common/inc/sgx_interrupt.h b/common/inc/sgx_interrupt.h new file mode 100644 index 000000000..e2ca93269 --- /dev/null +++ b/common/inc/sgx_interrupt.h @@ -0,0 +1,65 @@ +#ifndef _SGX_INTERRUPT_H_ +#define _SGX_INTERRUPT_H_ + +// An interrupt mechanism for dynamically-loaded workloads in enclaves. +// +// Workloads in an enclave can be classified into two categories: statically-loaded and +// dynamically-loaded workloads. Statically-loaded workloads are application code that +// are built into the enclave; that is, they are part of the enclave since enclave initialization. +// Dynamically-loaded workloads, as the name suggests, are application code loaded after +// the enclave gets running. +// +// One typical example of dynamically-loaded workloads is user programs loaded by a SGX +// LibOS. The user programs could be arbitrary code. As a result, once the user program +// gets executed, the LibOS may never have the opportunity to take control of the CPU. +// Without the ability to regain the control, it is impossible for the LibOS to implement +// features like interruptible signal handler or preemptive in-enclave thread scheduling. +// +// To address the issue above, we implement the signal-based interrupt mechanism for +// dynamically-loaded workloads. With the provided APIs, the users can now interrupt the +// dynamically-loaded workloads executed in a SGX thread by simply sending a real-time +// POSIX signal (whosenumber is 64, the max value of signal numbers on Linux) to the SGX +// thread. The signal will be captured and (if the timing is good) a pre-registered +// interrupt handler will get executed inside the enclave. +// +// Note that the interrupt mechanism only performs the signal-to-interrupt conversion +// described above is in a best-effort manner. That is, sending a signal may not +// result in the interrupt handler getting called. For example, if the target SGX thread is +// executing some code outside the enclave, then the signal received will be simply +// ignored, thus not triggering the interrupt handler to be executed. So the users of +// the interrupt mechanism should find other means to determine if an interrupt has been +// delivered, and if not, whether and when to resend the interrupt (via POSIX signal). + +#include "sgx_error.h" +#include "sgx_trts_exception.h" + +// A data structure that represents an interrupt +typedef struct _sgx_interrupt_info_t { + sgx_cpu_context_t cpu_context; +} sgx_interrupt_info_t; + +// A handler function that processes an interrupt +typedef void (*sgx_interrupt_handler_t)(sgx_interrupt_info_t*); + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize the interrupt mechanism for SGX threads. +sgx_status_t SGXAPI sgx_interrupt_init(sgx_interrupt_handler_t handler); + +// Make the current thread interruptible when executing in the given code region. +// +// By default, a SGX thread is not interruptible. It is the responsibility of the +// caller of this API to ensure that the given code region is ok to be interrupted, +// e.g., not causing deadlocks. +sgx_status_t SGXAPI sgx_interrupt_enable(size_t code_addr, size_t code_size); + +// Make the current thread uninterruptible. +sgx_status_t SGXAPI sgx_interrupt_disable(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _SGX_INTERRUPT_H_ */ diff --git a/common/inc/sgx_mm.h b/common/inc/sgx_mm.h new file mode 120000 index 000000000..ec4db6615 --- /dev/null +++ b/common/inc/sgx_mm.h @@ -0,0 +1 @@ +../../external/sgx-emm/emm_src/include/sgx_mm.h \ No newline at end of file diff --git a/common/inc/sgx_mm_primitives.h b/common/inc/sgx_mm_primitives.h new file mode 120000 index 000000000..88d2c9b61 --- /dev/null +++ b/common/inc/sgx_mm_primitives.h @@ -0,0 +1 @@ +../../external/sgx-emm/emm_src/include/sgx_mm_primitives.h \ No newline at end of file diff --git a/common/inc/sgx_mm_rt_abstraction.h b/common/inc/sgx_mm_rt_abstraction.h new file mode 120000 index 000000000..8ffd119d4 --- /dev/null +++ b/common/inc/sgx_mm_rt_abstraction.h @@ -0,0 +1 @@ +../../external/sgx-emm/emm_src/include/sgx_mm_rt_abstraction.h \ No newline at end of file diff --git a/common/inc/sgx_occlum_utils.edl b/common/inc/sgx_occlum_utils.edl new file mode 100644 index 000000000..5996b5621 --- /dev/null +++ b/common/inc/sgx_occlum_utils.edl @@ -0,0 +1,6 @@ +enclave { + untrusted { + /* Go outside and wait on my untrusted event with timeout */ + [cdecl] int sgx_thread_wait_untrusted_event_timeout_ocall([user_check] const void *self, int clockbit, [in] const struct sgx_edl_timespec* ts, int absolute_time, [out] int* err); + }; +}; diff --git a/common/inc/sgx_random_buffers.h b/common/inc/sgx_random_buffers.h index 721de3d7f..0a78bae11 100644 --- a/common/inc/sgx_random_buffers.h +++ b/common/inc/sgx_random_buffers.h @@ -164,7 +164,12 @@ struct alignas(A)randomly_placed_buffer // used for objects without a constructor. T *randomize_object(std::size_t count = 1) { - return (T*)(reset(count).__bigger_ + ((rdrand() % M) & ~(A - 1))); +#if defined(MAXIMAL_CALLSTACK) + unsigned rand_size = M - 1; +#else + unsigned rand_size = rdrand() % M; +#endif + return (T*)(reset(count).__bigger_ + ((rand_size) & ~(A - 1))); } // instantiate_object() invokes T's constructor on the object returned by diff --git a/common/inc/sgx_tprotected_fs.edl b/common/inc/sgx_tprotected_fs.edl index b6f0b8c3f..5cd025da7 100644 --- a/common/inc/sgx_tprotected_fs.edl +++ b/common/inc/sgx_tprotected_fs.edl @@ -14,7 +14,6 @@ * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/common/inc/sgx_tprotected_fs.h b/common/inc/sgx_tprotected_fs.h index dbd5abf91..acb6dbe32 100644 --- a/common/inc/sgx_tprotected_fs.h +++ b/common/inc/sgx_tprotected_fs.h @@ -45,6 +45,7 @@ #include "sgx_defs.h" #include "sgx_key.h" +#include "sgx_tcrypto.h" #define SGX_FILE void @@ -94,6 +95,43 @@ SGX_FILE* SGXAPI sgx_fopen(const char* filename, const char* mode, const sgx_key SGX_FILE* SGXAPI sgx_fopen_auto_key(const char* filename, const char* mode); +/* sgx_fopen_integrity_only +* Purpose: open existing protected file (created with previous call to sgx_fopen_integrity_only) or create a new one (see c++ fopen documentation for more details). +* This API skips encryption and only performs MAC calculation/validation, thus protecting the file's integrity, not confidentiality. +* +* Parameters: +* filename - [IN] the name of the file to open/create. +* mode - [IN] open mode. only supports 'r' or 'w' or 'a' (one and only one of them must be present), and optionally 'b' and/or '+'. +* +* Return value: +* SGX_FILE* - pointer to the newly created file handle, NULL if an error occurred - check errno for the error code. +*/ +SGX_FILE* SGXAPI sgx_fopen_integrity_only(const char* filename, const char* mode); + + +/* sgx_fopen_ex + * Purpose: Expert version of sgx_fopen/sgx_fopen_auto_key which is used if you want to control the internal `cache size`. + * The specified `cache size` must be page (4KB by default) aligned. + * Note that `sgx_fexport_auto_key` and `sgx_fimport_auto_key` don't support configuring `cache_size` right now + * + * Parameters: + * filename - [IN] the name of the file to open/create. + * mode - [IN] open mode. only supports 'r' or 'w' or 'a' (one and only one of them must be present), and optionally 'b' and/or '+'. + * key - [IN] encryption key that will be used for the file encryption. + * If it's NULL, we will swtich back to `sgx_fopen_auto_key and use enclave's seal key to protect the file + * NOTE - the key is actually used as a KDK (key derivation key) and only for the meta-data node, and not used directly for the encryption of any part of the file + * this is important in order to prevent hitting the key wear-out problem, and some other issues with GCM encryptions using the same key + * cache_size - [IN] Internal cache size in byte, which used to cache R/W data in enclave before flush to actual file + * It must larger than default cache size (192KB), and must be page (4KB by default) aligned + * a) Please make sure enclave heap is enough for the `cache`, e.g. Configure enough heap in enclave config file + * b) All the data in cache may lost after exeception, please try to call `sgx_fflush` explicitly to avoid data loss + * + * Return value: + * SGX_FILE* - pointer to the newly created file handle, NULL if an error occurred - check errno for the error code. +*/ +SGX_FILE* SGXAPI sgx_fopen_ex(const char* filename, const char* mode, const sgx_key_128bit_t *key, const uint64_t cache_size); + + /* sgx_fwrite * Purpose: write data to a file (see c++ fwrite documentation for more details). * @@ -101,7 +139,7 @@ SGX_FILE* SGXAPI sgx_fopen_auto_key(const char* filename, const char* mode); * ptr - [IN] pointer to the input data buffer * size - [IN] size of data block * count - [IN] count of data blocks to write - * stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key) + * stream - [IN] the file handle (opened with sgx_fopen*) * * Return value: * size_t - number of 'size' blocks written to the file, 0 in case of an error - check sgx_ferror for error code @@ -116,7 +154,7 @@ size_t SGXAPI sgx_fwrite(const void* ptr, size_t size, size_t count, SGX_FILE* s * ptr - [OUT] pointer to the output data buffer * size - [IN] size of data block * count - [IN] count of data blocks to write - * stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key) + * stream - [IN] the file handle (opened with sgx_fopen*) * * Return value: * size_t - number of 'size' blocks read from the file, 0 in case of an error - check sgx_ferror for error code @@ -128,7 +166,7 @@ size_t SGXAPI sgx_fread(void* ptr, size_t size, size_t count, SGX_FILE* stream); * Purpose: get the current value of the position indicator of the file (see c++ ftell documentation for more details). * * Parameters: - * stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key) + * stream - [IN] the file handle (opened with sgx_fopen*) * * Return value: * int64_t - the current value of the position indicator, -1 on error - check errno for the error code @@ -140,7 +178,7 @@ int64_t SGXAPI sgx_ftell(SGX_FILE* stream); * Purpose: set the current value of the position indicator of the file (see c++ fseek documentation for more details). * * Parameters: - * stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key) + * stream - [IN] the file handle (opened with sgx_fopen*) * offset - [IN] the new required value, relative to the origin parameter * origin - [IN] the origin from which to calculate the offset (SEEK_SET, SEEK_CUR or SEEK_END) * @@ -154,7 +192,7 @@ int32_t SGXAPI sgx_fseek(SGX_FILE* stream, int64_t offset, int origin); * Purpose: force actual write of all the cached data to the disk (see c++ fflush documentation for more details). * * Parameters: - * stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key) + * stream - [IN] the file handle (opened with sgx_fopen*) * * Return value: * int32_t - result, 0 on success, 1 in case of an error - check sgx_ferror for error code @@ -166,7 +204,7 @@ int32_t SGXAPI sgx_fflush(SGX_FILE* stream); * Purpose: get the latest operation error code (see c++ ferror documentation for more details). * * Parameters: - * stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key) + * stream - [IN] the file handle (opened with sgx_fopen*) * * Return value: * int32_t - the error code, 0 means no error, anything else is the latest operation error code @@ -178,7 +216,7 @@ int32_t SGXAPI sgx_ferror(SGX_FILE* stream); * Purpose: did the file's position indicator hit the end of the file in a previous read operation (see c++ feof documentation for more details). * * Parameters: - * stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key) + * stream - [IN] the file handle (opened with sgx_fopen*) * * Return value: * int32_t - 1 - end of file was reached, 0 - end of file wasn't reached @@ -191,7 +229,7 @@ int32_t SGXAPI sgx_feof(SGX_FILE* stream); * call sgx_ferror or sgx_feof after a call to this function to learn if it was successful or not * * Parameters: - * stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key) + * stream - [IN] the file handle (opened with sgx_fopen*) * * Return value: * none @@ -204,7 +242,7 @@ void SGXAPI sgx_clearerr(SGX_FILE* stream); * after a call to this function, the handle is invalid even if an error is returned * * Parameters: - * stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key) + * stream - [IN] the file handle (opened with sgx_fopen*) * * Return value: * int32_t - result, 0 - file was closed successfully, 1 - there were errors during the operation @@ -261,7 +299,7 @@ int32_t SGXAPI sgx_fimport_auto_key(const char* filename, const sgx_key_128bit_t * if a user wishes to remove all secrets from memory, he should close the file handle with sgx_fclose * * Parameters: -* stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key +* stream - [IN] the file handle (opened with sgx_fopen*) * * Return value: * int32_t - result, 0 - success, 1 - there was an error, check errno for the error code @@ -269,6 +307,19 @@ int32_t SGXAPI sgx_fimport_auto_key(const char* filename, const sgx_key_128bit_t int32_t SGXAPI sgx_fclear_cache(SGX_FILE* stream); +/* sgx_fget_mac +* Purpose: get the MAC of the file. To ensure the MAC reflects all the content in the file, +* sgx_fflush will be called automatically before getting the MAC. It is the caller's responsibility of not doing any writes before +* this function returns the MAC. +* +* Parameters: +* stream - [IN] the file handle (opened with sgx_fopen*) +* +* Return value: +* int32_t - result, 0 - success, 1 - there was an error, check errno for the error code +*/ +int32_t SGXAPI sgx_fget_mac(SGX_FILE* stream, sgx_aes_gcm_128bit_tag_t* mac); + #ifdef __cplusplus } #endif diff --git a/common/inc/sgx_trts_exception.h b/common/inc/sgx_trts_exception.h index 3e04c3255..83cdd5cb4 100644 --- a/common/inc/sgx_trts_exception.h +++ b/common/inc/sgx_trts_exception.h @@ -54,6 +54,7 @@ typedef enum _sgx_exception_vector_t SGX_EXCEPTION_VECTOR_BP = 3, /* INT 3 instruction */ SGX_EXCEPTION_VECTOR_BR = 5, /* BOUND instruction */ SGX_EXCEPTION_VECTOR_UD = 6, /* UD2 instruction or reserved opcode */ + SGX_EXCEPTION_VECTOR_PF = 14, /* page fault */ SGX_EXCEPTION_VECTOR_MF = 16, /* x87 FPU floating-point or WAIT/FWAIT instruction */ SGX_EXCEPTION_VECTOR_AC = 17, /* Any data reference in memory */ SGX_EXCEPTION_VECTOR_XM = 19, /* SSE/SSE2/SSE3 floating-point instruction */ @@ -103,11 +104,19 @@ typedef struct _cpu_context_t } sgx_cpu_context_t; #endif +typedef struct _exinfo_t +{ + uint64_t faulting_address; + uint32_t error_code; + uint32_t reserved; +}sgx_misc_exinfo_t; + typedef struct _exception_info_t { sgx_cpu_context_t cpu_context; sgx_exception_vector_t exception_vector; sgx_exception_type_t exception_type; + sgx_misc_exinfo_t exinfo; } sgx_exception_info_t; typedef int (*sgx_exception_handler_t)(sgx_exception_info_t *info); diff --git a/common/inc/sgx_tstdc.edl b/common/inc/sgx_tstdc.edl index 7e5769132..0ec65f723 100644 --- a/common/inc/sgx_tstdc.edl +++ b/common/inc/sgx_tstdc.edl @@ -30,9 +30,15 @@ */ enclave { + /* Define libc's timespec_t for EDL */ + struct sgx_edl_timespec { + int64_t sec; + int64_t nsec; + }; + untrusted { [cdecl] void sgx_oc_cpuidex([out] int cpuinfo[4], int leaf, int subleaf); - + /* Go outside and wait on my untrusted event */ [cdecl] int sgx_thread_wait_untrusted_event_ocall([user_check] const void *self); diff --git a/common/se_wrapper/Makefile b/common/se_wrapper/Makefile index d741a7b9c..92ff48abc 100644 --- a/common/se_wrapper/Makefile +++ b/common/se_wrapper/Makefile @@ -43,7 +43,8 @@ OBJS := se_memory.o \ se_event.o \ se_rwlock.o \ se_time.o \ - se_map.o + se_map.o \ + se_event_timeout_wait.o LIBWRAPPER := libwrapper.a diff --git a/common/se_wrapper_psw/Makefile b/common/se_wrapper_psw/Makefile index e776c2b25..92ff48abc 100644 --- a/common/se_wrapper_psw/Makefile +++ b/common/se_wrapper_psw/Makefile @@ -34,7 +34,7 @@ include ../../buildenv.mk CFLAGS += -Werror -D_GNU_SOURCE -fPIC CFLAGS += $(ADDED_INC) -CPPFLAGS := -I$(SGX_HEADER_DIR) \ +CPPFLAGS := -I$(COMMON_DIR)/inc \ -I$(COMMON_DIR)/inc/internal OBJS := se_memory.o \ @@ -43,7 +43,8 @@ OBJS := se_memory.o \ se_event.o \ se_rwlock.o \ se_time.o \ - se_map.o + se_map.o \ + se_event_timeout_wait.o LIBWRAPPER := libwrapper.a diff --git a/common/src/se_event_timeout_wait.c b/common/src/se_event_timeout_wait.c new file mode 100644 index 000000000..6ab337479 --- /dev/null +++ b/common/src/se_event_timeout_wait.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011-2020 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include "se_event.h" + +#include +#include + +int se_event_timeout_wait(se_handle_t se_event, int clockbit, const struct timespec *ts, int absolute_time, int *err) +{ + int ret = 0; + + if (se_event == NULL || err == NULL) + return SE_MUTEX_INVALID; + + if (__sync_fetch_and_add((int*)se_event, -1) == 0) { + // From futex man page: + // For FUTEX_WAIT, timeout is interpreted as a relative value. This differs from other futex operations, where + // timeout is interpreted as an absolute value. To obtain the equivalent of FUTEX_WAIT with an absolute timeout, + // employ FUTEX_WAIT_BITSET with val3 specified as FUTEX_BITSET_MATCH_ANY. + if (absolute_time == 1) { + ret = (int)syscall(__NR_futex, se_event, FUTEX_WAIT_BITSET | clockbit, -1, ts, NULL, FUTEX_BITSET_MATCH_ANY); + } else { + // FUTEX_WAIT can't work with FUTEX_CLOCK_REALTIME in Linux. Thus, ignore the clockbit. + // Reference: https://github.com/torvalds/linux/commit/4fbf5d6837bf81fd7a27d771358f4ee6c4f243f8 + ret = (int)syscall(__NR_futex, se_event, FUTEX_WAIT, -1, ts, NULL, 0); + } + __sync_val_compare_and_swap((int*)se_event, -1, 0); + } + *err = ret < 0 ? errno : 0; + + return SE_MUTEX_SUCCESS; +} diff --git a/compile_and_install.sh b/compile_and_install.sh new file mode 100755 index 000000000..d48319d92 --- /dev/null +++ b/compile_and_install.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -e + +pushd `dirname $0` > /dev/null +SCRIPT_PATH=`pwd` +popd > /dev/null + +# Uninstall old sdk +sudo /opt/intel/sgxsdk/uninstall.sh || true + +# Compile SDK and install +make USE_OPT_LIBS=3 sdk_no_mitigation +make sdk_install_pkg_no_mitigation +sudo mkdir -p /opt/intel +cd /opt/intel +yes yes | sudo ${SCRIPT_PATH}/linux/installer/bin/sgx_linux_x64_sdk_*.bin +source /opt/intel/sgxsdk/environment + +cd ${SCRIPT_PATH} +make -C psw/urts/linux +cd build/linux +ln -sf libsgx_enclave_common.so libsgx_enclave_common.so.1 +export LD_LIBRARY_PATH=${SCRIPT_PATH}/build/linux/ + +cd ${SCRIPT_PATH}/external/sgx-emm/api_tests/ +make clean +make +./test_mm_api + diff --git a/external/sgx-emm/Makefile b/external/sgx-emm/Makefile new file mode 100644 index 000000000..43c82abec --- /dev/null +++ b/external/sgx-emm/Makefile @@ -0,0 +1,66 @@ +# Copyright (C) 2011-2021 Intel Corporation. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include ../../buildenv.mk + +HAVE_PRIMITIVES ?= 1 + +CPPFLAGS += -Iemm_src/include \ + -I$(COMMON_DIR)/inc/tlibc \ + -Wno-missing-braces -Wno-unused-parameter + +C_Files := $(wildcard emm_src/*.c) +OBJS := $(C_Files:.c=.o) +OBJS := $(sort $(OBJS)) + +ifneq ($(HAVE_PRIMITIVES), 1) +ASM_OBJ := emm_src/sgx_primitives.o +endif + +LIB_NAME := libsgx_mm.a + +.PHONY: all +all: $(LIB_NAME) | $(BUILD_DIR) + $(CP) $(LIB_NAME) $| + +$(LIB_NAME): $(OBJS) $(ASM_OBJ) + $(AR) rcs $@ $^ + +$(ASM_OBJ): %.o: %.S + $(CC) $(COMMON_FLAGS) $(ENCLAVE_CFLAGS) $(CPPFLAGS) -c $< -o $@ + +$(OBJS): %.o: %.c + $(CC) -c $(COMMON_FLAGS) $(ENCLAVE_CFLAGS) $(CPPFLAGS) $< -o $@ + +$(BUILD_DIR): + @$(MKDIR) $@ + +.PHONY: clean +clean: + @$(RM) $(LIB_NAME) $(ASM_OBJ) $(OBJS) $(BUILD_DIR)/$(LIB_NAME) *.bak *~ + diff --git a/external/sgx-emm/api_tests/App/App.cpp b/external/sgx-emm/api_tests/App/App.cpp new file mode 100644 index 000000000..91d16b503 --- /dev/null +++ b/external/sgx-emm/api_tests/App/App.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include +#include + +#include +#include +#include + +# include +# include +# define MAX_PATH FILENAME_MAX + +#include "sgx_urts.h" +#include "App.h" +#include "Enclave_u.h" +#include "../tcs.h" +using namespace std; + +/* Global EID shared by multiple threads */ +sgx_enclave_id_t global_eid = 0; + +typedef struct _sgx_errlist_t { + sgx_status_t err; + const char *msg; + const char *sug; /* Suggestion */ +} sgx_errlist_t; + +/* Error code returned by sgx_create_enclave */ +static sgx_errlist_t sgx_errlist[] = { + { + SGX_ERROR_UNEXPECTED, + "Unexpected error occurred.", + NULL + }, + { + SGX_ERROR_INVALID_PARAMETER, + "Invalid parameter.", + NULL + }, + { + SGX_ERROR_OUT_OF_MEMORY, + "Out of memory.", + NULL + }, + { + SGX_ERROR_ENCLAVE_LOST, + "Power transition occurred.", + "Please refer to the sample \"PowerTransition\" for details." + }, + { + SGX_ERROR_INVALID_ENCLAVE, + "Invalid enclave image.", + NULL + }, + { + SGX_ERROR_INVALID_ENCLAVE_ID, + "Invalid enclave identification.", + NULL + }, + { + SGX_ERROR_INVALID_SIGNATURE, + "Invalid enclave signature.", + NULL + }, + { + SGX_ERROR_OUT_OF_EPC, + "Out of EPC memory.", + NULL + }, + { + SGX_ERROR_NO_DEVICE, + "Invalid SGX device.", + "Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards." + }, + { + SGX_ERROR_MEMORY_MAP_CONFLICT, + "Memory map conflicted.", + NULL + }, + { + SGX_ERROR_INVALID_METADATA, + "Invalid enclave metadata.", + NULL + }, + { + SGX_ERROR_DEVICE_BUSY, + "SGX device was busy.", + NULL + }, + { + SGX_ERROR_INVALID_VERSION, + "Enclave version was invalid.", + NULL + }, + { + SGX_ERROR_INVALID_ATTRIBUTE, + "Enclave was not authorized.", + NULL + }, + { + SGX_ERROR_ENCLAVE_FILE_ACCESS, + "Can't open enclave file.", + NULL + }, +}; + +/* Check error conditions for loading enclave */ +void print_error_message(sgx_status_t ret) +{ + size_t idx = 0; + size_t ttl = sizeof sgx_errlist/sizeof sgx_errlist[0]; + + for (idx = 0; idx < ttl; idx++) { + if(ret == sgx_errlist[idx].err) { + if(NULL != sgx_errlist[idx].sug) + printf("Info: %s\n", sgx_errlist[idx].sug); + printf("Error: %s\n", sgx_errlist[idx].msg); + break; + } + } + + if (idx == ttl) + printf("Error code is 0x%X. Please refer to the \"Intel SGX SDK Developer Reference\" for more details.\n", ret); +} + +/* Initialize the enclave: + * Call sgx_create_enclave to initialize an enclave instance + */ +int initialize_enclave(void) +{ + sgx_status_t ret = SGX_ERROR_UNEXPECTED; + + /* Call sgx_create_enclave to initialize an enclave instance */ + /* Debug Support: set 2nd parameter to 1 */ + ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL); + if (ret != SGX_SUCCESS) { + print_error_message(ret); + return -1; + } + + return 0; +} + +/* OCall functions */ +void ocall_print_string(const char *str) +{ + /* Proxy/Bridge will check the length and null-terminate + * the input string to prevent buffer overflow. + */ + printf("%s", str); +} + +int test_tcs(); + +static atomic counter_failures; + +#include //rand +void driver(int sid) +{ + sgx_status_t ret = SGX_ERROR_UNEXPECTED; + int retval = 0; + do{ + usleep(rand()%11); + ret = ecall_test_sgx_mm(global_eid, &retval, sid); + if (ret == SGX_SUCCESS){ + printf("test_sgx_mm returned %d\n", retval); + counter_failures += retval; + }else if (ret == SGX_ERROR_OUT_OF_TCS){ + printf("!!! enclave out of TCS, retrying...\n"); + continue; + }else + { + printf("ret = %d\n", ret); + abort(); + } + //test_tcs does its own retry + counter_failures += test_tcs(); + return; + }while(true); +} + + +int test_unsafe() +{ + sgx_status_t ret = SGX_ERROR_UNEXPECTED; + int retval = 0; + ret = ecall_test_sgx_mm_unsafe(global_eid, &retval); + if (ret == SGX_SUCCESS){ + if(retval) + printf("!!! test_sgx_mm_unsafe returned %d\n", retval); + else + printf("*** unsafe tests passed\n"); + return retval; + }else + abort(); +} + + +typedef struct ms_ecall_check_context_t { + int ms_retval; + size_t ms_tcs; +} ms_ecall_check_context_t; + +extern "C" { +#include "sgx.h" +} +vdso_sgx_enter_enclave_t vdso_sgx_enter_enclave; + +#define EENTER 2 + +int ecall_check_context_manual(int* retval, size_t tcs) +{ + ms_ecall_check_context_t ms; + ms.ms_tcs = tcs; + ms.ms_retval= -1; + struct sgx_enclave_run run; + memset(&run, 0, sizeof(run)); + run.tcs = (__u64)tcs; +/******** + !NOTE: hardcoded ecall number. Needs update if edl changes +*******/ + int ret = vdso_sgx_enter_enclave((unsigned long)3, (unsigned long)(&ms), 0, EENTER, + 0, 0, &run); + if (ret == 0) *retval = ms.ms_retval; + return ret; +} +#include +#include +void* get_vdso_sym(const char* vdso_func_name) +{ + char* dynstr = 0; + void *ret = NULL; + + uint8_t* vdso_addr = (uint8_t*)getauxval(AT_SYSINFO_EHDR); + Elf64_Ehdr* elf_header = (Elf64_Ehdr*)vdso_addr; + Elf64_Shdr* section_header = (Elf64_Shdr*)(vdso_addr + elf_header->e_shoff); + + for (int i = 0; i < elf_header->e_shnum; i++) { + auto& s = section_header[i]; + auto& ss_ = section_header[elf_header->e_shstrndx]; + auto name = (char*)(vdso_addr + ss_.sh_offset + s.sh_name); + if (strcmp(name, ".dynstr") == 0) { + dynstr = (char*)(vdso_addr + s.sh_offset); + break; + } + } + + for (int i = 0; i < elf_header->e_shnum; i++) { + auto& s = section_header[i]; + auto& ss_ = section_header[elf_header->e_shstrndx]; + auto name = (char*)(vdso_addr + ss_.sh_offset + s.sh_name); + if (strcmp(name, ".dynsym") == 0) { + for (unsigned int si = 0; si < (s.sh_size/s.sh_entsize); si++) { + auto &sym = ((Elf64_Sym*)(vdso_addr + s.sh_offset))[si]; + auto vdname = dynstr + sym.st_name; + if (strcmp(vdname, vdso_func_name) == 0) { + ret = (vdso_addr + sym.st_value); + break; + } + } + if (ret) break; + } + } + return ret; +} + +#define fastcall __attribute__((regparm(3),noinline,visibility("default"))) +//this function is used to notify GDB scripts +//GDB is supposed to have a breakpoint on urts_add_tcs to receive debug interupt +//once the breakpoint has been hit, GDB extracts the address of tcs and sets DBGOPTIN for the tcs +extern "C" void fastcall urts_add_tcs(tcs_t * const tcs) +{ + (void)(tcs); +} + +int test_tcs() +{ + if(vdso_sgx_enter_enclave == NULL) + return 0; //skip this test + sgx_status_t ret = SGX_ERROR_UNEXPECTED; + size_t tcs = 0; + + do { + usleep(rand()%11); + ret = ecall_alloc_context(global_eid, &tcs); + if (ret == SGX_SUCCESS){ + if (tcs > 1) { + printf("*** test_alloc_context returned 0X%LX\n", tcs); + break; + } else { + printf("!!! alloc context failed\n"); + return 1; + } + }else if (ret == SGX_ERROR_OUT_OF_TCS){ + continue; + }else + abort(); + } while (true); + + urts_add_tcs((tcs_t*)tcs);//turn on sgx-gdb + int retval = 0; + int r = ecall_check_context_manual(&retval, tcs); + + if (r == 0){ + if (retval) { + printf("!!! check tcs returned %d\n", retval); + return 1; + } + else + printf("*** check tcs passed\n"); + }else + abort(); + + do { + usleep(rand()%11); + ret = ecall_dealloc_context(global_eid, &retval, tcs); + if (ret == SGX_SUCCESS) { + if(retval) { + printf("!!! test_deaalloc_context returned %d\n", retval); + return 1; + } + else{ + printf("*** dealloc context pass\n"); + return 0; + } + } else if (ret == SGX_ERROR_OUT_OF_TCS){ + continue; + }else + abort(); + } while (true); + return 0; +} + +/* ecall_thread_functions: + * Invokes thread functions including mutex, condition variable, etc. + */ +int test_sgx_mm_functions(int num_threads) +{ + vector threads; + for (int i=0; i< num_threads; i++) + threads.push_back(new thread(driver, i)); + + for (int i=0; i< num_threads; i++) + { + threads[i]->join(); + delete threads[i]; + } + + if(counter_failures) + { + printf("!!! Fail in %d threads\n", static_cast(counter_failures)); + }else + printf("*** All threads ran successfully.\n"); + return counter_failures; +} + + + +/* Application entry */ +int SGX_CDECL main(int argc, char *argv[]) +{ + (void)(argc); + (void)(argv); + + + vdso_sgx_enter_enclave = (vdso_sgx_enter_enclave_t)get_vdso_sym("__vdso_sgx_enter_enclave"); + /* Initialize the enclave */ + if(initialize_enclave() < 0){ + printf("Failed initialize enclave.\n"); + return -1; + } + //srand (time(NULL)); + srand ((3141596/1618)*271828); + int ret = 0; + + //17 threads for 100 iterations passed when this is checked in + ret += test_sgx_mm_functions(2); // FIXME: 247 freeze on NUC. + ret += test_unsafe(); + + sgx_destroy_enclave(global_eid); + if (!ret) + printf("*** All tests pass.\n"); + else + printf("!!! %d test(s) failed.\n", ret); + + return ret; +} + diff --git a/sdk/trts/trts_emodpr.cpp b/external/sgx-emm/api_tests/App/App.h similarity index 58% rename from sdk/trts/trts_emodpr.cpp rename to external/sgx-emm/api_tests/App/App.h index 79d85ebd8..ec2de43c8 100644 --- a/sdk/trts/trts_emodpr.cpp +++ b/external/sgx-emm/api_tests/App/App.h @@ -30,50 +30,45 @@ */ -#include "trts_emodpr.h" +#ifndef _APP_H_ +#define _APP_H_ -#include "sgx_trts.h" // for sgx_ocalloc, sgx_is_outside_enclave -#include "arch.h" -#include "sgx_edger8r.h" // for sgx_ocall etc. -#include "internal/rts.h" +#include +#include +#include +#include -/* sgx_ocfree() just restores the original outside stack pointer. */ -#define OCALLOC(val, type, len) do { \ - void* __tmp = sgx_ocalloc(len); \ - if (__tmp == NULL) { \ - sgx_ocfree(); \ - return SGX_ERROR_UNEXPECTED;\ - } \ - (val) = (type)__tmp; \ -} while (0) +#include "sgx_error.h" /* sgx_status_t */ +#include "sgx_eid.h" /* sgx_enclave_id_t */ -typedef struct ms_change_permissions_ocall_t { - size_t ms_addr; - size_t ms_size; - uint64_t ms_epcm_perms; -} ms_change_permissions_ocall_t; - -sgx_status_t SGXAPI change_permissions_ocall(size_t addr, size_t size, uint64_t epcm_perms, const int proc) -{ -#ifdef SE_SIM - (void)addr; - (void)size; - (void)epcm_perms; - (void)proc; - return SGX_SUCCESS; -#else - sgx_status_t status = SGX_SUCCESS; +#ifndef TRUE +# define TRUE 1 +#endif - ms_change_permissions_ocall_t* ms; - OCALLOC(ms, ms_change_permissions_ocall_t*, sizeof(*ms)); +#ifndef FALSE +# define FALSE 0 +#endif - ms->ms_addr = addr; - ms->ms_size = size; - ms->ms_epcm_perms = epcm_perms; - status = sgx_ocall(proc, ms); +# define TOKEN_FILENAME "enclave.token" +# define ENCLAVE_FILENAME "enclave.signed.so" +extern sgx_enclave_id_t global_eid; /* global enclave id */ - sgx_ocfree(); - return status; +#if defined(__cplusplus) +extern "C" { #endif + +void edger8r_array_attributes(void); +void edger8r_type_attributes(void); +void edger8r_pointer_attributes(void); +void edger8r_function_attributes(void); + +void ecall_libc_functions(void); +void ecall_libcxx_functions(void); +void ecall_thread_functions(void); + +#if defined(__cplusplus) } +#endif + +#endif /* !_APP_H_ */ diff --git a/external/sgx-emm/api_tests/App/sgx.h b/external/sgx-emm/api_tests/App/sgx.h new file mode 100644 index 000000000..b2fbcee9d --- /dev/null +++ b/external/sgx-emm/api_tests/App/sgx.h @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright(c) 2016-20 Intel Corporation. + */ +#ifndef _UAPI_ASM_X86_SGX_H +#define _UAPI_ASM_X86_SGX_H + +#include +#include + +/** + * enum sgx_page_flags - page control flags + * %SGX_PAGE_MEASURE: Measure the page contents with a sequence of + * ENCLS[EEXTEND] operations. + */ +enum sgx_page_flags { + SGX_PAGE_MEASURE = 0x01, +}; + +#define SGX_MAGIC 0xA4 + +#define SGX_IOC_ENCLAVE_CREATE \ + _IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create) +#define SGX_IOC_ENCLAVE_ADD_PAGES \ + _IOWR(SGX_MAGIC, 0x01, struct sgx_enclave_add_pages) +#define SGX_IOC_ENCLAVE_INIT \ + _IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init) +#define SGX_IOC_ENCLAVE_PROVISION \ + _IOW(SGX_MAGIC, 0x03, struct sgx_enclave_provision) +#define SGX_IOC_PAGE_MODP \ + _IOWR(SGX_MAGIC, 0x04, struct sgx_page_modp) +#define SGX_IOC_PAGE_MODT \ + _IOWR(SGX_MAGIC, 0x05, struct sgx_page_modt) +#define SGX_IOC_PAGE_REMOVE \ + _IOWR(SGX_MAGIC, 0x06, struct sgx_page_remove) + +/** + * struct sgx_enclave_create - parameter structure for the + * %SGX_IOC_ENCLAVE_CREATE ioctl + * @src: address for the SECS page data + */ +struct sgx_enclave_create { + __u64 src; +}; + +/** + * struct sgx_enclave_add_pages - parameter structure for the + * %SGX_IOC_ENCLAVE_ADD_PAGE ioctl + * @src: start address for the page data + * @offset: starting page offset + * @length: length of the data (multiple of the page size) + * @secinfo: address for the SECINFO data + * @flags: page control flags + * @count: number of bytes added (multiple of the page size) + */ +struct sgx_enclave_add_pages { + __u64 src; + __u64 offset; + __u64 length; + __u64 secinfo; + __u64 flags; + __u64 count; +}; + +/** + * struct sgx_enclave_init - parameter structure for the + * %SGX_IOC_ENCLAVE_INIT ioctl + * @sigstruct: address for the SIGSTRUCT data + */ +struct sgx_enclave_init { + __u64 sigstruct; +}; + +/** + * struct sgx_enclave_provision - parameter structure for the + * %SGX_IOC_ENCLAVE_PROVISION ioctl + * @fd: file handle of /dev/sgx_provision + */ +struct sgx_enclave_provision { + __u64 fd; +}; + +/** + * struct sgx_page_modp - parameter structure for the %SGX_IOC_PAGE_MODP ioctl + * @offset: starting page offset (page aligned relative to enclave base + * address defined in SECS) + * @length: length of memory (multiple of the page size) + * @prot: new protection bits of pages in range described by @offset + * and @length + * @result: SGX result code of ENCLS[EMODPR] function + * @count: bytes successfully changed (multiple of page size) + */ +struct sgx_page_modp { + __u64 offset; + __u64 length; + __u64 prot; + __u64 result; + __u64 count; +}; + +/** + * struct sgx_page_modt - parameter structure for the %SGX_IOC_PAGE_MODT ioctl + * @offset: starting page offset (page aligned relative to enclave base + * address defined in SECS) + * @length: length of memory (multiple of the page size) + * @type: new type of pages in range described by @offset and @length + * @result: SGX result code of ENCLS[EMODT] function + * @count: bytes successfully changed (multiple of page size) + */ +struct sgx_page_modt { + __u64 offset; + __u64 length; + __u64 type; + __u64 result; + __u64 count; +}; + +/** + * struct sgx_page_remove - parameters for the %SGX_IOC_PAGE_REMOVE ioctl + * @offset: starting page offset (page aligned relative to enclave base + * address defined in SECS) + * @length: length of memory (multiple of the page size) + * @count: bytes successfully changed (multiple of page size) + * + * Regular (PT_REG) or TCS (PT_TCS) can be removed from an initialized + * enclave if the system supports SGX2. First, the %SGX_IOC_PAGE_MODT ioctl + * should be used to change the page type to PT_TRIM. After that succeeds + * ENCLU[EACCEPT] should be run from within the enclave and then can this + * ioctl be used to complete the page removal. + */ +struct sgx_page_remove { + __u64 offset; + __u64 length; + __u64 count; +}; + +struct sgx_enclave_run; + +/** + * typedef sgx_enclave_user_handler_t - Exit handler function accepted by + * __vdso_sgx_enter_enclave() + * @run: The run instance given by the caller + * + * The register parameters contain the snapshot of their values at enclave + * exit. An invalid ENCLU function number will cause -EINVAL to be returned + * to the caller. + * + * Return: + * - <= 0: The given value is returned back to the caller. + * - > 0: ENCLU function to invoke, either EENTER or ERESUME. + */ +typedef int (*sgx_enclave_user_handler_t)(long rdi, long rsi, long rdx, + long rsp, long r8, long r9, + struct sgx_enclave_run *run); + +/** + * struct sgx_enclave_run - the execution context of __vdso_sgx_enter_enclave() + * @tcs: TCS used to enter the enclave + * @function: The last seen ENCLU function (EENTER, ERESUME or EEXIT) + * @exception_vector: The interrupt vector of the exception + * @exception_error_code: The exception error code pulled out of the stack + * @exception_addr: The address that triggered the exception + * @user_handler: User provided callback run on exception + * @user_data: Data passed to the user handler + * @reserved Reserved for future extensions + * + * If @user_handler is provided, the handler will be invoked on all return paths + * of the normal flow. The user handler may transfer control, e.g. via a + * longjmp() call or a C++ exception, without returning to + * __vdso_sgx_enter_enclave(). + */ +struct sgx_enclave_run { + __u64 tcs; + __u32 function; + __u16 exception_vector; + __u16 exception_error_code; + __u64 exception_addr; + __u64 user_handler; + __u64 user_data; + __u8 reserved[216]; +}; + +/** + * typedef vdso_sgx_enter_enclave_t - Prototype for __vdso_sgx_enter_enclave(), + * a vDSO function to enter an SGX enclave. + * @rdi: Pass-through value for RDI + * @rsi: Pass-through value for RSI + * @rdx: Pass-through value for RDX + * @function: ENCLU function, must be EENTER or ERESUME + * @r8: Pass-through value for R8 + * @r9: Pass-through value for R9 + * @run: struct sgx_enclave_run, must be non-NULL + * + * NOTE: __vdso_sgx_enter_enclave() does not ensure full compliance with the + * x86-64 ABI, e.g. doesn't handle XSAVE state. Except for non-volatile + * general purpose registers, EFLAGS.DF, and RSP alignment, preserving/setting + * state in accordance with the x86-64 ABI is the responsibility of the enclave + * and its runtime, i.e. __vdso_sgx_enter_enclave() cannot be called from C + * code without careful consideration by both the enclave and its runtime. + * + * All general purpose registers except RAX, RBX and RCX are passed as-is to the + * enclave. RAX, RBX and RCX are consumed by EENTER and ERESUME and are loaded + * with @function, asynchronous exit pointer, and @run.tcs respectively. + * + * RBP and the stack are used to anchor __vdso_sgx_enter_enclave() to the + * pre-enclave state, e.g. to retrieve @run.exception and @run.user_handler + * after an enclave exit. All other registers are available for use by the + * enclave and its runtime, e.g. an enclave can push additional data onto the + * stack (and modify RSP) to pass information to the optional user handler (see + * below). + * + * Most exceptions reported on ENCLU, including those that occur within the + * enclave, are fixed up and reported synchronously instead of being delivered + * via a standard signal. Debug Exceptions (#DB) and Breakpoints (#BP) are + * never fixed up and are always delivered via standard signals. On synchronously + * reported exceptions, -EFAULT is returned and details about the exception are + * recorded in @run.exception, the optional sgx_enclave_exception struct. + * + * Return: + * - 0: ENCLU function was successfully executed. + * - -EINVAL: Invalid ENCL number (neither EENTER nor ERESUME). + */ +typedef int (*vdso_sgx_enter_enclave_t)(unsigned long rdi, unsigned long rsi, + unsigned long rdx, unsigned int function, + unsigned long r8, unsigned long r9, + struct sgx_enclave_run *run); + +#endif /* _UAPI_ASM_X86_SGX_H */ diff --git a/external/sgx-emm/api_tests/Enclave/Enclave.cpp b/external/sgx-emm/api_tests/Enclave/Enclave.cpp new file mode 100644 index 000000000..c7d809bc0 --- /dev/null +++ b/external/sgx-emm/api_tests/Enclave/Enclave.cpp @@ -0,0 +1,884 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "Enclave.h" +#include "Enclave_t.h" /* print_string */ +#include +#include /* vsnprintf */ +#include +#include +#include "../../emm_src/include/sgx_mm.h" +#define SGX_PAGE_SIZE 4096 +#include "sgx_thread.h" +#include +#include "sgx_trts.h" +#include "../tcs.h" +using namespace std; +/* + * printf: + * Invokes OCALL to display the enclave buffer to the terminal. + */ +int printf(const char* fmt, ...) +{ + char buf[4096*2] = { '\0' }; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, BUFSIZ, fmt, ap); + va_end(ap); + ocall_print_string(buf); + return (int)strnlen(buf, BUFSIZ - 1) + 1; +} + +#define LOG(fmt, ...) do { \ + printf("[%s %s:%d] " fmt, __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__); \ +}while(0) + + +#define EXPECT_EQ(a, b) \ + do { \ + if ((a) != (b)){ \ + LOG( #a " expected:" #b " got: %lu\n", (uint64_t)(a)); \ + return 1; \ + }\ + } while(0); + +#define EXPECT_NEQ(a, b) \ + do { \ + if ((a) == (b)) {\ + LOG( #a " not expected: " #b "\n" ); \ + return 1; \ + }\ + } while(0); + +const size_t ALLOC_SIZE = 0x2000; +vector allocated_blocks; +sgx_thread_mutex_t mutex = SGX_THREAD_MUTEX_INITIALIZER; + +int test_sgx_mm_alloc_dealloc() +{ + int ret = sgx_mm_dealloc(0, ALLOC_SIZE); + EXPECT_EQ(ret, EINVAL); + // we should be able to alloc, commit, uncommit + // in multiple threads without interference + void* addr = 0; + ret = sgx_mm_alloc(NULL, ALLOC_SIZE, + SGX_EMA_COMMIT_NOW, NULL, NULL, &addr); + + EXPECT_EQ(ret, 0); + EXPECT_NEQ(addr, NULL); + ret = sgx_mm_dealloc(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + + return 0; +} + +int test_sgx_mm_alloc_commit_uncommit() +{ + int ret = sgx_mm_dealloc(0, ALLOC_SIZE); + EXPECT_EQ(ret, EINVAL); + // we should be able to alloc, commit, uncommit + // in multiple threads without interference + void* addr = 0; + ret = sgx_mm_alloc(NULL, ALLOC_SIZE, + SGX_EMA_COMMIT_NOW, NULL, NULL, &addr); + + EXPECT_EQ(ret, 0); + EXPECT_NEQ(addr, NULL); + + ret = sgx_mm_commit(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + + void* addr1 = NULL; + ret = sgx_mm_alloc(addr, ALLOC_SIZE, + SGX_EMA_COMMIT_NOW | SGX_EMA_FIXED, NULL, NULL, &addr1); + + EXPECT_EQ(ret, EEXIST); + EXPECT_EQ(addr1, NULL); + ret = sgx_mm_uncommit(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + ret = sgx_mm_uncommit(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); //we do nothing if it's already uncommitted + + ret = sgx_mm_commit(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + + //no longer use these areas, ready to be + // released by any thread + sgx_thread_mutex_lock(&mutex); + allocated_blocks.push_back(addr); + sgx_thread_mutex_unlock(&mutex); + return 0; +} +/* + * Only release areas previously stored + * by other threads as ready to be released + */ +int test_sgx_mm_dealloc() +{ + int res = 0; + sgx_thread_mutex_lock(&mutex); + auto it = allocated_blocks.begin(); + while ( it!=allocated_blocks.end()){ + int ret = sgx_mm_dealloc(*it, ALLOC_SIZE); + if(ret){ + res ++; + LOG("!!! failed dealloc, errno = %d\n", ret); + it++; + }else + it = allocated_blocks.erase(it); + } + sgx_thread_mutex_unlock(&mutex); + return res; +} + +int test_sgx_mm_alloc_dealloc_unsafe1() +{ +// allocation, deallocation + int ret = sgx_mm_dealloc(0, ALLOC_SIZE); + EXPECT_EQ(ret, EINVAL); + + void* addr = 0; + ret = sgx_mm_alloc(NULL, ALLOC_SIZE, + SGX_EMA_COMMIT_NOW, NULL, NULL, &addr); + + EXPECT_EQ(ret, 0); + EXPECT_NEQ(addr, NULL); + + ret = sgx_mm_commit(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + + void* addr1 = NULL; + ret = sgx_mm_alloc(addr, ALLOC_SIZE, + SGX_EMA_COMMIT_NOW|SGX_EMA_FIXED, NULL, NULL, &addr1); + + EXPECT_EQ(ret, EEXIST); + EXPECT_EQ(addr1, NULL); + + ret = sgx_mm_uncommit(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + + ret = sgx_mm_uncommit(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); //we do nothing if it's already uncommitted + + ret = sgx_mm_commit(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + + ret = sgx_mm_dealloc(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + + ret = sgx_mm_dealloc(addr, ALLOC_SIZE); + EXPECT_EQ(ret, EINVAL); + + ret = sgx_mm_uncommit(addr, ALLOC_SIZE); + EXPECT_EQ(ret, EINVAL); // error if it's already deallocated + + void* addr2 = NULL; + ret = sgx_mm_alloc(addr, ALLOC_SIZE, + SGX_EMA_COMMIT_ON_DEMAND|SGX_EMA_FIXED, NULL, NULL, &addr2); + + EXPECT_EQ(ret, 0); + EXPECT_EQ(addr2, addr);//mm should realloc to the given addr + + ret = sgx_mm_dealloc(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + + ret = sgx_mm_alloc(addr, ALLOC_SIZE, + SGX_EMA_COMMIT_ON_DEMAND|SGX_EMA_FIXED, NULL, NULL, &addr2); + + EXPECT_EQ(ret, 0); + EXPECT_EQ(addr, addr2); + + ret = sgx_mm_alloc(addr, ALLOC_SIZE, + SGX_EMA_COMMIT_ON_DEMAND, NULL, NULL, &addr2); + + EXPECT_EQ(ret, 0); + EXPECT_NEQ(addr, addr2); + + uint8_t *data= (uint8_t*)addr2; + data[0]=0xFF; + data[ALLOC_SIZE-1]=0xFF; + + ret = sgx_mm_dealloc(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + + ret = sgx_mm_dealloc(addr2, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + + return 0; +} + +#include +typedef struct _pfdata +{ + sgx_pfinfo pf; + union { + int access; // access that triggers PF, R/W/X + int magic; + }; + void* addr_expected; + jmp_buf jbuf; // used for jmp_handler only +} pf_data_t; + +int jmp_handler(const sgx_pfinfo *pfinfo, void *private_data) +{ + pf_data_t* pd = (pf_data_t *) private_data; + memcpy(private_data, pfinfo, sizeof(*pfinfo)); + void* addr = (void*) pd->pf.maddr; + if (pd->pf.pfec.rw == 0 + && addr == pd->addr_expected) + { + int ret = sgx_mm_commit(addr, SGX_PAGE_SIZE); + if (ret) abort(); + memset(addr, pd->magic, SGX_PAGE_SIZE); + longjmp(pd->jbuf, 1); + abort(); //won't reach here + } + return SGX_MM_EXCEPTION_CONTINUE_SEARCH; +} + +int test_sgx_mm_alloc_jmp() +{ + + void* addr = 0; + pf_data_t pd; + memset((void*) &pd, 0, sizeof(pd)); + int ret = sgx_mm_alloc(NULL, ALLOC_SIZE, + SGX_EMA_COMMIT_ON_DEMAND, &jmp_handler, &pd, &addr); + + EXPECT_EQ(ret, 0); + EXPECT_NEQ(addr, NULL); + const int MAGIC = 0x55UL; + + uint8_t* data = (uint8_t*)addr; + pd.magic = MAGIC; + pd.addr_expected = addr; + if (0 == setjmp(pd.jbuf)) { + uint8_t d0 = 0; + d0 = data[0]; + EXPECT_NEQ (d0, 0); //should not come here + }else { + uint8_t d0 = data[0]; + + EXPECT_EQ (d0, MAGIC); + EXPECT_EQ (pd.pf.pfec.rw, 0); //Read caused PF + EXPECT_EQ (pd.pf.pfec.sgx, 1); // sgx bit set + } + + ret = sgx_mm_dealloc(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + return 0; +} + +int permissions_handler(const sgx_pfinfo *pfinfo, void *private_data) +{ + pf_data_t* pd = (pf_data_t *) private_data; + memcpy(private_data, pfinfo, sizeof(*pfinfo)); + void* addr = (void*) pd->pf.maddr; + if(pd->pf.pfec.rw == 1 && pd->access == SGX_EMA_PROT_WRITE){ + sgx_mm_modify_permissions(addr, SGX_PAGE_SIZE, SGX_EMA_PROT_WRITE | SGX_EMA_PROT_READ); + }else if (pd->pf.pfec.rw == 0 && (pd->access & SGX_EMA_PROT_READ )){//R or RX + sgx_mm_modify_permissions(addr, SGX_PAGE_SIZE, pd->access); + }else + abort(); + return SGX_MM_EXCEPTION_CONTINUE_EXECUTION; +} + +int commit_data_handler(const sgx_pfinfo *pfinfo, void *private_data) +{ + pf_data_t* pd = (pf_data_t *) private_data; + memcpy(private_data, pfinfo, sizeof(*pfinfo)); + void* addr = (void*) pd->pf.maddr; + + if (pd->access == SGX_EMA_PROT_WRITE + && pd->pf.pfec.rw == 1 + && addr == pd->addr_expected) + { + int ret = sgx_mm_modify_permissions(addr, SGX_PAGE_SIZE, SGX_EMA_PROT_WRITE | SGX_EMA_PROT_READ); + if(ret) abort(); + return SGX_MM_EXCEPTION_CONTINUE_EXECUTION; + } + + if (addr == pd->addr_expected) + { + void* data = 0; + int ret = sgx_mm_alloc(NULL, SGX_PAGE_SIZE, SGX_EMA_COMMIT_NOW, + NULL, NULL, &data); + if(ret) abort(); + assert(data!=0); + memset(data, pd->magic, SGX_PAGE_SIZE); + ret = sgx_mm_commit_data(addr, SGX_PAGE_SIZE, (uint8_t*)data, + SGX_EMA_PROT_READ); + if(ret) abort(); + ret = sgx_mm_dealloc((void*)data, SGX_PAGE_SIZE); + if(ret) abort(); + return SGX_MM_EXCEPTION_CONTINUE_EXECUTION; + }else + return SGX_MM_EXCEPTION_CONTINUE_SEARCH; +} + +static const int MAX_NESTED_HANDLER = 10; +int nested_handler(const sgx_pfinfo *pfinfo, void *private_data) +{ + pf_data_t* orig_pd = (pf_data_t *) private_data; + memcpy(private_data, pfinfo, sizeof(*pfinfo)); + void* addr = (void*) orig_pd->pf.maddr; + + if (addr == orig_pd->addr_expected) + { + void* data = 0; + if (orig_pd->magic == MAX_NESTED_HANDLER) + { + int ret = sgx_mm_alloc(NULL, SGX_PAGE_SIZE, SGX_EMA_COMMIT_NOW, + NULL, NULL, &data); + if (ret) abort(); + assert(data!=0); + memset(data, orig_pd->magic, SGX_PAGE_SIZE); + ret = sgx_mm_commit_data(addr, SGX_PAGE_SIZE, (uint8_t*)data, + SGX_EMA_PROT_READ); + if (ret) abort(); + } else + { + pf_data_t nested_pd; + memset((void*) &nested_pd, 0, sizeof(nested_pd)); + int ret = sgx_mm_alloc(NULL, SGX_PAGE_SIZE, + SGX_EMA_COMMIT_ON_DEMAND, + &nested_handler, + &nested_pd, &data); + + if (ret) abort(); + assert(data != 0); + nested_pd.addr_expected = data; + nested_pd.magic = orig_pd->magic + 1; + ret = sgx_mm_commit_data(addr, SGX_PAGE_SIZE, (uint8_t*)data, + SGX_EMA_PROT_READ); + if (ret) abort(); + if (nested_pd.pf.pfec.errcd == 0) abort(); //READ suceess with PF + if (nested_pd.pf.pfec.rw != 0) abort(); //READ indicated in PFEC + } + int ret = sgx_mm_dealloc((void*)data, SGX_PAGE_SIZE); + if (ret) abort(); + return SGX_MM_EXCEPTION_CONTINUE_EXECUTION; + }else + return SGX_MM_EXCEPTION_CONTINUE_SEARCH; +} + +int test_sgx_mm_permissions() +{ + + void* addr = 0; + pf_data_t pd; + memset((void*) &pd, 0, sizeof(pd)); + int ret = sgx_mm_alloc(NULL, ALLOC_SIZE, + SGX_EMA_COMMIT_NOW, &permissions_handler, &pd, &addr); + + EXPECT_EQ(ret, 0); + EXPECT_NEQ(addr, NULL); + + uint8_t* data = (uint8_t*)addr; + uint8_t d0 = data[0]; + EXPECT_EQ(d0, 0); + EXPECT_EQ (pd.pf.pfec.errcd, 0); //Read suceess without PF + data[0] = 0xFF; + EXPECT_EQ (pd.pf.pfec.errcd, 0); //WRITE suceess without PF + + // permissions reduction + ret = sgx_mm_modify_permissions(addr, ALLOC_SIZE/2, SGX_EMA_PROT_READ); + EXPECT_EQ(ret, 0); + + pd.access = SGX_EMA_PROT_READ; + d0 = data[0]; + EXPECT_EQ(d0, 0xFF); + EXPECT_EQ (pd.pf.pfec.errcd, 0); //Read suceess without PF + + pd.access = SGX_EMA_PROT_WRITE; + data[ALLOC_SIZE-1] = 0xFF; + EXPECT_EQ (pd.pf.pfec.errcd, 0); //WRITE suceess without PF + + pd.access = SGX_EMA_PROT_WRITE; + data[0] = 0xFF; + EXPECT_NEQ (pd.pf.pfec.errcd, 0); //WRITE suceess with PF + EXPECT_EQ (pd.pf.pfec.rw, 1); //WRITE indicated in PFEC + + // permissions reduction + ret = sgx_mm_modify_permissions(addr + ALLOC_SIZE/2, ALLOC_SIZE/2, SGX_EMA_PROT_NONE); + EXPECT_EQ(ret, 0); + + //no longer used, ready to be released by any thread + //we could dealloc here but to make it more interesting... + sgx_thread_mutex_lock(&mutex); + allocated_blocks.push_back(addr); + sgx_thread_mutex_unlock(&mutex); + + return 0; +} + +int test_sgx_mm_permissions_dealloc() +{ + void* addr = 0; + pf_data_t pd; + memset((void*) &pd, 0, sizeof(pd)); + int ret = sgx_mm_alloc(NULL, ALLOC_SIZE, + SGX_EMA_COMMIT_NOW, &permissions_handler, &pd, &addr); + + EXPECT_EQ(ret, 0); + EXPECT_NEQ(addr, NULL); + + uint8_t* data = (uint8_t*)addr; + uint8_t d0 = data[0]; + EXPECT_EQ(d0, 0); + EXPECT_EQ (pd.pf.pfec.errcd, 0); //Read suceess without PF + data[0] = 0xFF; + EXPECT_EQ (pd.pf.pfec.errcd, 0); //WRITE suceess without PF + + // permissions reduction + ret = sgx_mm_modify_permissions(addr, ALLOC_SIZE/2, SGX_EMA_PROT_READ); + EXPECT_EQ(ret, 0); + + pd.access = SGX_EMA_PROT_READ; + d0 = data[0]; + EXPECT_EQ(d0, 0xFF); + EXPECT_EQ (pd.pf.pfec.errcd, 0); //Read suceess without PF + + pd.access = SGX_EMA_PROT_WRITE; + data[ALLOC_SIZE-1] = 0xFF; + EXPECT_EQ (pd.pf.pfec.errcd, 0); //WRITE suceess without PF + + pd.access = SGX_EMA_PROT_WRITE; + data[0] = 0xFF; + EXPECT_NEQ (pd.pf.pfec.errcd, 0); //WRITE suceess with PF + EXPECT_EQ (pd.pf.pfec.rw, 1); //WRITE indicated in PFEC + + memset((void*) &pd, 0, sizeof(pd)); + pd.access = SGX_EMA_PROT_READ|SGX_EMA_PROT_EXEC; + + + ret = sgx_mm_dealloc(addr, ALLOC_SIZE); + EXPECT_EQ(ret, 0); + EXPECT_EQ (pd.pf.pfec.errcd, 0); // no PF + + return 0; +} + +int test_sgx_mm_commit_data() +{ + void* addr = 0; + const int MAGIC = 0x55UL; + pf_data_t pd; + memset((void*) &pd, 0, sizeof(pd)); + int ret = sgx_mm_alloc(NULL, ALLOC_SIZE, + SGX_EMA_COMMIT_ON_DEMAND, + &commit_data_handler, + &pd, &addr); + + EXPECT_EQ(ret, 0); + EXPECT_NEQ(addr, NULL); + + pd.addr_expected = addr; + pd.magic = MAGIC; + + uint8_t* data = (uint8_t*)addr; + for (int i =0; ioentry = (size_t)(&enclave_entry) - enclave_base; + tcs->cssa = 0; + tcs->nssa = 2; + tcs->ofs_limit = tcs->ogs_limit = (uint32_t)-1; + tcs->ossa = (size_t) ssa - enclave_base; + tcs->ofs_base = (size_t)tls - enclave_base; + tcs->ogs_base = (size_t)tls - enclave_base; + + ret =sgx_mm_modify_type(ptcs, SGX_PAGE_SIZE, SGX_EMA_PAGE_TYPE_TCS); + + EXPECT_EQ(ret, 0); + return (size_t) ptcs; +} + +int ecall_check_context(size_t tcs) +{ + return 0; +} + +int ecall_dealloc_context(size_t tcs) +{ + size_t base = tcs - 37*SGX_PAGE_SIZE; + size_t size = (16 * 3 + 5 + 1 + 2 + 1) * SGX_PAGE_SIZE; + + int ret = sgx_mm_dealloc ((void*)base, size); + + EXPECT_EQ(ret, 0); + + return 0; +} diff --git a/external/sgx-emm/api_tests/Enclave/Enclave.edl b/external/sgx-emm/api_tests/Enclave/Enclave.edl new file mode 100644 index 000000000..be3fc5775 --- /dev/null +++ b/external/sgx-emm/api_tests/Enclave/Enclave.edl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +enclave { + from "sgx_tstdc.edl" import sgx_thread_wait_untrusted_event_ocall, sgx_thread_set_untrusted_event_ocall; + trusted { + public int ecall_test_sgx_mm(int seq_id); + public int ecall_test_sgx_mm_unsafe(void); + public size_t ecall_alloc_context(void); + public int ecall_check_context(size_t tcs); + public int ecall_dealloc_context(size_t tcs); + }; + untrusted { + void ocall_print_string([in, string] const char *str); + }; + +}; diff --git a/external/sgx-emm/api_tests/Enclave/Enclave.h b/external/sgx-emm/api_tests/Enclave/Enclave.h new file mode 100644 index 000000000..f6bb82b59 --- /dev/null +++ b/external/sgx-emm/api_tests/Enclave/Enclave.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _ENCLAVE_H_ +#define _ENCLAVE_H_ + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +int printf(const char* fmt, ...); + +#if defined(__cplusplus) +} +#endif + +#endif /* !_ENCLAVE_H_ */ diff --git a/external/sgx-emm/api_tests/Enclave/Enclave.lds b/external/sgx-emm/api_tests/Enclave/Enclave.lds new file mode 100644 index 000000000..0d5614f55 --- /dev/null +++ b/external/sgx-emm/api_tests/Enclave/Enclave.lds @@ -0,0 +1,11 @@ +enclave.so +{ + global: + g_global_data_sim; + g_global_data; + enclave_entry; + g_peak_heap_used; + g_peak_rsrv_mem_committed; + local: + *; +}; diff --git a/external/sgx-emm/api_tests/Enclave/Enclave_private_test.pem b/external/sgx-emm/api_tests/Enclave/Enclave_private_test.pem new file mode 100644 index 000000000..529d07be3 --- /dev/null +++ b/external/sgx-emm/api_tests/Enclave/Enclave_private_test.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG4gIBAAKCAYEAroOogvsj/fZDZY8XFdkl6dJmky0lRvnWMmpeH41Bla6U1qLZ +AmZuyIF+mQC/cgojIsrBMzBxb1kKqzATF4+XwPwgKz7fmiddmHyYz2WDJfAjIveJ +ZjdMjM4+EytGlkkJ52T8V8ds0/L2qKexJ+NBLxkeQLfV8n1mIk7zX7jguwbCG1Pr +nEMdJ3Sew20vnje+RsngAzdPChoJpVsWi/K7cettX/tbnre1DL02GXc5qJoQYk7b +3zkmhz31TgFrd9VVtmUGyFXAysuSAb3EN+5VnHGr0xKkeg8utErea2FNtNIgua8H +ONfm9Eiyaav1SVKzPHlyqLtcdxH3I8Wg7yqMsaprZ1n5A1v/levxnL8+It02KseD +5HqV4rf/cImSlCt3lpRg8U5E1pyFQ2IVEC/XTDMiI3c+AR+w2jSRB3Bwn9zJtFlW +KHG3m1xGI4ck+Lci1JvWWLXQagQSPtZTsubxTQNx1gsgZhgv1JHVZMdbVlAbbRMC +1nSuJNl7KPAS/VfzAgEDAoIBgHRXxaynbVP5gkO0ug6Qw/E27wzIw4SmjsxG6Wpe +K7kfDeRskKxESdsA/xCrKkwGwhcx1iIgS5+Qscd1Yg+1D9X9asd/P7waPmWoZd+Z +AhlKwhdPsO7PiF3e1AzHhGQwsUTt/Y/aSI1MpHBvy2/s1h9mFCslOUxTmWw0oj/Q +ldIEgWeNR72CE2+jFIJIyml6ftnb6qzPiga8Bm48ubKh0kvySOqnkmnPzgh+JBD6 +JnBmtZbfPT97bwTT+N6rnPqOOApvfHPf15kWI8yDbprG1l4OCUaIUH1AszxLd826 +5IPM+8gINLRDP1MA6azECPjTyHXhtnSIBZCyWSVkc05vYmNXYUNiXWMajcxW9M02 +wKzFELO8NCEAkaTPxwo4SCyIjUxiK1LbQ9h8PSy4c1+gGP4LAMR8xqP4QKg6zdu9 +osUGG/xRe/uufgTBFkcjqBHtK5L5VI0jeNIUAgW/6iNbYXjBMJ0GfauLs+g1VsOm +WfdgXzsb9DYdMa0OXXHypmV4GwKBwQDUwQj8RKJ6c8cT4vcWCoJvJF00+RFL+P3i +Gx2DLERxRrDa8AVGfqaCjsR+3vLgG8V/py+z+dxZYSqeB80Qeo6PDITcRKoeAYh9 +xlT3LJOS+k1cJcEmlbbO2IjLkTmzSwa80fWexKu8/Xv6vv15gpqYl1ngYoqJM3pd +vzmTIOi7MKSZ0WmEQavrZj8zK4endE3v0eAEeQ55j1GImbypSf7Idh7wOXtjZ7WD +Dg6yWDrri+AP/L3gClMj8wsAxMV4ZR8CgcEA0fzDHkFa6raVOxWnObmRoDhAtE0a +cjUj976NM5yyfdf2MrKy4/RhdTiPZ6b08/lBC/+xRfV3xKVGzacm6QjqjZrUpgHC +0LKiZaMtccCJjLtPwQd0jGQEnKfMFaPsnhOc5y8qVkCzVOSthY5qhz0XNotHHFmJ +gffVgB0iqrMTvSL7IA2yqqpOqNRlhaYhNl8TiFP3gIeMtVa9rZy31JPgT2uJ+kfo +gV7sdTPEjPWZd7OshGxWpT6QfVDj/T9T7L6tAoHBAI3WBf2DFvxNL2KXT2QHAZ9t +k3imC4f7U+wSE6zILaDZyzygA4RUbwG0gv8/TJVn2P/Eynf76DuWHGlaiLWnCbSz +Az2DHBQBBaku409zDQym3j1ugMRjzzSQWzJg0SIyBH3hTmnYcn3+Uqcp/lEBvGW6 +O+rsXFt3pukqJmIV8HzLGGaLm62BHUeZf3dyWm+i3p/hQAL7Xvu04QW70xuGqdr5 +afV7p5eaeQIJXyGQJ0eylV/90+qxjMKiB1XYg6WYvwKBwQCL/ddpgOdHJGN8uRom +e7Zq0Csi3hGheMKlKbN3vcxT5U7MdyHtTZZOJbTvxKNNUNYH/8uD+PqDGNneb29G +BfGzvI3EASyLIcGZF3OhKwZd0jUrWk2y7Vhob91jwp2+t73vdMbkKyI4mHOuXvGv +fg95si9oO7EBT+Oqvhccd2J+F1IVXncccYnF4u5ZGWt5lLewN/pVr7MjjykeaHqN +t+rfnQam2psA6fL4zS2zTmZPzR2tnY8Y1GBTi0Ko1OKd1HMCgcAb5cB/7/AQlhP9 +yQa04PLH9ygQkKKptZp7dy5WcWRx0K/hAHRoi2aw1wZqfm7VBNu2SLcs90kCCCxp +6C5sfJi6b8NpNbIPC+sc9wsFr7pGo9SFzQ78UlcWYK2Gu2FxlMjonhka5hvo4zvg +WxlpXKEkaFt3gLd92m/dMqBrHfafH7VwOJY2zT3WIpjwuk0ZzmRg5p0pG/svVQEH +NZmwRwlopysbR69B/n1nefJ84UO50fLh5s5Zr3gBRwbWNZyzhXk= +-----END RSA PRIVATE KEY----- diff --git a/external/sgx-emm/api_tests/Enclave/config.xml b/external/sgx-emm/api_tests/Enclave/config.xml new file mode 100644 index 000000000..f96ddcd47 --- /dev/null +++ b/external/sgx-emm/api_tests/Enclave/config.xml @@ -0,0 +1,21 @@ + + 0 + 0 + 248 + 3 + 1 + 248 + + 0x10000 + 0x2000 + 0xF0000000 + 0x9000 + 0x08000 + 0x90000000 + + 0 + 1 + 0xFFFFFFFF + diff --git a/external/sgx-emm/api_tests/Makefile b/external/sgx-emm/api_tests/Makefile new file mode 100644 index 000000000..4f49bc834 --- /dev/null +++ b/external/sgx-emm/api_tests/Makefile @@ -0,0 +1,265 @@ +# +# Copyright (C) 2011-2021 Intel Corporation. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# + +######## SGX SDK Settings ######## + +SGX_SDK ?= /opt/intel/sgxsdk +SGX_MODE ?= HW +SGX_ARCH ?= x64 +SGX_DEBUG ?= 1 + +include $(SGX_SDK)/buildenv.mk + +ifeq ($(shell getconf LONG_BIT), 32) + SGX_ARCH := x86 +else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32) + SGX_ARCH := x86 +endif + +ifeq ($(SGX_ARCH), x86) + SGX_COMMON_FLAGS := -m32 + SGX_LIBRARY_PATH := $(SGX_SDK)/lib + SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x86/sgx_sign + SGX_EDGER8R := $(SGX_SDK)/bin/x86/sgx_edger8r +else + SGX_COMMON_FLAGS := -m64 + SGX_LIBRARY_PATH := $(SGX_SDK)/lib64 + SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign + SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_edger8r +endif + +ifeq ($(SGX_DEBUG), 1) +ifeq ($(SGX_PRERELEASE), 1) +$(error Cannot set SGX_DEBUG and SGX_PRERELEASE at the same time!!) +endif +endif + +ifeq ($(SGX_DEBUG), 1) + SGX_COMMON_FLAGS += -O0 -g +else + SGX_COMMON_FLAGS += -O2 +endif + +SGX_COMMON_FLAGS += -Wall -Wextra -Winit-self -Wpointer-arith -Wreturn-type \ + -Waddress -Wsequence-point -Wformat-security \ + -Wmissing-include-dirs -Wfloat-equal -Wundef -Wshadow \ + -Wcast-align -Wcast-qual -Wconversion -Wredundant-decls +SGX_COMMON_CFLAGS := $(SGX_COMMON_FLAGS) -Wjump-misses-init -Wstrict-prototypes -Wunsuffixed-float-constants +SGX_COMMON_CXXFLAGS := $(SGX_COMMON_FLAGS) -Wnon-virtual-dtor -std=c++11 + +######## App Settings ######## + +ifneq ($(SGX_MODE), HW) + Urts_Library_Name := sgx_urts_sim +else + Urts_Library_Name := sgx_urts +endif + +App_Cpp_Files := App/App.cpp +App_Include_Paths := -IApp -I$(SGX_SDK)/include + +App_C_Flags := -fPIC -Wno-attributes $(App_Include_Paths) + +# Three configuration modes - Debug, prerelease, release +# Debug - Macro DEBUG enabled. +# Prerelease - Macro NDEBUG and EDEBUG enabled. +# Release - Macro NDEBUG enabled. +ifeq ($(SGX_DEBUG), 1) + App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG +else ifeq ($(SGX_PRERELEASE), 1) + App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG +else + App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG +endif + +App_Cpp_Flags := $(App_C_Flags) +App_Link_Flags := -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lpthread + +App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o) + +App_Name := test_mm_api + +######## Enclave Settings ######## + +ifneq ($(SGX_MODE), HW) + Trts_Library_Name := sgx_trts_sim + Service_Library_Name := sgx_tservice_sim +else + Trts_Library_Name := sgx_trts + Service_Library_Name := sgx_tservice +endif +Crypto_Library_Name := sgx_tcrypto + +Enclave_Cpp_Files := Enclave/Enclave.cpp +Enclave_Include_Paths := -IEnclave -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/libcxx + +Enclave_C_Flags := $(Enclave_Include_Paths) -nostdinc -fvisibility=hidden -fpie -ffunction-sections -fdata-sections $(MITIGATION_CFLAGS) +CC_BELOW_4_9 := $(shell expr "`$(CC) -dumpversion`" \< "4.9") +ifeq ($(CC_BELOW_4_9), 1) + Enclave_C_Flags += -fstack-protector +else + Enclave_C_Flags += -fstack-protector-strong +endif + +Enclave_Cpp_Flags := $(Enclave_C_Flags) -nostdinc++ + +# Enable the security flags +Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack + +# To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries: +# 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options, +# so that the whole content of trts is included in the enclave. +# 2. For other libraries, you just need to pull the required symbols. +# Use `--start-group' and `--end-group' to link these libraries. +# Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options. +# Otherwise, you may get some undesirable errors. +Enclave_Link_Flags := $(MITIGATION_LDFLAGS) $(Enclave_Security_Link_Flags) \ + -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_TRUSTED_LIBRARY_PATH) \ + -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ + -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ + -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ + -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ + -Wl,--defsym,__ImageBase=0 -Wl,--gc-sections \ + -Wl,--version-script=Enclave/Enclave.lds + +Enclave_Cpp_Objects := $(sort $(Enclave_Cpp_Files:.cpp=.o)) + +Enclave_Name := enclave.so +Signed_Enclave_Name := enclave.signed.so +Enclave_Config_File := Enclave/config.xml + +ifeq ($(SGX_MODE), HW) +ifeq ($(SGX_DEBUG), 1) + Build_Mode = HW_DEBUG +else ifeq ($(SGX_PRERELEASE), 1) + Build_Mode = HW_PRERELEASE +else + Build_Mode = HW_RELEASE +endif +else +ifeq ($(SGX_DEBUG), 1) + Build_Mode = SIM_DEBUG +else ifeq ($(SGX_PRERELEASE), 1) + Build_Mode = SIM_PRERELEASE +else + Build_Mode = SIM_RELEASE +endif +endif + + +.PHONY: all target run +all: .config_$(Build_Mode)_$(SGX_ARCH) + @$(MAKE) target + +ifeq ($(Build_Mode), HW_RELEASE) +target: $(App_Name) $(Enclave_Name) + @echo "The project has been built in release hardware mode." + @echo "Please sign the $(Enclave_Name) first with your signing key before you run the $(App_Name) to launch and access the enclave." + @echo "To sign the enclave use the command:" + @echo " $(SGX_ENCLAVE_SIGNER) sign -key -enclave $(Enclave_Name) -out <$(Signed_Enclave_Name)> -config $(Enclave_Config_File)" + @echo "You can also sign the enclave using an external signing tool." + @echo "To build the project in simulation mode set SGX_MODE=SIM. To build the project in prerelease mode set SGX_PRERELEASE=1 and SGX_MODE=HW." + + +else +target: $(App_Name) $(Signed_Enclave_Name) +ifeq ($(Build_Mode), HW_DEBUG) + @echo "The project has been built in debug hardware mode." +else ifeq ($(Build_Mode), SIM_DEBUG) + @echo "The project has been built in debug simulation mode." +else ifeq ($(Build_Mode), HW_PRERELEASE) + @echo "The project has been built in pre-release hardware mode." +else ifeq ($(Build_Mode), SIM_PRERELEASE) + @echo "The project has been built in pre-release simulation mode." +else + @echo "The project has been built in release simulation mode." +endif + +endif + +run: all +ifneq ($(Build_Mode), HW_RELEASE) + @$(CURDIR)/$(App_Name) + @echo "RUN => $(App_Name) [$(SGX_MODE)|$(SGX_ARCH), OK]" +endif + +.config_$(Build_Mode)_$(SGX_ARCH): + @rm -f .config_* $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.* + @touch .config_$(Build_Mode)_$(SGX_ARCH) + +######## App Objects ######## + +App/Enclave_u.h: $(SGX_EDGER8R) Enclave/Enclave.edl + @cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include + @echo "GEN => $@" + +App/Enclave_u.c: App/Enclave_u.h + +App/Enclave_u.o: App/Enclave_u.c + @$(CC) $(SGX_COMMON_CFLAGS) $(App_C_Flags) -c $< -o $@ + @echo "CC <= $<" + +App/%.o: App/%.cpp App/Enclave_u.h + @$(CXX) $(SGX_COMMON_CXXFLAGS) $(App_Cpp_Flags) -c $< -o $@ + @echo "CXX <= $<" + +$(App_Name): App/Enclave_u.o $(App_Cpp_Objects) + @$(CXX) $^ -o $@ $(App_Link_Flags) + @echo "LINK => $@" + +######## Enclave Objects ######## + +Enclave/Enclave_t.h: $(SGX_EDGER8R) Enclave/Enclave.edl + @cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include + @echo "GEN => $@" + +Enclave/Enclave_t.c: Enclave/Enclave_t.h + +Enclave/Enclave_t.o: Enclave/Enclave_t.c + @$(CC) $(SGX_COMMON_CFLAGS) $(Enclave_C_Flags) -c $< -o $@ + @echo "CC <= $<" + +Enclave/%.o: Enclave/%.cpp Enclave/Enclave_t.h + @$(CXX) $(SGX_COMMON_CXXFLAGS) $(Enclave_Cpp_Flags) -c $< -o $@ + @echo "CXX <= $<" + +$(Enclave_Name): Enclave/Enclave_t.o $(Enclave_Cpp_Objects) + @$(CXX) $^ -o $@ $(Enclave_Link_Flags) + @echo "LINK => $@" + +$(Signed_Enclave_Name): $(Enclave_Name) + @$(SGX_ENCLAVE_SIGNER) sign -key Enclave/Enclave_private_test.pem -enclave $(Enclave_Name) -out $@ -config $(Enclave_Config_File) + @echo "SIGN => $@" + +.PHONY: clean + +clean: + @rm -f .config_* $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.* diff --git a/external/sgx-emm/api_tests/tcs.h b/external/sgx-emm/api_tests/tcs.h new file mode 100644 index 000000000..a6012e3a2 --- /dev/null +++ b/external/sgx-emm/api_tests/tcs.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TCS_H_ +#define TCS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _tcs_t +{ + uint64_t reserved0; /* (0) */ + uint64_t flags; /* (8)bit 0: DBGOPTION */ + uint64_t ossa; /* (16)State Save Area */ + uint32_t cssa; /* (24)Current SSA slot */ + uint32_t nssa; /* (28)Number of SSA slots */ + uint64_t oentry; /* (32)Offset in enclave to which control is transferred on EENTER if enclave INACTIVE state */ + uint64_t reserved1; /* (40) */ + uint64_t ofs_base; /* (48)When added to the base address of the enclave, produces the base address FS segment inside the enclave */ + uint64_t ogs_base; /* (56)When added to the base address of the enclave, produces the base address GS segment inside the enclave */ + uint32_t ofs_limit; /* (64)Size to become the new FS limit in 32-bit mode */ + uint32_t ogs_limit; /* (68)Size to become the new GS limit in 32-bit mode */ +#define TCS_RESERVED_LENGTH 4024 + uint8_t reserved[TCS_RESERVED_LENGTH]; /* (72) */ +}tcs_t; + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/external/sgx-emm/api_tests/test_loop.sh b/external/sgx-emm/api_tests/test_loop.sh new file mode 100755 index 000000000..ea5d95d45 --- /dev/null +++ b/external/sgx-emm/api_tests/test_loop.sh @@ -0,0 +1,17 @@ +let fail=0 +for ((i=1;i<=$1;i++));do + ./test_mm_api + if [ $? -eq 0 ] + then + echo "pass for iteration $i" + else + echo "fail for iteration $i" + let fail=fail+1 + fi +done +if [ $fail -eq 0 ] +then + echo "passed $1 iterations" + else + echo "$fail out of $1 iterations failed" +fi diff --git a/external/sgx-emm/emm_src b/external/sgx-emm/emm_src new file mode 160000 index 000000000..5497098a7 --- /dev/null +++ b/external/sgx-emm/emm_src @@ -0,0 +1 @@ +Subproject commit 5497098a71cd6e791fcbde6f524b334f7b45b80f diff --git a/external/sgx-emm/ut/Makefile b/external/sgx-emm/ut/Makefile new file mode 100644 index 000000000..34a7fa2e8 --- /dev/null +++ b/external/sgx-emm/ut/Makefile @@ -0,0 +1,55 @@ +# +# Copyright (C) 2011-2021 Intel Corporation. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# + +include ../../../buildenv.mk + +CPPFLAGS += -I$(COMMON_DIR)/inc \ + -I$(COMMON_DIR)/inc/internal \ + -DTEST=1 -g + +.PHONY: all clean + +all: test_bit_array test_ema test_public test_emm + +test_bit_array: test_bit_array.c ../emm_src/bit_array.c + @$(CC) $(CPPFLAGS) $^ -o $@ + +test_ema: test_ema.c stub.c ../ema.c ../bit_array.c + @$(CC) $(CPPFLAGS) $^ -o $@ + +test_public: test_public.c stub.c ../sgx_mm.c ../ema.c ../bit_array.c + @$(CC) $(CPPFLAGS) $^ -o $@ + +test_emm: test_emm.c stub.c ../emm_private.c ../sgx_mm.c ../ema.c ../bit_array.c + @$(CC) $(CPPFLAGS) $^ -o $@ + +clean: + @$(RM) test_bit_array test_ema test_public test_emm diff --git a/sdk/trts/trts_trim.cpp b/external/sgx-emm/ut/stub.c similarity index 56% rename from sdk/trts/trts_trim.cpp rename to external/sgx-emm/ut/stub.c index de447033a..8fe080d52 100644 --- a/sdk/trts/trts_trim.cpp +++ b/external/sgx-emm/ut/stub.c @@ -29,58 +29,80 @@ * */ +#include "../sgx_mm_primitives.h" +#include "../sgx_mm_rt_abstraction.h" -#include "trts_trim.h" -#include "sgx_trts.h" // for sgx_ocalloc, sgx_is_outside_enclave -#include "internal/rts.h" +struct _sgx_mm_mutex { + void *impl; +} g_mm_lock; -/* sgx_ocfree() just restores the original outside stack pointer. */ -#define OCALLOC(val, type, len) do { \ - void* __tmp = sgx_ocalloc(len); \ - if (__tmp == NULL) { \ - sgx_ocfree(); \ - return SGX_ERROR_UNEXPECTED;\ - } \ - (val) = (type)__tmp; \ -} while (0) - -typedef struct ms_trim_range_ocall_t { - size_t ms_fromaddr; - size_t ms_toaddr; -} ms_trim_range_ocall_t; - -typedef struct ms_trim_range_commit_ocall_t { - size_t ms_addr; -} ms_trim_range_commit_ocall_t; +int do_eaccept(const sec_info_t* si, size_t addr) +{ + return 0; +} -sgx_status_t SGXAPI trim_range_ocall(size_t fromaddr, size_t toaddr) +int do_eacceptcopy(const sec_info_t* si, size_t addr, size_t src) { - sgx_status_t status = SGX_SUCCESS; + return 0; +} - ms_trim_range_ocall_t* ms; - OCALLOC(ms, ms_trim_range_ocall_t*, sizeof(*ms)); +int do_emodpe(const sec_info_t* si, size_t addr) +{ + return 0; +} - ms->ms_fromaddr = fromaddr; - ms->ms_toaddr = toaddr; - status = sgx_ocall(EDMM_TRIM, ms); +int sgx_mm_alloc_ocall(size_t addr, size_t length, int props, int flags) +{ + return 0; +} +int sgx_mm_modify_ocall(size_t addr, size_t length, int flags_from, int flags_to) +{ + return 0; +} - sgx_ocfree(); - return status; +size_t get_rts_base() +{ + return 0; } -sgx_status_t SGXAPI trim_range_commit_ocall(size_t addr) +size_t get_rts_end() { - sgx_status_t status = SGX_SUCCESS; + return 0x7FFFFF000000; +} - ms_trim_range_commit_ocall_t* ms; - OCALLOC(ms, ms_trim_range_commit_ocall_t*, sizeof(*ms)); +size_t get_user_base() +{ + return 0x7FFFFF000000; +} - ms->ms_addr = addr; - status = sgx_ocall(EDMM_TRIM_COMMIT, ms); +size_t get_user_end() +{ + return 0x7FFFFFFFFFFF; +} +bool sgx_mm_is_within_enclave(const void *ptr, size_t size){ + return true; +} - sgx_ocfree(); - return status; +sgx_mm_mutex* sgx_mm_mutex_create(void) +{ + return &g_mm_lock; +} +int sgx_mm_mutex_lock(sgx_mm_mutex *mutex) +{ + return 0; +} +int sgx_mm_mutex_unlock(sgx_mm_mutex *mutex) +{ + return 0; } +int sgx_mm_mutex_destroy(sgx_mm_mutex *mutex) +{ + return 0; +} +bool sgx_mm_register_pfhandler(sgx_mm_pfhandler_t pfhandler) +{ + return true; +} diff --git a/external/sgx-emm/ut/test_bit_array.c b/external/sgx-emm/ut/test_bit_array.c new file mode 100644 index 000000000..c329fcb88 --- /dev/null +++ b/external/sgx-emm/ut/test_bit_array.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include "bit_array.h" + +int main() +{ + bit_array *ba = bit_array_new_set(31); + + assert(bit_array_size(ba) == 31); + + assert(bit_array_any(ba) == true); + assert(bit_array_none(ba) == false); + + assert(bit_array_test(ba, 0) == true); + assert(bit_array_test(ba, 15) == true); + assert(bit_array_test(ba, 18) == true); + assert(bit_array_test(ba, 24) == true); + assert(bit_array_test(ba, 30) == true); + + assert(bit_array_test_range(ba, 17, 10) == true); + assert(bit_array_all(ba) == true); + + bit_array_reset_range(ba, 17, 10); + assert(bit_array_test_range(ba, 17, 10) == false); + assert(bit_array_test(ba, 17) == false); + assert(bit_array_test(ba, 18) == false); + assert(bit_array_test(ba, 24) == false); + assert(bit_array_test(ba, 26) == false); + assert(bit_array_test(ba, 27) == true); + + bit_array_flip(ba, 30); + assert(bit_array_test(ba, 30) == false); + + bit_array *lo = NULL, *hi = NULL; + int ret = bit_array_split(ba, 0, &lo, &hi); + assert(ret == 0); + assert(lo == NULL); + assert(hi == ba); + + ret = bit_array_split(ba, 31, &lo, &hi); + assert(ret == 0); + assert(lo == ba); + assert(hi == NULL); + + ret = bit_array_split(ba, 17, &lo, &hi); + assert(lo == ba); + assert(ret == 0); + bit_array_delete(lo); + + bit_array *new_ba = NULL, *new_hi = NULL; + ret = bit_array_split(hi, 10, &new_ba, &new_hi); + assert(ret == 0); + assert(new_ba == hi); + assert(bit_array_size(new_ba) == 10); + assert(bit_array_none(new_ba) == true); + assert(bit_array_size(new_hi) == 4); + assert(bit_array_all(new_hi) == false); + assert(bit_array_test(new_hi, 3) == false); + + bit_array_delete(new_ba); + bit_array_delete(new_hi); + return 0; +} diff --git a/external/sgx-emm/ut/test_ema.c b/external/sgx-emm/ut/test_ema.c new file mode 100644 index 000000000..7ceb61408 --- /dev/null +++ b/external/sgx-emm/ut/test_ema.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include "ema.h" + +extern ema_root_t g_user_ema_root; +extern ema_root_t g_rts_ema_root; +struct ema_root_ { + ema_t *guard; +}; + +int main() +{ + //make sure rts is inited. + ema_t *node0 = ema_new(0, 0xFFF00000, + SGX_EMA_COMMIT_NOW, + SGX_EMA_PROT_READ_WRITE | SGX_EMA_PAGE_TYPE_REG, + NULL, NULL, g_rts_ema_root.guard); + + assert(node0); + // find_build/insert node + size_t addr = 0; + ema_t *next_ema = NULL; + bool ret = find_free_region(&g_user_ema_root, + 0x2000, SGX_PAGE_SIZE, &addr, &next_ema); + + assert(ret == true); + assert(addr == 0xFFF00000); + assert(next_ema == g_user_ema_root.guard); + + node0 = ema_new(0xFFF00000, 0x2000, + SGX_EMA_COMMIT_ON_DEMAND, + SGX_EMA_PROT_READ_WRITE | SGX_EMA_PAGE_TYPE_REG, + NULL, NULL, next_ema); + + + // find at/build/push_back node + + ret = find_free_region_at(&g_user_ema_root, 0xFFF03000, + 0x1000, + &next_ema); + + assert(ret == true); + assert(next_ema == g_user_ema_root.guard); + + ema_t *node1 = ema_new(0xFFF03000, 0x1000, + SGX_EMA_COMMIT_NOW, + SGX_EMA_PROT_READ_WRITE | SGX_EMA_PAGE_TYPE_REG, + NULL, NULL, g_user_ema_root.guard); + + + // negative case for find_at + ret = find_free_region_at(&g_user_ema_root, + 0xFFF02000, 0x3000, &next_ema); + + assert(ret == false); + assert(next_ema == NULL); + + + // find_at/build/insert node + ret = find_free_region_at(&g_user_ema_root, + 0xFFF06000, 0x3000, &next_ema); + + assert(ret == true); + assert(next_ema == g_user_ema_root.guard); + + ema_t *node2 = ema_new(0xFFF06000, 0x3000, + SGX_EMA_COMMIT_ON_DEMAND, + SGX_EMA_PROT_READ_WRITE | SGX_EMA_PAGE_TYPE_REG, + NULL, NULL, next_ema); + + // dump current nodes on the root + dump_ema_root(&g_user_ema_root); + + ema_t *first = NULL, *last = NULL; + + // search_ema_range #1 + int r = search_ema_range(&g_user_ema_root, + 0xFFF00000, 0xFFF06000, + &first, &last); + assert(r == 0); + assert(first == node0); + assert(last == node2); + + + // search_ema_range #2 + r = search_ema_range(&g_user_ema_root, + 0xFFF02000, 0xFFF06000, + &first, &last); + assert(r == 0); + assert(first == node1); + assert(last == node2); + + + // search_ema_range #3 + r = search_ema_range(&g_user_ema_root, + 0xFFF02000, 0xFFF09000, + &first, &last); + assert(r == 0); + assert(first == node1); + assert(last == g_user_ema_root.guard); + + // search_ema_range #4 + r = search_ema_range(&g_user_ema_root, + 0xFFF01000, 0xFFF05000, + &first, &last); + assert(r == 0); + assert(first == node0); + assert(last == node2); + + // negative case, middle address region + r = search_ema_range(&g_user_ema_root, + 0xFFF04000, 0xFFF05000, + &first, &last); + assert(r == -1); + assert(first == NULL); + assert(last == NULL); + + // negative case, front address region + r = search_ema_range(&g_user_ema_root, + 0xFFE00000, 0xFFF00000, + &first, &last); + assert(r == -1); + assert(first == NULL); + assert(last == NULL); + + // negative case, rear address region + r = search_ema_range(&g_user_ema_root, + 0xFFF0A000, 0xFFF0B000, + &first, &last); + assert(r == -1); + assert(first == NULL); + assert(last == NULL); + + + // ema split: split point is out of range + ema_t *tmp_node = NULL; + r = ema_split(node0, 0xFFE00000, true, &tmp_node); + assert(tmp_node == NULL); + + // ema split: split point is out of range + tmp_node = NULL; + r = ema_split(node0, 0xFFF02000, false, &tmp_node); + assert(tmp_node == NULL); + + // ema split: split point is within range + size_t node0_base = ema_base(node0); + tmp_node = NULL; + ema_split(node0, 0xFFF01000, true, &tmp_node); + assert(ema_next(tmp_node) == node0); + assert(ema_base(tmp_node) == node0_base); + assert(ema_size(tmp_node) == 0x1000); + + tmp_node = NULL; + r = ema_split_ex(node2, 0xFFF07000, 0xFFF08000, &tmp_node); + assert(ema_base(tmp_node) == 0xFFF07000); + assert(ema_size(tmp_node) == 0x1000); + dump_ema_root(&g_user_ema_root); + destroy_ema_root(&g_user_ema_root); + + return 0; +} diff --git a/external/sgx-emm/ut/test_emm.c b/external/sgx-emm/ut/test_emm.c new file mode 100644 index 000000000..a82330d81 --- /dev/null +++ b/external/sgx-emm/ut/test_emm.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "emm_private.h" +#include "sgx_mm.h" + +int main() +{ + int ret = -1; + void* addr; + ret = mm_alloc((void *)0xFFFF0000, 0x10000, + SGX_EMA_COMMIT_NOW | SGX_EMA_GROWSUP, + NULL, NULL, &addr); + + return ret; +} diff --git a/external/sgx-emm/ut/test_public.c b/external/sgx-emm/ut/test_public.c new file mode 100644 index 000000000..64d15c243 --- /dev/null +++ b/external/sgx-emm/ut/test_public.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sgx_mm.h" + +int main() +{ + int ret = -1; + + ret = sgx_mm_alloc((void *)0xFFFF0000, 0x10000, + SGX_EMA_COMMIT_NOW | SGX_EMA_GROWSUP, + NULL, NULL, NULL); + + return ret; +} diff --git a/linux/installer/common/sdk/BOMs/sdk_base.txt b/linux/installer/common/sdk/BOMs/sdk_base.txt index c9e5f348e..2b4309cd6 100644 --- a/linux/installer/common/sdk/BOMs/sdk_base.txt +++ b/linux/installer/common/sdk/BOMs/sdk_base.txt @@ -26,6 +26,7 @@ DeliveryName InstallName FileCheckSum FileFeature FileOwner /common/inc/sgx_trts.h /package/include/./sgx_trts.h 0 main STP /common/inc/sgx_tseal.h /package/include/./sgx_tseal.h 0 main STP /common/inc/sgx_tstdc.edl /package/include/./sgx_tstdc.edl 0 main STP +/common/inc/sgx_occlum_utils.edl /package/include/./sgx_occlum_utils.edl 0 main Occlum /common/inc/sgx_uae_service.h /package/include/./sgx_uae_service.h 0 main STP /common/inc/sgx_uae_epid.h /package/include/./sgx_uae_epid.h 0 main STP /common/inc/sgx_uae_launch.h /package/include/./sgx_uae_launch.h 0 main STP diff --git a/linux/installer/common/sdk/BOMs/sdk_x64.txt b/linux/installer/common/sdk/BOMs/sdk_x64.txt index d96b24c0b..ca62ff7df 100644 --- a/linux/installer/common/sdk/BOMs/sdk_x64.txt +++ b/linux/installer/common/sdk/BOMs/sdk_x64.txt @@ -34,6 +34,9 @@ DeliveryName InstallName FileCheckSum FileFeature FileOwner /build/linux/libsgx_pclsim.a /package/lib64/libsgx_pclsim.a 0 main STP /build/linux/libsgx_urts_deploy.so /package/lib64/libsgx_urts.so 0 main STP /build/linux/libsgx_urts_sim.so /package/lib64/libsgx_urts_sim.so 0 main STP +/build/linux/libsgx_urts.a /package/lib64/libsgx_urts.a 0 main STP +/build/linux/libsgx_urts_sim.a /package/lib64/libsgx_urts_sim.a 0 main STP +/build/linux/libsgx_urts_sim_with_se_event.a /package/lib64/libsgx_urts_sim_with_se_event.a 0 main STP /build/linux/libc++_Changes_SGX.txt /package/lib64/libc++_Changes_SGX.txt 0 main STP /build/linux/sgx_config_cpusvn /package/bin/x64/sgx_config_cpusvn 0 main STP /build/linux/sgx_edger8r /package/bin/x64/sgx_edger8r 0 main STP diff --git a/linux/installer/common/sgx-aesm-service/Makefile b/linux/installer/common/sgx-aesm-service/Makefile index 71face180..c86ca03fb 100644 --- a/linux/installer/common/sgx-aesm-service/Makefile +++ b/linux/installer/common/sgx-aesm-service/Makefile @@ -42,14 +42,10 @@ AESMD_CONF_DEL=$(if $(wildcard /run/systemd/system/.*),aesmd.conf,$(if $(wildcar AESMD_CONF_PATH=$(if $(wildcard /run/systemd/system/.*),$(if $(wildcard /lib/systemd/system/.*),/lib/systemd/system,/usr/lib/systemd/system),$(if $(wildcard /etc/init/.*),/etc/init/)) ifeq ($(AESMD_CONF_NAME),) -ifneq ($(shell awk -F/ '$$2 == "docker"' /proc/self/cgroup),) AESMD_CONF_NAME=aesmd.service AESMD_CONF_DEL=aesmd.conf AESMD_CONF_PATH=/lib/systemd/system $(warning "You may need to start aesmd manually after it's installed!") -else -$(error "Unsupported platform - neither systemctl nor initctl is found!") -endif endif QE_VER=1.0.0 diff --git a/psw/enclave_common/Makefile b/psw/enclave_common/Makefile index 6627e99c5..583536796 100644 --- a/psw/enclave_common/Makefile +++ b/psw/enclave_common/Makefile @@ -44,9 +44,10 @@ CXXFLAGS += $(ADDED_INC) CFLAGS += -fPIC -Werror -g CFLAGS += $(ADDED_INC) -INC += -I$(SGX_HEADER_DIR) \ +INC += -I$(COMMON_DIR)/inc \ -I$(COMMON_DIR)/inc/internal \ -I$(COMMON_DIR)/inc/internal/linux \ + -I$(LINUX_EXTERNAL_DIR)/sgx-emm/emm_src/include \ -I$(LINUX_PSW_DIR)/urts/ \ -I$(LINUX_PSW_DIR)/urts/linux \ -I$(LINUX_PSW_DIR)/enclave_common @@ -92,7 +93,7 @@ ifndef DEBUG $(OBJCOPY) --add-gnu-debuglink=$(LIBSGX_ENCLAVE_COMMON_DEBUG) $(LIBSGX_ENCLAVE_COMMON) endif -$(OBJ): %.o: %.cpp +$(OBJ): %.o: %.cpp sgx_mm_ocalls.cpp $(CXX) -c $(CXXFLAGS) $(INC) $< -o $@ $(LIBWRAPPER): diff --git a/psw/enclave_common/sgx_enclave_common.cpp b/psw/enclave_common/sgx_enclave_common.cpp index 95e7eb4f6..f3dace1fd 100644 --- a/psw/enclave_common/sgx_enclave_common.cpp +++ b/psw/enclave_common/sgx_enclave_common.cpp @@ -47,12 +47,12 @@ #include #include "se_memcpy.h" #include "se_lock.hpp" +#include "sgx_mm.h" //ubuntu 18.04 use glibc 2.27, doesn't support MAP_FIXED_NOREPLACE #ifndef MAP_FIXED_NOREPLACE #define MAP_FIXED_NOREPLACE 0x100000 #endif - #define POINTER_TO_U64(A) ((__u64)((uintptr_t)(A))) #define SGX_LAUNCH_SO "libsgx_launch.so.1" @@ -1066,7 +1066,6 @@ extern "C" size_t COMM_API enclave_load_data( } - /* enclave_initialize() * Parameters: * base_address [in] - The enclave base address as returned from the enclave_create API. @@ -1312,4 +1311,9 @@ extern "C" bool COMM_API enclave_set_information( return false; } - +uint32_t COMM_API enclave_get_features() +{ + //!TODO + return 0; +} +#include "sgx_mm_ocalls.cpp" diff --git a/psw/enclave_common/sgx_enclave_common.h b/psw/enclave_common/sgx_enclave_common.h index cdedbed98..32f4ef21d 100644 --- a/psw/enclave_common/sgx_enclave_common.h +++ b/psw/enclave_common/sgx_enclave_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2022 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,11 +35,23 @@ #include #include #include +#ifdef _MSC_VER +#include +#endif #ifdef __cplusplus extern "C" { #endif +#ifdef _MSC_VER +/* The following macros are MSVC only */ +#define COMM_API cdecl +#define COMM_IN _In_ +#define COMM_IN_OPT _In_opt_ +#define COMM_OUT _Out_ +#define COMM_OUT_OPT _Out_opt_ +#define COMM_IN_OUT _Inout_ +#else /* The following macros are for GCC only */ #define COMM_API #define COMM_IN @@ -47,9 +59,12 @@ extern "C" { #define COMM_OUT #define COMM_OUT_OPT #define COMM_IN_OUT +#endif #ifndef ENCLAVE_TYPE_SGX #define ENCLAVE_TYPE_SGX 0x00000001 /* An enclave for the Intel Software Guard Extensions (SGX) architecture version 1. */ +#endif +#ifndef ENCLAVE_TYPE_SGX2 #define ENCLAVE_TYPE_SGX2 0x00000002 /* An enclave for the Intel Software Guard Extensions (SGX) architecture version 2. */ #endif #define ENCLAVE_TYPE_SGX1 ENCLAVE_TYPE_SGX @@ -86,9 +101,29 @@ typedef enum { ENCLAVE_PAGE_WRITE = 1 << 1, /* Enables write access to the committed region of pages. */ ENCLAVE_PAGE_EXECUTE = 1 << 2, /* Enables execute access to the committed region of pages. */ ENCLAVE_PAGE_THREAD_CONTROL = 1 << 8, /* The page contains a thread control structure. */ + ENCLAVE_PAGE_REG = 2 << 8, /* The page contains a PT_REG page. */ + ENCLAVE_PAGE_TRIM = 4 << 8, /* The page is trimmed(PT_TRIM). This is for pages which will be trimmed (removed) from the enclave. */ + ENCLAVE_PAGE_SS_FIRST = 5 << 8, /* The page contains the first page of a Shadow Stack (future). */ + ENCLAVE_PAGE_SS_REST = 6 << 8, /* The page contains a non-first page of a Shadow Stack (future). */ ENCLAVE_PAGE_UNVALIDATED = 1 << 12, /* The page contents that you supply are excluded from measurement and content validation. */ } enclave_page_properties_t; +/* + * Hints to OS on how application may use the pages allocated with enclave_alloc. + */ +typedef enum { + ENCLAVE_EMA_NONE = 0, /* No suggestions provided. */ + ENCLAVE_EMA_RESERVE = 1, /* Suggest that the kernel should reserve the memory range and not immediately EAUG pages. */ + ENCLAVE_EMA_COMMIT_NOW = 2, /* Gives a hint that the kernel should EAUG pages immediately. */ + ENCLAVE_EMA_COMMIT_ON_DEMAND = 4, /* Gives a hint that the kernel can EAUG pages later. */ + ENCLAVE_EMA_GROWSDOWN = 16, /* Gives a hint to the kernel that the application will access pages above the + last accessed page. The kernel may want to EAUG pages from higher to lower addresses + with no gaps in addresses above the last committed page. */ + ENCLAVE_EMA_GROWSUP = 32, /* Gives a hint to the kernel that the application will access pages below the + last accessed page. The kernel may want to EAUG pages from lower to higher addresses + with no gaps in addresses below the last committed page. */ +} enclave_alloc_flags_t; + typedef enum { ENCLAVE_LAUNCH_TOKEN = 0x1 } enclave_info_type_t; @@ -100,12 +135,12 @@ typedef enum { #define ENCLAVE_CREATE_EX_EL_RANGE (1 << ENCLAVE_CREATE_EX_EL_RANGE_BIT_IDX) // Reserve Bit 0 for the el_range config //update the following when adding new extended feature -#define _ENCLAVE_CREATE_LAST_EX_FEATURE_IDX_ ENCLAVE_CREATE_EX_EL_RANGE_BIT_IDX +#define _ENCLAVE_CREATE_LAST_EX_FEATURE_IDX_ ENCLAVE_CREATE_EX_EL_RANGE_BIT_IDX #define _ENCLAVE_CREATE_EX_FEATURES_MASK_ (((uint32_t)-1) >> (ENCLAVE_CREATE_MAX_EX_FEATURES_COUNT - 1 - _ENCLAVE_CREATE_LAST_EX_FEATURE_IDX_)) -typedef struct enclave_elrange{ +typedef struct enclave_elrange { uint64_t enclave_image_address; uint64_t elrange_start_address; uint64_t elrange_size; @@ -148,7 +183,7 @@ void* COMM_API enclave_create_ex( COMM_IN const uint32_t ex_features, COMM_IN const void* ex_features_p[32], COMM_OUT_OPT uint32_t* enclave_error); - + /* enclave_create() * Parameters: @@ -175,7 +210,7 @@ void* COMM_API enclave_create( /* enclave_load_data() * Parameters: * target_address [in] - The address in the enclave where you want to load the data. - * target_size [in] - The size of the range that you want to load in the enclave, in bytes. + * target_size [in] - The size of the range that you want to load in the enclave, in bytes. * source_buffer [in, optional] - An optional pointer to the data you want to load into the enclave. * data_properties [in] - The properties of the pages you want to add to the enclave. * enclave_error [out, optional] - An optional pointer to a variable that receives an enclave error code. @@ -193,7 +228,7 @@ size_t COMM_API enclave_load_data( /* enclave_initialize() * Parameters: * base_address [in] - The enclave base address as returned from the enclave_create API. - * info [in] - A pointer to the architecture-specific information to use to initialize the enclave. + * info [in] - A pointer to the architecture-specific information to use to initialize the enclave. * info_size [in] - The length of the structure that the info parameter points to, in bytes. * enclave_error [out, optional] - An optional pointer to a variable that receives an enclave error code. * Return Value: @@ -224,7 +259,7 @@ bool COMM_API enclave_delete( * info_type[in] - Identifies the type of information requested. initialized. * output_info[out] - Pointer to information returned by the API * output_info_size[in, out] - Size of the output_info buffer, in bytes. If the API succeeds, then this will return the number of bytes returned in output_info. If the API fails with, ENCLAVE_INVALID_SIZE, then this will return the required size - * enclave_error [out, optional] - An optional pointer to a variable that receives an enclave error code. + * enclave_error [out, optional] - An optional pointer to a variable that receives an enclave error code. */ bool COMM_API enclave_get_information( COMM_IN void* base_address, @@ -239,7 +274,7 @@ bool COMM_API enclave_get_information( * info_type[in] - Identifies the type of information requested. not been initialized. * input_info[in] - Pointer to information provided to the API * input_info_size[in] - Size of the information, in bytes, provided in input_info from the API. - * enclave_error [out, optional] - An optional pointer to a variable that receives an enclave error code. + * enclave_error [out, optional] - An optional pointer to a variable that receives an enclave error code. */ bool COMM_API enclave_set_information( COMM_IN void* base_address, @@ -247,6 +282,116 @@ bool COMM_API enclave_set_information( COMM_IN void* input_info, COMM_IN size_t input_info_size, COMM_OUT_OPT uint32_t* enclave_error); + +/* enclave_get_features() + * Parameters: + * None + * Return Value: + * Returns flags indicating enclave features which are supported on the platform. + */ +uint32_t COMM_API enclave_get_features(); + +/* enclave_alloc() + * Call OS to reserve region for EAUG, immediately or on-demand. + * + * Parameters + * targt_addr [in] - Desired page aligned start address. + * target_size [in] - Size of the region in bytes of multiples of page size. + * data_properties [in] - Page types to be allocated, must be one of these: + * - ENCLAVE_PAGE_REG: regular page type. This is the default if not specified. + * - ENCLAVE_PAGE_SS_FIRST: the first page in shadow stack. + * - ENCLAVE_PAGE_SS_REST: the rest page in shadow stack. + * alloc_flags [in] - A bitwise OR of flags describing committing mode, committing + * order, address preference, page type. The untrusted side. Implementation + * should always invoke mmap syscall with MAP_SHARED|MAP_FIXED_NOREPLACE, and + * translate following additional bits to proper parameters invoking mmap or + * other SGX specific syscall(s) provided by the kernel. The alloc_flags param + * of this interface should include exactly one of following for committing mode: + * - ENCLAVE_EMA_COMMIT_NOW: reserves memory range with ENCLAVE_PAGE_READ|SGX_EMA_PROT_WRITE, if supported, + * kernel is given a hint to EAUG EPC pages for the area as soon as possible. + * - ENCLAVE_EMA_COMMIT_ON_DEMAND: reserves memory range, EPC pages can be EAUGed upon #PF. + * ORed with zero or one of the committing order flags: + * - ENCLAVE_EMA_GROWSDOWN: if supported, a hint given for the kernel to EAUG pages from higher + * to lower addresses, no gaps in addresses above the last committed. + * - ENCLAVE_EMA_GROWSUP: if supported, a hint given for the kernel to EAUG pages from lower + * to higher addresses, no gaps in addresses below the last committed. + * enclave_error [out, optional] - An optional pointer to a variable that receives an enclave error code. + * + * Return Values: + * ENCLAVE_ERROR_SUCCESS(0): The operation was successful. + * ENCLAVE_NOT_SUPPORTED: Enavle feature is not supported by the system + * ENCLAVE_LOST: May be returned if the enclave has been removed or if it has not been initialized (via EINIT) + * ENCLAVE_INVALID_ADDRESS: The start address does not point to an enclave. + * ENCLAVE_INVALID_PARAMETER: An invalid combination of flags was provided. + * ENCLAVE_OUT_OF_MEMORY: No EPC left (some OSes like Linux), or system is out of memory for internal allocation by OS or this function. + * ENCLAVE_DEVICE_NO_MEMORY: NO EPC left (some OSes like Windows) + * ENCLAVE_INVALID_ADDRESS: Address does not point to an enclave or valid memory within the enclave + * ENCLAVE_NOT_INITIALIZED: May be returned if the enclave has not been initialized (via EINIT). + * Some configurations may give ENCLAVE_LOST if the enclave has not been initialized. + * ENCLAVE_UNEXPECTED: Unexpected error. + */ + +uint32_t COMM_API enclave_alloc ( + COMM_IN void* target_addr, + COMM_IN size_t target_size, + COMM_IN uint32_t data_properties, + COMM_IN uint32_t alloc_flags, + COMM_OUT_OPT uint32_t* enclave_error +); + +/* enclave_modify() + * Call OS to change permissions, type, or notify EACCEPT done after TRIM. + * + * Parameters: + * target_addr [in] - Start address of the memory to change protections. + * target_size [in] - Length of the area. This must be a multiple of the page size. + * from_data_properties [in] - The original EPCM flags of the EPC pages to be modified. + * Must be bitwise OR of following: + * ENCLAVE_PAGE_READ + * ENCLAVE_PAGE_WRITE + * ENCLAVE_PAGE_EXEC + * ENCLAVE_PAGE_REG: regular page, changeable to TRIM or TCS + * ENCLAVE_PAGE_TRIM: signal to the kernel EACCEPT is done for TRIM pages. + * to_data_properties [in] - The target EPCM flags. This must be bitwise OR of following: + * ENCLAVE_PAGE_READ + * ENCLAVE_PAGE_WRITE + * ENCLAVE_PAGE_EXEC + * ENCLAVE_PAGE_TRIM: change the page type to PT_TRIM. Note the address + * range for trimmed pages may still be reserved by enclave with + * proper permissions. + * ENCLAVE_PAGE_TCS: change the page type to PT_TCS + * + * Return Values: + * ENCLAVE_ERROR_SUCCESS(0): The operation was successful. + * ENCLAVE_NOT_SUPPORTED: Enclave feature is not supported by the system + * ENCLAVE_LOST: May be returned if the enclave has been removed or if it has not been initialized (via EINIT) + * ENCLAVE_INVALID_PARAMETER: An invalid combination of flags was provided. + * ENCLAVE_OUT_OF_MEMORY: No EPC left (some OSes like Linux), or system is out of memory for internal allocation by OS or this function. + * ENCLAVE_DEVICE_NO_MEMORY: NO EPC left (some OSes like Windows) + * ENCLAVE_INVALID_ADDRESS: Address does not point to an enclave or valid memory within the enclave + * ENCLAVE_NOT_INITIALIZED: May be returned if the enclave has not been initialized (via EINIT). + * Some configurations may give ENCLAVE_LOST if the enclave has not been initialized. + * ENCLAVE_UNEXPECTED: Unexpected error. + */ + +uint32_t COMM_API enclave_modify ( + COMM_IN void* target_addr, + COMM_IN size_t target_size, + COMM_IN uint32_t from_data_properties, + COMM_IN uint32_t to_data_properties, + COMM_OUT_OPT uint32_t* enclave_error +); + +/** + * The enclave features flags describe additional enclave features + * which are supported by the platform. A value of 0 indicates not features are supported. + */ +typedef enum { + ENCLAVE_FEATURE_NONE = 0, + ENCLAVE_FEATURE_SGX1 = 0x00000001, /* The platform (HW and OS) supports SGX1 */ + ENCLAVE_FEATURE_SGX2 = 0x00000002, /* The platform (HW and OS) supports SGX2 */ +}enclave_features_t; + #ifdef __cplusplus } #endif diff --git a/psw/enclave_common/sgx_enclave_common.lds b/psw/enclave_common/sgx_enclave_common.lds index d76001f15..8621fdf50 100644 --- a/psw/enclave_common/sgx_enclave_common.lds +++ b/psw/enclave_common/sgx_enclave_common.lds @@ -7,6 +7,8 @@ global: enclave_get_information; enclave_set_information; enclave_create_ex; + enclave_alloc; + enclave_modify; local: *; }; diff --git a/psw/enclave_common/sgx_mm_ocalls.cpp b/psw/enclave_common/sgx_mm_ocalls.cpp new file mode 100644 index 000000000..7f29d51e3 --- /dev/null +++ b/psw/enclave_common/sgx_mm_ocalls.cpp @@ -0,0 +1,460 @@ + +//////////////////////////////////////////////////////////// +// OCall impl. These will be part of sgx_enclave_common.cpp +//////////////////////////////////////////////////////////// +#include +using namespace std; +#define PROT_MASK (PROT_READ|PROT_WRITE|PROT_EXEC) + +uint32_t COMM_API enclave_alloc( + COMM_IN void* target_addr, + COMM_IN size_t target_size, + COMM_IN uint32_t data_properties, + COMM_IN uint32_t alloc_flags, + COMM_OUT_OPT uint32_t* enclave_error) +{ + int ret = ENCLAVE_UNEXPECTED; + SE_TRACE(SE_TRACE_DEBUG, + "enclave_alloc for %p ( %llX ) with alloc flags = 0x%lX\n", + target_addr, target_size, alloc_flags); + + if (s_driver_type == SGX_DRIVER_DCAP) + { + if (enclave_error != NULL) + *enclave_error = ret; + return ret; + } + if (s_driver_type == SGX_DRIVER_OUT_OF_TREE) + { + ret = mprotect(target_addr, target_size, PROT_WRITE | PROT_READ); + if ((ret != 0) && (enclave_error != NULL)) + { + *enclave_error = ENCLAVE_UNEXPECTED; + } + return ret; + } + int enclave_fd = get_file_handle_from_address(target_addr); + if (enclave_fd == -1) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_ADDRESS; + return ENCLAVE_INVALID_ADDRESS; + } + int map_flags = MAP_SHARED | MAP_FIXED; + //COMMIT_NOW not supported by kernel yet + if (alloc_flags & ENCLAVE_EMA_COMMIT_NOW) + { + } + //CET pages not supported by kernel yet + int type = data_properties; + if((type == ENCLAVE_PAGE_SS_FIRST) | (type == ENCLAVE_PAGE_SS_REST)) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_NOT_SUPPORTED; + return ENCLAVE_NOT_SUPPORTED; + } + if((type == ENCLAVE_PAGE_SS_FIRST) && target_size > SE_PAGE_SIZE) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_PARAMETER; + return ENCLAVE_INVALID_PARAMETER; + } + void *out = mmap(target_addr, target_size, PROT_WRITE | PROT_READ, map_flags, enclave_fd, 0); + if (out == MAP_FAILED) + { + ret = errno; + SE_TRACE(SE_TRACE_WARNING, "mmap failed, error = %d\n", ret); + ret = error_driver2api(-1, ret); + if (enclave_error != NULL) + *enclave_error = ret; + } + else + { + ret = 0; + } + return ret; +} + +uint64_t get_offset_for_address(uint64_t target_address) +{ + uint64_t enclave_base_addr = (uint64_t)get_enclave_base_address_from_address((void *)target_address); + assert(enclave_base_addr != 0); + assert(target_address >= enclave_base_addr); + return (uint64_t)target_address - (uint64_t)enclave_base_addr; +} + +static int emodt(int fd, void *addr, size_t length, uint64_t type) +{ + struct sgx_enclave_modify_types ioc; + if (length == 0) + return EINVAL; + + SE_TRACE(SE_TRACE_DEBUG, + "MODT for %p ( %llX ), type: 0x%llX\n", + addr, length, type); + memset(&ioc, 0, sizeof(ioc)); + + ioc.page_type = type; + ioc.offset = get_offset_for_address((uint64_t)addr); + ioc.length = length; + do + { + int ret = ioctl(fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc); + + if (ret && ioc.count == 0 && errno != EBUSY && errno != EAGAIN) + { //total failure + int err = errno; + SE_TRACE(SE_TRACE_WARNING, + "MODT failed, error = %d for %p ( %llX ), type: 0x%llX\n", + err, addr, length, type); + return err; + } + //for recoverable partial errors + length -= ioc.count; + ioc.offset += ioc.count; + ioc.result = 0; + ioc.count = 0; + } while (length != 0); + + return 0; +} + +static int trim(int fd, void *addr, size_t length) +{ + return emodt(fd, addr, length, (SGX_EMA_PAGE_TYPE_TRIM >> SGX_EMA_PAGE_TYPE_SHIFT)); +} +static int mktcs(int fd, void *addr, size_t length) +{ + + return emodt(fd, addr, length, (SGX_EMA_PAGE_TYPE_TCS >> SGX_EMA_PAGE_TYPE_SHIFT)); +} +static int trim_accept(int fd, void *addr, size_t length) +{ + struct sgx_enclave_remove_pages ioc; + memset(&ioc, 0, sizeof(ioc)); + + SE_TRACE(SE_TRACE_DEBUG, + "REMOVE for 0x%llX ( %llX )\n", + addr, length); + ioc.offset = get_offset_for_address((uint64_t)addr); + ioc.length = length; + int ret = 0; + do { + ret = ioctl(fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &ioc); + if(ret && ioc.count == 0 && errno != EBUSY && errno != EAGAIN ) + { //total failure + int err = errno; + SE_TRACE(SE_TRACE_WARNING, + "REMOVE failed, error = %d for 0x%llX ( %llX )\n", + err, addr, length); + return err; + } + ioc.length -= ioc.count; + ioc.offset += ioc.count; + ioc.count = 0; + } while (ioc.length != 0); + + return 0; +} +static int emodpr(int fd, void *addr, size_t length, uint64_t prot) +{ + struct sgx_enclave_restrict_permissions ioc; + if (length == 0) + return EINVAL; + + SE_TRACE(SE_TRACE_DEBUG, + "MODP for 0x%llX ( %llX ), prot: 0x%llX\n", + addr, length, prot); + memset(&ioc, 0, sizeof(ioc)); + + ioc.permissions = prot; + ioc.offset = get_offset_for_address((uint64_t)addr); + ioc.length = length; + + do + { + int ret = ioctl(fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, &ioc); + //TODO: use error code + if (ret && ioc.count == 0 && errno != EBUSY && errno!=EAGAIN ) + { //total failure + int err = errno; + SE_TRACE(SE_TRACE_WARNING, + "MODP failed, error = %d for 0x%llX ( %llX ), prot: 0x%llX\n", + err, addr, length, prot); + return err; + } + ioc.length -= ioc.count; + ioc.offset += ioc.count; + ioc.result = 0; + ioc.count = 0; + } while (ioc.length != 0); + + return 0; +} + +// legacy support for EDMM + +static int trim_accept_legacy(int fd, void *addr, size_t len) +{ + sgx_range params; + memset(¶ms, 0, sizeof(sgx_range)); + params.start_addr = (unsigned long)addr; + params.nr_pages = (unsigned int)(len / SE_PAGE_SIZE); + + int ret = ioctl(fd, SGX_IOC_ENCLAVE_NOTIFY_ACCEPT, ¶ms); + + if (ret) + { + return errno; + } + + return SGX_SUCCESS; +} + +static int trim_legacy(int fd, void *fromaddr, uint64_t len) +{ + sgx_range params; + memset(¶ms, 0, sizeof(sgx_range)); + params.start_addr = (unsigned long)fromaddr; + params.nr_pages = (unsigned int)((len) / SE_PAGE_SIZE); + + int ret = ioctl(fd, SGX_IOC_ENCLAVE_TRIM, ¶ms); + if (ret) + { + return errno; + } + + return SGX_SUCCESS; +} + +static int mktcs_legacy(int fd, void *tcs_addr, size_t len) +{ + if (len != SE_PAGE_SIZE) + return EINVAL; + sgx_range params; + memset(¶ms, 0, sizeof(sgx_range)); + params.start_addr = (unsigned long)tcs_addr; + params.nr_pages = 1; + + int ret = ioctl(fd, SGX_IOC_ENCLAVE_MKTCS, ¶ms); + if (ret) + { + return errno; + } + return SGX_SUCCESS; +} + +static int emodpr_legacy(int fd, void *addr, uint64_t size, uint64_t flag) +{ + sgx_modification_param params; + memset(¶ms, 0, sizeof(sgx_modification_param)); + params.range.start_addr = (unsigned long)addr; + params.range.nr_pages = (unsigned int)(size / SE_PAGE_SIZE); + params.flags = (unsigned long)flag; + + int ret = ioctl(fd, SGX_IOC_ENCLAVE_EMODPR, ¶ms); + if (ret) + { + return errno; + } + + return SGX_SUCCESS; +} + +uint32_t COMM_API enclave_modify( + COMM_IN void* target_addr, + COMM_IN size_t target_size, + COMM_IN uint32_t from_data_properties, + COMM_IN uint32_t to_data_properties, + COMM_OUT_OPT uint32_t* enclave_error) +{ + int ret = ENCLAVE_UNEXPECTED; + SE_TRACE(SE_TRACE_DEBUG, + "enclave_modify for %p ( %llX ) from 0x%lX to %lX\n", + target_addr, target_size, from_data_properties, to_data_properties); + if (s_driver_type == SGX_DRIVER_DCAP) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_NOT_SUPPORTED; + return ENCLAVE_NOT_SUPPORTED; + } + uint64_t enclave_base = (uint64_t)get_enclave_base_address_from_address(target_addr); + if (enclave_base == 0) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_ADDRESS; + return ENCLAVE_INVALID_ADDRESS; + } + if (target_size % SE_PAGE_SIZE != 0) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_PARAMETER; + return ENCLAVE_INVALID_PARAMETER; + } + function _trim = trim; + function _trim_accept = trim_accept; + function _mktcs = mktcs; + function _emodpr = emodpr; + int fd = get_file_handle_from_address(target_addr); + if (s_driver_type == SGX_DRIVER_OUT_OF_TREE) + { + _trim = trim_legacy; + _trim_accept = trim_accept_legacy; + _mktcs = mktcs_legacy; + _emodpr = emodpr_legacy; + fd = s_hdevice; + } + if(fd == -1) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_ADDRESS; + return ENCLAVE_INVALID_ADDRESS; + } + + int type_to = (to_data_properties & SGX_EMA_PAGE_TYPE_MASK); + int type_from = (from_data_properties & SGX_EMA_PAGE_TYPE_MASK); + if (type_from == SGX_EMA_PAGE_TYPE_TRIM && type_to != SGX_EMA_PAGE_TYPE_TRIM) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_PARAMETER; + return ENCLAVE_INVALID_PARAMETER; + } + int prot_to = (to_data_properties & PROT_MASK); + int prot_from = (from_data_properties & PROT_MASK); + if ((prot_to != prot_from) && (type_to != type_from)) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_PARAMETER; + return ENCLAVE_INVALID_PARAMETER; + } + + if ((type_from & type_to & SGX_EMA_PAGE_TYPE_TRIM)) + { + //user space can only do EACCEPT for PT_TRIM type + ret = _trim_accept(fd, target_addr, target_size); + if (ret) + { + ret = error_driver2api(-1, ret); + if (enclave_error != NULL) + *enclave_error = ret; + return ret; + } + if (prot_to == PROT_NONE) + { + //EACCEPT done and notified. + //if user wants to remove permissions, + //only mprotect is needed + ret = mprotect(target_addr, target_size, prot_to); + if (ret == -1) + { + ret = error_driver2api(ret, errno); + if (enclave_error != NULL) + *enclave_error = ret; + return ret; + } + } + return ret; + } + + if (type_to == SGX_EMA_PAGE_TYPE_TRIM) + { + assert(type_from != SGX_EMA_PAGE_TYPE_TRIM); + if (prot_to != prot_from) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_PARAMETER; + return ENCLAVE_INVALID_PARAMETER; + } + ret = _trim(fd, target_addr, target_size); + if (ret) + { + ret = error_driver2api(-1, ret); + if (enclave_error != NULL) + *enclave_error = ret; + return ret; + } + return 0; + } + + if (type_to == SGX_EMA_PAGE_TYPE_TCS) + { + if (type_from != SGX_EMA_PAGE_TYPE_REG) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_PARAMETER; + return ENCLAVE_INVALID_PARAMETER; + } + if ((prot_from != (SGX_EMA_PROT_READ_WRITE)) && prot_to != prot_from) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_PARAMETER; + return ENCLAVE_INVALID_PARAMETER; + } + ret = _mktcs(fd, target_addr, target_size); + if (ret) + { + ret = error_driver2api(-1, ret); + if (enclave_error != NULL) + *enclave_error = ret; + return ret; + } + return 0; + } + + if (type_to != type_from) + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_PARAMETER; + return ENCLAVE_INVALID_PARAMETER; + } + // type_to == type_from + // this is for emodpr to epcm.NONE, enclave EACCEPT with pte.R + // separate mprotect is needed to change pte.R to pte.NONE + if (prot_to == prot_from && prot_to == PROT_NONE) + { + ret = mprotect(target_addr, target_size, prot_to); + if (ret == -1) + { + ret = error_driver2api(ret, errno); + if (enclave_error != NULL) + *enclave_error = ret; + return ret; + } + } + + if (prot_to == prot_from) + { + return 0; //nothing to be done. + } + // Permissions changes. Only do emodpr for PT_REG pages + if ((type_from & type_to & SGX_EMA_PAGE_TYPE_MASK) == SGX_EMA_PAGE_TYPE_REG) + { + ret = _emodpr(fd, target_addr, target_size, prot_to); + if (ret) + { + ret = error_driver2api(-1, ret); + if (enclave_error != NULL) + *enclave_error = ret; + return ret; + } + } + else + { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_INVALID_PARAMETER; + return ENCLAVE_INVALID_PARAMETER; + } + //EACCEPT needs at least pte.R, PROT_NONE case done above. + if (prot_to != PROT_NONE) + { + ret = mprotect((void *)target_addr, target_size, prot_to); + if (ret == -1) + { + ret = error_driver2api(ret, errno); + if (enclave_error != NULL) + *enclave_error = ret; + return ret; + } + } + return ret; +} diff --git a/psw/uae_service/linux/Makefile b/psw/uae_service/linux/Makefile index c797b00a9..523c2b03f 100644 --- a/psw/uae_service/linux/Makefile +++ b/psw/uae_service/linux/Makefile @@ -52,8 +52,7 @@ INCLUDE += -I$(COMMON_DIR) \ INCLUDE += -I$(LINUX_PSW_DIR)/ae/common \ -I$(LINUX_PSW_DIR)/ae/inc \ - -I$(LINUX_PSW_DIR)/ae/inc/internal \ - -I$(SGX_HEADER_DIR) + -I$(LINUX_PSW_DIR)/ae/inc/internal INCLUDE += -I$(LINUX_EXTERNAL_DIR)/epid-sdk \ -I$(IPC_COMMON_INC_DIR) \ diff --git a/psw/urts/create_param.h b/psw/urts/create_param.h index 6300d7dad..235427e66 100644 --- a/psw/urts/create_param.h +++ b/psw/urts/create_param.h @@ -51,6 +51,8 @@ typedef struct _create_param_t uint64_t rsrv_init_size; uint64_t rsrv_offset; uint64_t rsrv_executable; + uint64_t user_region_offset; + uint64_t user_region_size; uint64_t first_ssa_gpr; uint64_t td_addr; uint64_t tls_addr; diff --git a/psw/urts/enclave.cpp b/psw/urts/enclave.cpp index b7fdc2afb..8ef2e53d5 100644 --- a/psw/urts/enclave.cpp +++ b/psw/urts/enclave.cpp @@ -40,6 +40,7 @@ #include "se_memory.h" #include "urts_trim.h" #include "urts_emodpr.h" +#include "urts_emm.h" #include "rts_cmd.h" #include #include "rts.h" @@ -352,7 +353,7 @@ sgx_status_t CEnclave::ecall(const int proc, const void *ocall_table, void *ms, se_event_wake(m_new_thread_event); pthread_join(m_pthread_tid, NULL); } - ocall_table = m_ocall_table; + /*ocall_table = m_ocall_table; std::vector threads = m_thread_pool->get_thread_list(); for (unsigned idx = 0; idx < threads.size(); ++idx) @@ -370,6 +371,7 @@ sgx_status_t CEnclave::ecall(const int proc, const void *ocall_table, void *ms, // Change TCS permission to Read only to let driver not handle the // #PF caused by TCS trim. It gives urts a chance to catch the exception // and exit the ecall with an error code. + //!TODO do we really need this? if(0 != mprotect((void *)start, TCS_SIZE, SI_FLAG_R)) { se_rdunlock(&m_rwlock); @@ -381,7 +383,7 @@ sgx_status_t CEnclave::ecall(const int proc, const void *ocall_table, void *ms, return (sgx_status_t)ret; } } - } + }*/ } ret = do_ecall(proc, m_ocall_table, ms, trust_thread); @@ -420,6 +422,10 @@ int CEnclave::ocall(const unsigned int proc, const sgx_ocall_table_t *ocall_tabl error = ocall_emodpr(ms); else if ((int)proc == EDMM_MPROTECT) error = ocall_mprotect(ms); + else if ((int)proc == EDMM_ALLOC) + error = ocall_emm_alloc(ms); + else if ((int)proc == EDMM_MODIFY) + error = ocall_emm_modify(ms); } else { diff --git a/psw/urts/enclave_creator_hw.h b/psw/urts/enclave_creator_hw.h index 15d02e200..6cfe8b4a7 100644 --- a/psw/urts/enclave_creator_hw.h +++ b/psw/urts/enclave_creator_hw.h @@ -61,10 +61,10 @@ class EnclaveCreatorHW : public EnclaveCreator int get_misc_attr(sgx_misc_attribute_t *sgx_misc_attr, metadata_t *metadata, SGXLaunchToken * const lc, uint32_t flag); bool get_plat_cap(sgx_misc_attribute_t *se_attr); int emodpr(uint64_t addr, uint64_t size, uint64_t flag); + int alloc(uint64_t addr, uint64_t size, int flag); int mktcs(uint64_t tcs_addr); int trim_range(uint64_t fromaddr, uint64_t toaddr); int trim_accept(uint64_t addr); - int remove_range(uint64_t fromaddr, uint64_t numpages); private: virtual bool open_device(); virtual void close_device(); diff --git a/psw/urts/enclave_creator_hw_com.cpp b/psw/urts/enclave_creator_hw_com.cpp index 534f7233b..9bfe23d0c 100644 --- a/psw/urts/enclave_creator_hw_com.cpp +++ b/psw/urts/enclave_creator_hw_com.cpp @@ -65,7 +65,7 @@ int EnclaveCreatorHW::initialize(sgx_enclave_id_t enclave_id) init_cpuinfo((uint32_t *)info.cpuinfo_table); info.system_feature_set[0] |= (1ULL << SYS_FEATURE_EXTEND); info.size = sizeof(system_features_t); - info.version = (sdk_version_t)MIN((uint32_t)SDK_VERSION_2_3, enclave->get_enclave_version()); + info.version = (sdk_version_t)MIN((uint32_t)SDK_VERSION_3_0, enclave->get_enclave_version()); info.sealed_key = enclave->get_sealed_key(); info.cpu_core_num = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN); if (is_EDMM_supported(enclave_id)) diff --git a/psw/urts/enclave_mutex.cpp b/psw/urts/enclave_mutex.cpp index 49abe95b9..6588d61a6 100644 --- a/psw/urts/enclave_mutex.cpp +++ b/psw/urts/enclave_mutex.cpp @@ -52,6 +52,21 @@ extern "C" int sgx_thread_wait_untrusted_event_ocall(const void *self) return SGX_SUCCESS; } +extern "C" int sgx_thread_wait_untrusted_event_timeout_ocall(const void *self, int clockbit, const struct timespec *ts, int absolute_time, int *err) +{ + if (self == NULL) + return SGX_ERROR_INVALID_PARAMETER; + + se_handle_t hevent = CEnclavePool::instance()->get_event(self); + if (hevent == NULL) + return SE_ERROR_MUTEX_GET_EVENT; + + if (SE_MUTEX_SUCCESS != se_event_timeout_wait(hevent, clockbit, ts, absolute_time, err)) + return SE_ERROR_MUTEX_WAIT_EVENT; + + return SGX_SUCCESS; +} + /* set untrusted event */ extern "C" int sgx_thread_set_untrusted_event_ocall(const void *waiter) { diff --git a/psw/urts/linux/Makefile b/psw/urts/linux/Makefile index 529d7c2bc..689fd4585 100644 --- a/psw/urts/linux/Makefile +++ b/psw/urts/linux/Makefile @@ -44,13 +44,14 @@ CFLAGS += $(ADDED_INC) VTUNE_DIR = $(LINUX_EXTERNAL_DIR)/vtune/linux -INC += -I$(SGX_HEADER_DIR) \ +INC += -I$(COMMON_DIR)/inc \ -I$(COMMON_DIR)/inc/internal \ -I$(COMMON_DIR)/inc/internal/linux \ -I$(LINUX_PSW_DIR)/enclave_common \ -I$(LINUX_PSW_DIR)/urts/ \ -I$(LINUX_PSW_DIR)/urts/linux \ -I$(LINUX_PSW_DIR)/urts/parser \ + -I$(LINUX_EXTERNAL_DIR)/sgx-emm/emm_src/include \ -I$(VTUNE_DIR)/include \ -I$(VTUNE_DIR)/sdk/src/ittnotify @@ -96,6 +97,7 @@ OBJ2 := urts.o \ get_thread_id.o \ prd_css_util.o \ urts_emodpr.o \ + urts_emm.o \ urts_trim.o \ edmm_utility.o @@ -120,11 +122,13 @@ LIBSGX_ENCLAVE_COMMON := libsgx_enclave_common.a LIBURTS := libsgx_urts.so LIBURTS_INTERNAL := liburts_internal.so LIBURTS_DEBUG := libsgx_urts.so.debug +LIBURTS_STATIC := libsgx_urts.a .PHONY: all -all: $(LIBURTS) $(LIBURTS_INTERNAL) $(LIBURTS_DEBUG) | $(BUILD_DIR) +all: $(LIBURTS) $(LIBURTS_STATIC) $(LIBURTS_INTERNAL) $(LIBURTS_DEBUG) | $(BUILD_DIR) @$(CP) $(LIBURTS) $| + @$(CP) $(LIBURTS_STATIC) $| @$(CP) $(LIBURTS_INTERNAL) $| ifndef DEBUG @$(CP) $(LIBURTS_DEBUG) $| @@ -142,6 +146,15 @@ $(LIBURTS_INTERNAL): $(INTERNAL_OBJ) $(LIBWRAPPER) $(LIBSGX_ENCLAVE_COMMON) ittn $(LIBURTS): $(URTS_OBJ) $(LIBWRAPPER) $(LIBSGX_ENCLAVE_COMMON) ittnotify $(CXX) $(CXXFLAGS) -shared -Wl,-soname=$@ $(LIB) -o $@ $(URTS_OBJ) $(LDFLAGS) +$(LIBURTS_STATIC): $(LIBURTS) + @$(MKDIR) $(BUILD_DIR)/.sgx_static_urts + @$(RM) -f $(BUILD_DIR)/.sgx_static_urts/* + cd $(BUILD_DIR)/.sgx_static_urts && \ + $(AR) x $(COMMON_DIR)/se_wrapper/libwrapper.a && \ + $(AR) x $(VTUNE_DIR)/sdk/src/ittnotify/libittnotify.a && \ + $(RM) -f se_event.o + $(AR) rsD $@ $(URTS_OBJ) $(BUILD_DIR)/.sgx_static_urts/*.o + $(LIBURTS_DEBUG): $(LIBURTS) ifndef DEBUG $(CP) $(LIBURTS) $(LIBURTS).orig @@ -171,7 +184,7 @@ $(BUILD_DIR): .PHONY: clean clean:: - @$(RM) *.o $(LIBURTS) $(LIBURTS_INTERNAL) $(LIBURTS_DEBUG) + @$(RM) *.o $(LIBURTS) $(LIBURTS_INTERNAL) $(LIBURTS_DEBUG) $(LIBURTS_STATIC) @$(RM) $(BUILD_DIR)/$(LIBURTS) $(BUILD_DIR)/$(LIBURTS_INTERNAL) @$(RM) $(LIBURTS).orig $(BUILD_DIR)/$(LIBURTS_DEBUG) $(MAKE) -C $(COMMON_DIR)/se_wrapper_psw/ clean diff --git a/psw/urts/linux/edmm_utility.cpp b/psw/urts/linux/edmm_utility.cpp index 69e701a6b..a7e9f73ce 100644 --- a/psw/urts/linux/edmm_utility.cpp +++ b/psw/urts/linux/edmm_utility.cpp @@ -41,7 +41,7 @@ #include #include #include - +#include #define SGX_URTS_CMD "for f in $(find /usr/$(basename $(gcc -print-multi-os-directory)) -name 'libsgx_urts.so' 2> /dev/null); do strings $f|grep 'SGX_URTS_VERSION_2'; done" #define SGX_CPUID 0x12 @@ -236,8 +236,17 @@ extern "C" bool is_cpu_support_edmm() */ extern "C" bool is_driver_support_edmm(int hdevice) { - if (-1 == hdevice) - return false; + if (-1 == hdevice){ + if(!open_se_device(SGX_DRIVER_IN_KERNEL, &hdevice)) + return false; + struct sgx_enclave_restrict_permissions ioc; + memset(&ioc, 0, sizeof(ioc)); + + int ret = ioctl(hdevice, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, &ioc); + bool supported = ret != -1 || (errno != ENOTTY); + close_se_device(&hdevice); + return supported; + } sgx_modification_param param; param.flags = 0; diff --git a/psw/urts/linux/enclave_creator_hw.cpp b/psw/urts/linux/enclave_creator_hw.cpp index d956e8181..425a7d890 100644 --- a/psw/urts/linux/enclave_creator_hw.cpp +++ b/psw/urts/linux/enclave_creator_hw.cpp @@ -49,7 +49,7 @@ #include #include #include - +#include "sgx_mm.h" #define POINTER_TO_U64(A) ((__u64)((uintptr_t)(A))) static EnclaveCreatorHW g_enclave_creator_hw; @@ -306,103 +306,76 @@ void EnclaveCreatorHW::close_device() m_hdevice = -1; } -int EnclaveCreatorHW::emodpr(uint64_t addr, uint64_t size, uint64_t flag) +int EnclaveCreatorHW::alloc(uint64_t addr, uint64_t size, int flag) { - sgx_modification_param params; - memset(¶ms, 0 ,sizeof(sgx_modification_param)); - params.range.start_addr = (unsigned long)addr; - params.range.nr_pages = (unsigned int)(size/SE_PAGE_SIZE); - params.flags = (unsigned long)flag; - - int ret = ioctl(m_hdevice, SGX_IOC_ENCLAVE_EMODPR, ¶ms); + int ret = enclave_alloc((void *)addr, size, flag, SGX_EMA_COMMIT_ON_DEMAND, NULL); if (ret) { - SE_TRACE(SE_TRACE_ERROR, "SGX_IOC_ENCLAVE_EMODPR failed %d\n", errno); - return error_driver2urts(ret, errno); + SE_TRACE(SE_TRACE_ERROR, "SGX_IOC_ENCLAVE_alloc failed %d\n", ret); + return error_api2urts(ret); } return SGX_SUCCESS; } - -int EnclaveCreatorHW::mktcs(uint64_t tcs_addr) + +int EnclaveCreatorHW::emodpr(uint64_t addr, uint64_t size, uint64_t flag) { - sgx_range params; - memset(¶ms, 0 ,sizeof(sgx_range)); - params.start_addr = (unsigned long)tcs_addr; - params.nr_pages = 1; - int ret = ioctl(m_hdevice, SGX_IOC_ENCLAVE_MKTCS, ¶ms); + int ret = enclave_modify((void *)addr, size, PROT_READ|PROT_WRITE|PROT_EXEC|SGX_EMA_PAGE_TYPE_REG, + (int) (flag|SGX_EMA_PAGE_TYPE_REG), NULL); if (ret) { - SE_TRACE(SE_TRACE_ERROR, "MODIFY_TYPE failed %d\n", errno); - return error_driver2urts(ret, errno); + SE_TRACE(SE_TRACE_ERROR, "SGX_IOC_ENCLAVE_EMODPR failed %d\n", ret); + return error_api2urts(ret); } return SGX_SUCCESS; } -int EnclaveCreatorHW::trim_range(uint64_t fromaddr, uint64_t toaddr) +int EnclaveCreatorHW::mktcs(uint64_t tcs_addr) { - sgx_range params; - memset(¶ms, 0 ,sizeof(sgx_range)); - params.start_addr = (unsigned long)fromaddr; - params.nr_pages = (unsigned int)((toaddr - fromaddr)/SE_PAGE_SIZE); - - int ret= ioctl(m_hdevice, SGX_IOC_ENCLAVE_TRIM, ¶ms); + int ret = enclave_modify((void *)tcs_addr, SE_PAGE_SIZE, PROT_READ|PROT_WRITE|SGX_EMA_PAGE_TYPE_REG, PROT_READ|PROT_WRITE|SGX_EMA_PAGE_TYPE_TCS, NULL); if (ret) { - SE_TRACE(SE_TRACE_ERROR, "SGX_IOC_ENCLAVE_TRIM failed %d\n", errno); - return error_driver2urts(ret, errno); + SE_TRACE(SE_TRACE_ERROR, "MODIFY_TYPE failed %d\n", ret); + return error_api2urts(ret); } return SGX_SUCCESS; - } -int EnclaveCreatorHW::trim_accept(uint64_t addr) +int EnclaveCreatorHW::trim_range(uint64_t fromaddr, uint64_t toaddr) { - sgx_range params; - memset(¶ms, 0 ,sizeof(sgx_range)); - params.start_addr = (unsigned long)addr; - params.nr_pages = 1; - - int ret = ioctl(m_hdevice, SGX_IOC_ENCLAVE_NOTIFY_ACCEPT, ¶ms); - + int ret= enclave_modify( (void *)fromaddr, toaddr - fromaddr, PROT_READ|PROT_WRITE, PROT_READ|PROT_WRITE|SGX_EMA_PAGE_TYPE_TRIM, NULL); if (ret) { - SE_TRACE(SE_TRACE_ERROR, "TRIM_RANGE_COMMIT failed %d\n", errno); - return error_driver2urts(ret, errno); + SE_TRACE(SE_TRACE_ERROR, "SGX_IOC_ENCLAVE_TRIM failed %d\n", ret); + return error_api2urts(ret); } return SGX_SUCCESS; + } -int EnclaveCreatorHW::remove_range(uint64_t fromaddr, uint64_t numpages) +int EnclaveCreatorHW::trim_accept(uint64_t addr) { - int ret = -1; - uint64_t i; - unsigned long start; + int ret = enclave_modify((void *)addr, SE_PAGE_SIZE, SGX_EMA_PAGE_TYPE_TRIM|PROT_READ|PROT_WRITE + , SGX_EMA_PAGE_TYPE_TRIM|PROT_READ|PROT_WRITE, NULL); - for (i = 0; i < numpages; i++) + if (ret) { - start = (unsigned long)fromaddr + (unsigned long)(i << SE_PAGE_SHIFT); - ret = ioctl(m_hdevice, SGX_IOC_ENCLAVE_PAGE_REMOVE, &start); - if (ret) - { - SE_TRACE(SE_TRACE_ERROR, "PAGE_REMOVE failed %d\n", errno); - return error_driver2urts(ret, errno); - } + SE_TRACE(SE_TRACE_ERROR, "TRIM_RANGE_COMMIT failed %d\n", ret); + return error_api2urts(ret); } return SGX_SUCCESS; } - //EDMM is supported if and only if all of the following requirements are met: //1. We operate in HW mode //2. CPU has EDMM support //3. Driver has EDMM support -//4. Both the uRTS version and enclave (metadata) version are higher than 1.5 +//4. SDK version >= 3.0 bool EnclaveCreatorHW::is_EDMM_supported(sgx_enclave_id_t enclave_id) { bool supported = false, driver_supported = false, cpu_edmm = false; @@ -415,7 +388,7 @@ bool EnclaveCreatorHW::is_EDMM_supported(sgx_enclave_id_t enclave_id) driver_supported = is_driver_compatible(); //return value of get_enclave_version() considers the version of uRTS and enclave metadata - supported = use_se_hw() && cpu_edmm && driver_supported && (enclave->get_enclave_version() >= SDK_VERSION_2_0); + supported = use_se_hw() && cpu_edmm && driver_supported && (enclave->get_enclave_version() >= SDK_VERSION_3_0); return supported; } diff --git a/psw/urts/linux/isgx_user.h b/psw/urts/linux/isgx_user.h index 3c4dfdd00..177b50276 100644 --- a/psw/urts/linux/isgx_user.h +++ b/psw/urts/linux/isgx_user.h @@ -4,7 +4,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2016 Intel Corporation. + * Copyright(c) 2016-2022 Intel Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -21,7 +21,7 @@ * * BSD LICENSE * - * Copyright(c) 2016 Intel Corporation. + * Copyright(c) 2016-2022 Intel Corporation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -55,6 +55,7 @@ * Suresh Siddha * Serge Ayoun * Shay Katz-zamir + * Haitao Huang */ #ifndef _UAPI_ASM_X86_SGX_H @@ -108,16 +109,28 @@ enum sgx_page_flags { _IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init) #define SGX_IOC_ENCLAVE_SET_ATTRIBUTE \ _IOW(SGX_MAGIC, 0x03, struct sgx_enclave_set_attribute) +#define SGX_IOC_VEPC_REMOVE_ALL \ + _IO(SGX_MAGIC, 0x04) +#define SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS \ + _IOWR(SGX_MAGIC, 0x05, struct sgx_enclave_restrict_permissions) +#define SGX_IOC_ENCLAVE_MODIFY_TYPES \ + _IOWR(SGX_MAGIC, 0x06, struct sgx_enclave_modify_types) +#define SGX_IOC_ENCLAVE_REMOVE_PAGES \ + _IOWR(SGX_MAGIC, 0x07, struct sgx_enclave_remove_pages) + + +/* Legacy OOT driver support for EDMM */ #define SGX_IOC_ENCLAVE_EMODPR \ _IOW(SGX_MAGIC, 0x09, struct sgx_modification_param) #define SGX_IOC_ENCLAVE_MKTCS \ _IOW(SGX_MAGIC, 0x0a, struct sgx_range) #define SGX_IOC_ENCLAVE_TRIM \ _IOW(SGX_MAGIC, 0x0b, struct sgx_range) + +//Legacy implementation to ensure EPC pages removed no later by this ioctl + #define SGX_IOC_ENCLAVE_NOTIFY_ACCEPT \ _IOW(SGX_MAGIC, 0x0c, struct sgx_range) -#define SGX_IOC_ENCLAVE_PAGE_REMOVE \ - _IOW(SGX_MAGIC, 0x0d, unsigned long) //Note: SGX_IOC_ENCLAVE_CREATE is the same for in-kernel except that it returns a file handle for in-kernel #define SGX_IOC_ENCLAVE_ADD_PAGES_IN_KERNEL \ @@ -267,7 +280,7 @@ struct sgx_enclave_destroy { /* - * SGX2.0 definitions + * SGX2.0 definitions for Legacy OOT driver */ #define SGX_GROW_UP_FLAG 1 @@ -284,6 +297,61 @@ struct sgx_modification_param { }; +/** + * struct sgx_enclave_restrict_permissions - parameters for ioctl + * %SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS + * @offset: starting page offset (page aligned relative to enclave base + * address defined in SECS) + * @length: length of memory (multiple of the page size) + * @permissions:new permission bits for pages in range described by @offset + * and @length + * @result: (output) SGX result code of ENCLS[EMODPR] function + * @count: (output) bytes successfully changed (multiple of page size) + */ +struct sgx_enclave_restrict_permissions { + __u64 offset; + __u64 length; + __u64 permissions; + __u64 result; + __u64 count; +}; + +/** + * struct sgx_enclave_modify_type - parameters for %SGX_IOC_ENCLAVE_MODIFY_TYPES + * @offset: starting page offset (page aligned relative to enclave base + * address defined in SECS) + * @length: length of memory (multiple of the page size) + * @page_type: new type for pages in range described by @offset and @length + * @result: (output) SGX result code of ENCLS[EMODT] function + * @count: (output) bytes successfully changed (multiple of page size) + */ +struct sgx_enclave_modify_types { + __u64 offset; + __u64 length; + __u64 page_type; + __u64 result; + __u64 count; +}; + +/** + * struct sgx_enclave_remove_pages - %SGX_IOC_ENCLAVE_REMOVE_PAGES parameters + * @offset: starting page offset (page aligned relative to enclave base + * address defined in SECS) + * @length: length of memory (multiple of the page size) + * @count: (output) bytes successfully changed (multiple of page size) + * + * Regular (PT_REG) or TCS (PT_TCS) can be removed from an initialized + * enclave if the system supports SGX2. First, the %SGX_IOC_ENCLAVE_MODIFY_TYPE + * ioctl() should be used to change the page type to PT_TRIM. After that + * succeeds ENCLU[EACCEPT] should be run from within the enclave and then + * %SGX_IOC_ENCLAVE_REMOVE_PAGES can be used to complete the page removal. + */ +struct sgx_enclave_remove_pages { + __u64 offset; + __u64 length; + __u64 count; +}; + struct sgx_enclave_run; @@ -363,7 +431,7 @@ struct sgx_enclave_run { * Most exceptions reported on ENCLU, including those that occur within the * enclave, are fixed up and reported synchronously instead of being delivered * via a standard signal. Debug Exceptions (#DB) and Breakpoints (#BP) are - * never fixed up and are always delivered via standard signals. On synchrously + * never fixed up and are always delivered via standard signals. On synchronously * reported exceptions, -EFAULT is returned and details about the exception are * recorded in @run.exception, the optional sgx_enclave_exception struct. * diff --git a/psw/urts/linux/sig_handler.cpp b/psw/urts/linux/sig_handler.cpp index b84d0a227..e99ea2d4b 100644 --- a/psw/urts/linux/sig_handler.cpp +++ b/psw/urts/linux/sig_handler.cpp @@ -86,6 +86,12 @@ typedef struct _ecall_param_t #define ECALL_PARAM (reinterpret_cast(context->uc_mcontext.gregs[REG_EBP] + 2 * 4)) #endif +// Real-time signal 64 is used to trigger an interrupt to an enclave thread +#define SIGRT_INTERRUPT (64) + +/* Known from the kernel driver. Relative to %rbp. */ +#define SGX_ENCLAVE_OFFSET_OF_RUN 16 + extern "C" void *get_aep(); extern "C" void *get_eenterp(); extern "C" void *get_eretp(); @@ -95,15 +101,18 @@ extern "C" int vdso_sgx_enter_enclave_wrapper(unsigned long rdi, unsigned long r unsigned long rdx, unsigned int function, unsigned long r8, unsigned long r9, struct sgx_enclave_run *run); - +static size_t g_sgx_enter_enclave_symbol_start = 0; +static size_t g_sgx_enter_enclave_symbol_end = 0; void reg_sig_handler(); int do_ecall(const int fn, const void *ocall_table, const void *ms, CTrustThread *trust_thread); +// TODO: For simulation mode, the signal should be handled in the old way. void sig_handler(int signum, siginfo_t* siginfo, void *priv) { + UNUSED(siginfo); SE_TRACE(SE_TRACE_DEBUG, "signal handler is triggered\n"); ucontext_t* context = reinterpret_cast(priv); unsigned int *xip = reinterpret_cast(context->uc_mcontext.gregs[REG_XIP]); @@ -112,14 +121,14 @@ void sig_handler(int signum, siginfo_t* siginfo, void *priv) /* `xbx' is only used in assertions. */ size_t xbx = context->uc_mcontext.gregs[REG_XBX]; #endif - ecall_param_t *param = ECALL_PARAM; //the case of exception on ERESUME or within enclave. //We can't distinguish ERESUME exception from exception within enclave. We assume it is the exception within enclave. //If it is ERESUME exception, it will raise another exception in ecall and ecall will return error. - if(xip == get_aep() - && SE_ERESUME == xax) - { + //Here we can't get an accurate address for AEP. We just use the symbol's range of __vdso_sgx_enter_enclave. + if(g_sgx_enter_enclave_symbol_start <= (size_t)xip + && (size_t)xip <= g_sgx_enter_enclave_symbol_end + && SE_ERESUME == xax) { #ifndef SE_SIM assert(ENCLU == (*xip & 0xffffff)); #endif @@ -127,84 +136,54 @@ void sig_handler(int signum, siginfo_t* siginfo, void *priv) SE_TRACE(SE_TRACE_NOTICE, "exception on ERESUME\n"); //The ecall looks recursively, but it will not cause infinite call. //If exception is raised in trts again and again, the SSA will overflow, and finally it is EENTER exception. - assert(reinterpret_cast(xbx) == param->tcs); - CEnclave *enclave = param->trust_thread->get_enclave(); - unsigned int ret = enclave->ecall(ECMD_EXCEPT, param->ocall_table, NULL); - if(SGX_SUCCESS == ret) + int ecmd; + if (signum != SIGRT_INTERRUPT) { + ecmd = ECMD_EXCEPT; + } else { + ecmd = ECMD_INTERRUPT; + } + // This handler is only used to handle interrupt signal. + assert(ecmd == ECMD_INTERRUPT); + + size_t rbp = context->uc_mcontext.gregs[REG_RBP]; + size_t* run_context_addr = reinterpret_cast(rbp + SGX_ENCLAVE_OFFSET_OF_RUN); + struct sgx_enclave_run* run = reinterpret_cast (*run_context_addr); + SE_TRACE(SE_TRACE_DEBUG, "in sig_handler, run_addr = 0x%lx\n", run); + +#ifndef NDEBUG + tcs_t *tcs = reinterpret_cast(xbx); + assert(reinterpret_cast(run->tcs) == tcs); +#endif + + __u64 *user_data = (__u64*)run->user_data; + CTrustThread* trust_thread = reinterpret_cast(user_data[1]); + if (trust_thread == NULL) { - //ERESUME execute + run->user_data = SGX_ERROR_UNEXPECTED; return; } - //If the exception is caused by enclave lost or internal stack overrun, then return the error code to ecall caller elegantly. - else if(SGX_ERROR_ENCLAVE_LOST == ret || SGX_ERROR_STACK_OVERRUN == ret) + + void *ocall_table = reinterpret_cast(user_data[0]); + unsigned int ret = do_ecall(ecmd, ocall_table, NULL, trust_thread); + if(SGX_SUCCESS == ret) { - //enter_enlcave function will return with ret which is from tRTS; - context->uc_mcontext.gregs[REG_XIP] = reinterpret_cast(get_eretp()); - context->uc_mcontext.gregs[REG_XSI] = ret; + //ERESUME execute + SE_TRACE(SE_TRACE_DEBUG, "SIGRT_INTERRUPT handle successful\n"); return; } - //If we can't fix the exception within enclave, then give the handle to other signal hanlder. - //Call the previous signal handler. The default signal handler should terminate the application. - - enclave->rdunlock(); - CEnclavePool::instance()->unref_enclave(enclave); } - //the case of exception on EENTER instruction. - else if(xip == get_eenterp() - && SE_EENTER == xax) + else if (signum == SIGRT_INTERRUPT) { - assert(reinterpret_cast(xbx) == param->tcs); - assert(ENCLU == (*xip & 0xffffff)); - SE_TRACE(SE_TRACE_NOTICE, "exception on EENTER\n"); - //enter_enlcave function will return with SE_ERROR_ENCLAVE_LOST - context->uc_mcontext.gregs[REG_XIP] = reinterpret_cast(get_eretp()); - context->uc_mcontext.gregs[REG_XSI] = SGX_ERROR_ENCLAVE_LOST; + // If not interrupting the enclave, just ignore the signal return; - } - - SE_TRACE(SE_TRACE_DEBUG, "NOT enclave signal\n"); - //it is not SE exception. if the old signal handler is default signal handler, we reset signal handler. - //raise the signal again, and the default signal handler will be called. - if(SIG_DFL == g_old_sigact[signum].sa_handler) - { - signal(signum, SIG_DFL); - raise(signum); - } - //if there is old signal handler, we need transfer the signal to the old signal handler; - else - { - if(!(g_old_sigact[signum].sa_flags & SA_NODEFER)) - sigaddset(&g_old_sigact[signum].sa_mask, signum); - - sigset_t cur_set; - pthread_sigmask(SIG_SETMASK, &g_old_sigact[signum].sa_mask, &cur_set); - - if(g_old_sigact[signum].sa_flags & SA_SIGINFO) - { - g_old_sigact[signum].sa_sigaction(signum, siginfo, priv); - } - else - { - g_old_sigact[signum].sa_handler(signum); - } - - pthread_sigmask(SIG_SETMASK, &cur_set, NULL); - - //If the g_old_sigact set SA_RESETHAND, it will break the chain which means - //g_old_sigact->next_old_sigact will not be called. Our signal handler does not - //responsable for that. We just follow what os do on SA_RESETHAND. - if(g_old_sigact[signum].sa_flags & SA_RESETHAND) - g_old_sigact[signum].sa_handler = SIG_DFL; + } else { + SE_TRACE(SE_TRACE_DEBUG, "Unexpected error occured\n"); + abort(); } } void reg_sig_handler() { - if(vdso_sgx_enter_enclave != NULL) - { - SE_TRACE(SE_TRACE_DEBUG, "vdso_sgx_enter_enclave exists, we won't use signal handler here\n"); - return; - } int ret = 0; struct sigaction sig_act; SE_TRACE(SE_TRACE_DEBUG, "signal handler is registered\n"); @@ -226,16 +205,13 @@ void reg_sig_handler() sigdelset(&sig_act.sa_mask, SIGBUS); sigdelset(&sig_act.sa_mask, SIGTRAP); } + // The signal for interrupt should only interrupt the normal execution of + // the enclave, not interrupt the enclave's handling of exceptions or + // interrupts + sigaddset(&sig_act.sa_mask, SIGRT_INTERRUPT); - ret = sigaction(SIGSEGV, &sig_act, &g_old_sigact[SIGSEGV]); - if (0 != ret) abort(); - ret = sigaction(SIGFPE, &sig_act, &g_old_sigact[SIGFPE]); - if (0 != ret) abort(); - ret = sigaction(SIGILL, &sig_act, &g_old_sigact[SIGILL]); - if (0 != ret) abort(); - ret = sigaction(SIGBUS, &sig_act, &g_old_sigact[SIGBUS]); - if (0 != ret) abort(); - ret = sigaction(SIGTRAP, &sig_act, &g_old_sigact[SIGTRAP]); + sig_act.sa_flags = SA_SIGINFO ; // Remove SA_RESTART and SA_NODEFER + ret = sigaction(SIGRT_INTERRUPT, &sig_act, &g_old_sigact[SIGRT_INTERRUPT]); if (0 != ret) abort(); } @@ -246,7 +222,7 @@ extern "C" int enter_enclave(const tcs_t *tcs, const long fn, const void *ocall_ extern "C" int stack_sticker(unsigned int proc, sgx_ocall_table_t *ocall_table, void *ms, CTrustThread *trust_thread, tcs_t *tcs); -void* get_vdso_sym(const char* vdso_func_name) +void* get_vdso_sym(const char* vdso_func_name, size_t *size) { void *ret = NULL; @@ -282,6 +258,9 @@ void* get_vdso_sym(const char* vdso_func_name) auto vdname = dynstr + sym.st_name; if (strcmp(vdname, vdso_func_name) == 0) { ret = (vdso_address + sym.st_value); + if (size != NULL) { + *size = sym.st_size; + } break; } } @@ -292,7 +271,6 @@ void* get_vdso_sym(const char* vdso_func_name) return ret; } - static int sgx_urts_vdso_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9, struct sgx_enclave_run *run) { @@ -304,14 +282,14 @@ static int sgx_urts_vdso_handler(long rdi, long rsi, long rdx, long ursp, long r { //need to handle exception here __u64 *user_data = (__u64*)run->user_data; - void *ocall_table = reinterpret_cast(user_data[0]); CTrustThread* trust_thread = reinterpret_cast(user_data[1]); - if(ocall_table == NULL || trust_thread == NULL) + if (trust_thread == NULL) { run->user_data = SGX_ERROR_UNEXPECTED; return 0; } + void *ocall_table = reinterpret_cast(user_data[0]); unsigned int ret = do_ecall(ECMD_EXCEPT, ocall_table, NULL, trust_thread); if(SGX_SUCCESS == ret) { @@ -337,14 +315,14 @@ static int sgx_urts_vdso_handler(long rdi, long rsi, long rdx, long ursp, long r else { __u64 *user_data = (__u64*)run->user_data; - sgx_ocall_table_t *ocall_table = reinterpret_cast(user_data[0]); CTrustThread* trust_thread = reinterpret_cast(user_data[1]); - if(ocall_table == NULL || trust_thread == NULL) + if (trust_thread == NULL) { run->user_data = SGX_ERROR_UNEXPECTED; return 0; } + sgx_ocall_table_t *ocall_table = reinterpret_cast(user_data[0]); auto status = stack_sticker((unsigned int )rdi, ocall_table, (void *)rsi, trust_thread, trust_thread->get_tcs()); if(status == (int)SE_ERROR_READ_LOCK_FAIL) @@ -379,7 +357,13 @@ static void __attribute__((constructor)) vdso_detector(void) #else if(vdso_sgx_enter_enclave == NULL) { - vdso_sgx_enter_enclave = (vdso_sgx_enter_enclave_t)get_vdso_sym("__vdso_sgx_enter_enclave"); + size_t size = 0; + void* start_addr = get_vdso_sym("__vdso_sgx_enter_enclave", &size); + g_sgx_enter_enclave_symbol_start = (size_t)start_addr; + g_sgx_enter_enclave_symbol_end = g_sgx_enter_enclave_symbol_start + size; + SE_TRACE(SE_TRACE_DEBUG, "get_vdso_range = [%x, %x]\n", g_sgx_enter_enclave_symbol_start, g_sgx_enter_enclave_symbol_end); + + vdso_sgx_enter_enclave = (vdso_sgx_enter_enclave_t)g_sgx_enter_enclave_symbol_start; } #endif } diff --git a/psw/urts/linux/urts.lds b/psw/urts/linux/urts.lds index 44897f21e..fcee9c930 100644 --- a/psw/urts/linux/urts.lds +++ b/psw/urts/linux/urts.lds @@ -6,6 +6,7 @@ sgx_ecall; sgx_ecall_switchless; sgx_thread_wait_untrusted_event_ocall; + sgx_thread_wait_untrusted_event_timeout_ocall; sgx_thread_set_untrusted_event_ocall; sgx_thread_setwait_untrusted_events_ocall; sgx_thread_set_multiple_untrusted_events_ocall; diff --git a/psw/urts/linux/urts_emm.cpp b/psw/urts/linux/urts_emm.cpp new file mode 100644 index 000000000..94f124abb --- /dev/null +++ b/psw/urts/linux/urts_emm.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "urts_emm.h" +#include "sgx_enclave_common.h" + +#ifdef SE_SIM +#include +#define PROT_MASK (PROT_READ | PROT_WRITE | PROT_EXEC) +#endif + +typedef struct ms_alloc_ocall_t { + int32_t retval; + size_t addr; + size_t size; + uint32_t page_properties; + uint32_t alloc_flags; +} ms_emm_alloc_ocall_t; + +extern "C" sgx_status_t SGX_CDECL ocall_emm_alloc(void* pms) +{ + + ms_emm_alloc_ocall_t* ms = SGX_CAST(ms_emm_alloc_ocall_t*, pms); +#ifdef SE_SIM + ms->retval = mprotect((void*)ms->addr, ms->size, ms->page_properties|PROT_MASK); +#else + ms->retval = enclave_alloc((void *)ms->addr, ms->size,ms->page_properties, ms->alloc_flags, NULL); +#endif + return SGX_SUCCESS; +} + +typedef struct ms_modify_ocall_t { + int32_t retval; + size_t addr; + size_t size; + uint32_t flags_from; + uint32_t flags_to; +} ms_emm_modify_ocall_t; + + +extern "C" sgx_status_t SGX_CDECL ocall_emm_modify(void* pms) +{ + ms_emm_modify_ocall_t* ms = SGX_CAST(ms_emm_modify_ocall_t*, pms); + +#ifdef SE_SIM + ms->retval = mprotect((void*)ms->addr, ms->size, ms->flags_to|PROT_MASK); +#else + ms->retval = enclave_modify((void *)ms->addr, ms->size, ms->flags_from, ms->flags_to, NULL); +#endif + return SGX_SUCCESS; +} diff --git a/sdk/trts/trts_trim.h b/psw/urts/linux/urts_emm.h similarity index 87% rename from sdk/trts/trts_trim.h rename to psw/urts/linux/urts_emm.h index 8adc959f0..747094456 100644 --- a/sdk/trts/trts_trim.h +++ b/psw/urts/linux/urts_emm.h @@ -29,17 +29,14 @@ * */ - -#ifndef TRIM_RANGE_T_H__ -#define TRIM_RANGE_T_H__ +#ifndef _URTS_EMM_H_ +#define _URTS_EMM_H_ #include #include #include -#include "sgx_edger8r.h" // for sgx_ocall etc. - +#include "sgx_urts.h" -#include // for size_t #define SGX_CAST(type, item) ((type)(item)) @@ -47,11 +44,15 @@ extern "C" { #endif -sgx_status_t SGXAPI trim_range_ocall(size_t fromaddr, size_t toaddr); -sgx_status_t SGXAPI trim_range_commit_ocall(size_t addr); + + +sgx_status_t SGX_CDECL ocall_emm_alloc(void* pms); +sgx_status_t SGX_CDECL ocall_emm_modify(void *pms); + #ifdef __cplusplus } #endif /* __cplusplus */ #endif + diff --git a/psw/urts/linux/urts_internal.lds b/psw/urts/linux/urts_internal.lds index b2a0f716b..f91338a8b 100644 --- a/psw/urts/linux/urts_internal.lds +++ b/psw/urts/linux/urts_internal.lds @@ -6,6 +6,7 @@ sgx_ecall; sgx_ecall_switchless; sgx_thread_wait_untrusted_event_ocall; + sgx_thread_wait_untrusted_event_timeout_ocall; sgx_thread_set_untrusted_event_ocall; sgx_thread_setwait_untrusted_events_ocall; sgx_thread_set_multiple_untrusted_events_ocall; diff --git a/psw/urts/loader.cpp b/psw/urts/loader.cpp index 546dd78e2..b80c7fa60 100644 --- a/psw/urts/loader.cpp +++ b/psw/urts/loader.cpp @@ -952,6 +952,7 @@ int CLoader::set_memory_protection() return SGX_ERROR_UNEXPECTED; } +#if 0 if ((META_DATA_MAKE_VERSION(MAJOR_VERSION,MINOR_VERSION) <= m_metadata->version) && get_enclave_creator()->is_EDMM_supported(get_enclave_id())) { @@ -980,6 +981,7 @@ int CLoader::set_memory_protection() } } } +#endif //set memory protection for context ret = set_context_protection(GET_PTR(layout_t, m_metadata, m_metadata->dirs[DIR_LAYOUT].offset), @@ -989,7 +991,6 @@ int CLoader::set_memory_protection() { return ret; } - return SGX_SUCCESS; } @@ -1028,13 +1029,25 @@ int CLoader::set_context_protection(layout_t *layout_start, layout_t *layout_end } #endif } - - ret = mprotect(GET_PTR(void, m_start_addr, layout->entry.rva + delta), +#ifdef SE_SIM + ret = mprotect(GET_PTR(void, m_start_addr, layout->entry.rva + delta), (size_t)layout->entry.page_count << SE_PAGE_SHIFT, prot); - if(ret != 0) +#else + if((layout->entry.attributes&PAGE_ATTR_EADD)) + ret = mprotect(GET_PTR(void, m_start_addr, layout->entry.rva + delta), + (size_t)layout->entry.page_count << SE_PAGE_SHIFT, + prot); + else//dynamic allocated regions + if(prot!=PROT_NONE) + ret = get_enclave_creator()->alloc((uint64_t) GET_PTR(void, m_start_addr, layout->entry.rva + delta), + (size_t)layout->entry.page_count << SE_PAGE_SHIFT, + prot); + else ret = 0; +#endif + if(ret != 0) { - SE_TRACE(SE_TRACE_WARNING, "mprotect(rva=%" PRIu64 ", len=%" PRIu64 ", flags=%d) failed\n", + SE_TRACE(SE_TRACE_WARNING, "mprotect/alloc(rva=%" PRIu64 ", len=%" PRIu64 ", flags=%d) failed\n", (uint64_t)m_start_addr + layout->entry.rva + delta, (uint64_t)layout->entry.page_count << SE_PAGE_SHIFT, prot); diff --git a/psw/urts/tcs.cpp b/psw/urts/tcs.cpp index fb4827622..46079ee19 100644 --- a/psw/urts/tcs.cpp +++ b/psw/urts/tcs.cpp @@ -433,7 +433,7 @@ CTrustThread * CTrustThreadPool::acquire_thread(int ecall_cmd) } if(is_special_ecall != true && - need_to_new_thread() == true) + need_to_new_thread() == true && NULL != m_utility_thread) { m_utility_thread->get_enclave()->fill_tcs_mini_pool_fn(); } diff --git a/psw/urts/urts_com.h b/psw/urts/urts_com.h index 40a1e0e4b..67ad10603 100644 --- a/psw/urts/urts_com.h +++ b/psw/urts/urts_com.h @@ -155,6 +155,11 @@ static bool check_metadata_version(uint64_t urts_version, uint64_t metadata_vers return false; } + if (MAJOR_VERSION_OF_METADATA(metadata_version)%SGX_MAJOR_VERSION_GAP == 2) + { + return false; + } + return true; } @@ -284,12 +289,7 @@ static int __create_enclave(BinParser &parser, if (MAJOR_VERSION_OF_METADATA(metadata->version) % SGX_MAJOR_VERSION_GAP == MAJOR_VERSION_OF_METADATA(urts_version)% SGX_MAJOR_VERSION_GAP && MINOR_VERSION_OF_METADATA(metadata->version) >= MINOR_VERSION_OF_METADATA(urts_version)) { - enclave_version = SDK_VERSION_2_3; - } - else if (MAJOR_VERSION_OF_METADATA(metadata->version) % SGX_MAJOR_VERSION_GAP == MAJOR_VERSION_OF_METADATA(urts_version)% SGX_MAJOR_VERSION_GAP && - MINOR_VERSION_OF_METADATA(metadata->version) < MINOR_VERSION_OF_METADATA(urts_version)) - { - enclave_version = SDK_VERSION_2_0; + enclave_version = SDK_VERSION_3_0; } // initialize the enclave object @@ -408,7 +408,8 @@ static int __create_enclave(BinParser &parser, if (get_enclave_creator()->is_EDMM_supported(loader.get_enclave_id())) { - layout_t *layout_start = GET_PTR(layout_t, metadata, metadata->dirs[DIR_LAYOUT].offset); + //!FIXME use version of enclave to determine action here + /*layout_t *layout_start = GET_PTR(layout_t, metadata, metadata->dirs[DIR_LAYOUT].offset); layout_t *layout_end = GET_PTR(layout_t, metadata, metadata->dirs[DIR_LAYOUT].offset + metadata->dirs[DIR_LAYOUT].size); if (SGX_SUCCESS != (ret = loader.post_init_action(layout_start, layout_end, 0))) { @@ -417,7 +418,7 @@ static int __create_enclave(BinParser &parser, generate_enclave_debug_event(URTS_EXCEPTION_PREREMOVEENCLAVE, debug_info); CEnclavePool::instance()->remove_enclave(loader.get_enclave_id(), status); goto fail; - } + }*/ } //call trts to do some initialization @@ -431,7 +432,8 @@ static int __create_enclave(BinParser &parser, if (get_enclave_creator()->is_EDMM_supported(loader.get_enclave_id())) { - + //!FIXME use version of enclave to determine action here + /* layout_t *layout_start = GET_PTR(layout_t, metadata, metadata->dirs[DIR_LAYOUT].offset); layout_t *layout_end = GET_PTR(layout_t, metadata, metadata->dirs[DIR_LAYOUT].offset + metadata->dirs[DIR_LAYOUT].size); if (SGX_SUCCESS != (ret = loader.post_init_action_commit(layout_start, layout_end, 0))) @@ -441,7 +443,7 @@ static int __create_enclave(BinParser &parser, generate_enclave_debug_event(URTS_EXCEPTION_PREREMOVEENCLAVE, debug_info); CEnclavePool::instance()->remove_enclave(loader.get_enclave_id(), status); goto fail; - } + }*/ } if(SGX_SUCCESS != (ret = loader.set_memory_protection())) diff --git a/sdk/Makefile b/sdk/Makefile index 4c95dd3d7..fd3e90667 100644 --- a/sdk/Makefile +++ b/sdk/Makefile @@ -48,6 +48,7 @@ opt_check_failed: .PHONY: all all: $(CHECK_OPT) $(MAKE) components + $(MAKE) -C ../psw/urts/linux ifneq ($(MITIGATION-CVE-2020-0551),) $(RM) -r $(BUILD_DIR)$(MITIGATION-CVE-2020-0551) mv $(BUILD_DIR) $(BUILD_DIR)$(MITIGATION-CVE-2020-0551) diff --git a/sdk/Makefile.source b/sdk/Makefile.source index 6ebb8fb33..6aeac2972 100644 --- a/sdk/Makefile.source +++ b/sdk/Makefile.source @@ -66,7 +66,7 @@ LIBTCXX := $(BUILD_DIR)/libsgx_tcxx.a LIBTSE := $(BUILD_DIR)/libsgx_tservice.a .PHONY: components -components: tstdc tcxx tservice trts tcrypto tkey_exchange ukey_exchange tprotected_fs uprotected_fs ptrace sample_crypto libcapable simulation signtool edger8r tcmalloc sgx_pcl sgx_encrypt sgx_tswitchless sgx_uswitchless pthread openmp protobuf ttls utls +components: tstdc tcxx tservice trts tcrypto tkey_exchange ukey_exchange tprotected_fs uprotected_fs ptrace sample_crypto libcapable simulation signtool edger8r tcmalloc sgx_pcl sgx_encrypt sgx_tswitchless sgx_uswitchless pthread openmp protobuf ttls utls sgx_mm # --------------------------------------------------- # tstdc @@ -176,6 +176,10 @@ ec_dh_lib: # --------------------------------------------------- # Other trusted libraries # --------------------------------------------------- +.PHONY: sgx_mm +sgx_mm: + $(MAKE) -C $(LINUX_EXTERNAL_DIR)/sgx-emm/ + .PHONY: trts trts: $(MAKE) -C trts/ @@ -291,6 +295,7 @@ clean: $(MAKE) -C tlibcxx/ clean $(MAKE) -C tseal/linux/ clean $(MAKE) -C selib/linux/ clean + $(MAKE) -C $(LINUX_EXTERNAL_DIR)/sgx-emm/ clean $(MAKE) -C trts/ clean $(MAKE) -C tsetjmp/ clean $(MAKE) -C tsafecrt/ clean diff --git a/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_plugin.py b/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_plugin.py index be120d16c..aeca1f950 100755 --- a/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_plugin.py +++ b/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_plugin.py @@ -56,6 +56,7 @@ ENCLAVE_INFO_SIZE = 8 * 7 + 2 * 4 INFO_FMT = 'QQQIIQQQQ' ENCLAVES_ADDR = {} +OCCLUM_GDB = 0 # The following definitions should strictly align with the struct of # tcs_t @@ -173,6 +174,8 @@ def init_enclave_debug(self): gdb.execute(gdb_cmd, False, True) global ENCLAVES_ADDR ENCLAVES_ADDR[self.start_addr] = gdb_cmd.split()[2] + if OCCLUM_GDB == 1: + GetOcclumElfBreakpoint() return 0 def get_peak_heap_used(self): @@ -523,7 +526,7 @@ def is_bp_in_urts(): try: ip = gdb.parse_and_eval("$pc") solib_name = gdb.solib_name(int(str(ip).split()[0], 16)) - if(solib_name.find("libsgx_urts.so") == -1 and solib_name.find("libsgx_urts_sim.so") == -1 and solib_name.find("libsgx_aesm_service.so") == -1): + if(solib_name.find("libocclum-pal.so") == -1 and solib_name.find("libsgx_urts.so") == -1 and solib_name.find("libsgx_urts_sim.so") == -1 and solib_name.find("libsgx_aesm_service.so") == -1): return False else: return True @@ -686,6 +689,64 @@ def stop(self): gdb.execute(gdb_cmd, False, True) return False +class GetLdLoadLibraryReturnBreakpoint(gdb.FinishBreakpoint): + def __init__(self): + gdb.FinishBreakpoint.__init__ (self, gdb.newest_frame(), internal=1) + self.silent = True + + def stop(self): + dso_addr_ = gdb.parse_and_eval("$rax") + dso_addr = ctypes.c_uint64(dso_addr_).value + string = read_from_memory(dso_addr, 16) + elf_start_addr, elf_name_addr = struct.unpack('QQ', string) + # Assume the file name length is less than 512 + string = read_from_memory(elf_name_addr, 512) + elf_name = "image" + for i in range(512): + if string[i] != struct.pack("B", 0): + elf_name += string[i].decode('ascii') + else: + break + gdb_cmd = load_symbol_cmd.GetLoadSymbolCommand(elf_name, str(elf_start_addr)) + if gdb_cmd == -1: + return 0 + gdb.execute(gdb_cmd, False, True) + return False + +class GetLdLoadLibraryBreakpoint(gdb.Breakpoint): + def __init__(self): + # for Musl + gdb.Breakpoint.__init__ (self, spec="load_library", internal=1) + # for Glibc + gdb.Breakpoint.__init__ (self, spec="_dl_map_object", internal=1) + + def stop(self): + GetLdLoadLibraryReturnBreakpoint() + return False + +class GetOcclumElfBreakpoint(gdb.Breakpoint): + def __init__(self): + gdb.Breakpoint.__init__ (self, spec="occlum_gdb_hook_load_elf", internal=1) + + def stop(self): + addr_ = gdb.parse_and_eval("$rdi") + addr = ctypes.c_uint64(addr_).value + file_name_ = gdb.parse_and_eval("$rsi") + file_name = ctypes.c_uint64(file_name_).value + file_name_len_ = gdb.parse_and_eval("$rdx") + file_name_len = ctypes.c_uint64(file_name_len_).value + file_string = read_from_memory(file_name, file_name_len) + file_path = "image" + \ + struct.unpack('{length}s'.format(length=file_name_len), \ + file_string[0:file_name_len])[0].decode("ascii") + gdb_cmd = load_symbol_cmd.GetLoadSymbolCommand(file_path, str(addr)) + if gdb_cmd == -1: + return 0 + print (gdb_cmd) + gdb.execute(gdb_cmd, False, True) + GetLdLoadLibraryBreakpoint() + return False + def sgx_debugger_init(): print ("detect urts is loaded, initializing") global SIZE @@ -697,6 +758,9 @@ def sgx_debugger_init(): if bp.location == "sgx_debug_load_state_add_element": inited = 1 break + if os.getenv("OCCLUM_GDB") == "1": + global OCCLUM_GDB + OCCLUM_GDB = 1 if inited == 0: detach_enclaves() gdb.execute("source gdb_sgx_cmd", False, True) @@ -716,7 +780,7 @@ def exit_handler(event): def newobj_handler(event): solib_name = os.path.basename(event.new_objfile.filename) - if solib_name == 'libsgx_urts.so' or solib_name == 'libsgx_urts_sim.so' or solib_name == 'libsgx_aesm_service.so': + if solib_name.find("libocclum-pal.so") != -1 or solib_name == 'libsgx_urts.so' or solib_name == 'libsgx_urts_sim.so' or solib_name == 'libsgx_aesm_service.so': sgx_debugger_init() return diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_crypto.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_crypto.cpp index ffef99314..02b155f76 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_crypto.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_crypto.cpp @@ -56,6 +56,11 @@ typedef struct { bool protected_fs_file::generate_secure_blob(sgx_aes_gcm_128bit_key_t* key, const char* label, uint64_t physical_node_number, sgx_aes_gcm_128bit_tag_t* output) { + if (integrity_only) + { + return true; + } + kdf_input_t buf = {0, "", 0, "", 0}; uint32_t len = (uint32_t)strnlen(label, MAX_LABEL_LEN + 1); @@ -67,19 +72,19 @@ bool protected_fs_file::generate_secure_blob(sgx_aes_gcm_128bit_key_t* key, cons // index // SP800-108: - // i - A counter, a binary string of length r that is an input to each iteration of a PRF in counter mode [...]. + // i ? A counter, a binary string of length r that is an input to each iteration of a PRF in counter mode [...]. buf.index = 0x01; // label // SP800-108: - // Label - A string that identifies the purpose for the derived keying material, which is encoded as a binary string. + // Label ? A string that identifies the purpose for the derived keying material, which is encoded as a binary string. // The encoding method for the Label is defined in a larger context, for example, in the protocol that uses a KDF. strncpy(buf.label, label, len); // context and nonce - // SP800-108: - // Context - A binary string containing the information related to the derived keying material. - // It may include identities of parties who are deriving and / or using the derived keying material and, + // SP800-108: + // Context ? A binary string containing the information related to the derived keying material. + // It may include identities of parties who are deriving and / or using the derived keying material and, // optionally, a nonce known by the parties who derive the keys. buf.node_number = physical_node_number; @@ -108,24 +113,29 @@ bool protected_fs_file::generate_secure_blob(sgx_aes_gcm_128bit_key_t* key, cons bool protected_fs_file::generate_secure_blob_from_user_kdk(bool restore) { + if (integrity_only) + { + return true; + } + kdf_input_t buf = {0, "", 0, "", 0}; sgx_status_t status = SGX_SUCCESS; // index // SP800-108: - // i - A counter, a binary string of length r that is an input to each iteration of a PRF in counter mode [...]. + // i ? A counter, a binary string of length r that is an input to each iteration of a PRF in counter mode [...]. buf.index = 0x01; // label // SP800-108: - // Label - A string that identifies the purpose for the derived keying material, which is encoded as a binary string. + // Label ? A string that identifies the purpose for the derived keying material, which is encoded as a binary string. // The encoding method for the Label is defined in a larger context, for example, in the protocol that uses a KDF. strncpy(buf.label, METADATA_KEY_NAME, strlen(METADATA_KEY_NAME)); // context and nonce - // SP800-108: - // Context - A binary string containing the information related to the derived keying material. - // It may include identities of parties who are deriving and / or using the derived keying material and, + // SP800-108: + // Context ? A binary string containing the information related to the derived keying material. + // It may include identities of parties who are deriving and / or using the derived keying material and, // optionally, a nonce known by the parties who derive the keys. buf.node_number = 0; @@ -143,7 +153,7 @@ bool protected_fs_file::generate_secure_blob_from_user_kdk(bool restore) { memcpy(&buf.nonce32, &file_meta_data.plain_part.meta_data_key_id, sizeof(sgx_key_id_t)); } - + // length of output (128 bits) buf.output_len = 0x80; @@ -168,8 +178,13 @@ bool protected_fs_file::generate_secure_blob_from_user_kdk(bool restore) bool protected_fs_file::init_session_master_key() { + if (integrity_only) + { + return true; + } + sgx_aes_gcm_128bit_key_t empty_key = {0}; - + if (generate_secure_blob(&empty_key, MASTER_KEY_NAME, 0, (sgx_aes_gcm_128bit_tag_t*)&session_master_key) == false) return false; @@ -181,6 +196,11 @@ bool protected_fs_file::init_session_master_key() bool protected_fs_file::derive_random_node_key(uint64_t physical_node_number) { + if (integrity_only) + { + return true; + } + if (master_key_count++ > MAX_MASTER_KEY_USAGES) { if (init_session_master_key() == false) @@ -196,15 +216,20 @@ bool protected_fs_file::derive_random_node_key(uint64_t physical_node_number) bool protected_fs_file::generate_random_meta_data_key() { + if (integrity_only) + { + return true; + } + if (use_user_kdk_key == 1) { return generate_secure_blob_from_user_kdk(false); } - // derive a random key from the enclave sealing key + // derive a random key from the enclave sealing key sgx_key_request_t key_request; - memset(&key_request, 0, sizeof(sgx_key_request_t)); - + memset(&key_request, 0, sizeof(sgx_key_request_t)); + key_request.key_name = SGX_KEYSELECT_SEAL; key_request.key_policy = SGX_KEYPOLICY_MRSIGNER; @@ -215,14 +240,14 @@ bool protected_fs_file::generate_random_meta_data_key() key_request.attribute_mask.xfrm = 0x0; key_request.misc_mask = TSEAL_DEFAULT_MISCMASK; - + sgx_status_t status = sgx_read_rand((unsigned char*)&key_request.key_id, sizeof(sgx_key_id_t)); if (status != SGX_SUCCESS) { last_error = status; return false; } - + status = sgx_get_key(&key_request, &cur_key); if (status != SGX_SUCCESS) { @@ -241,8 +266,13 @@ bool protected_fs_file::generate_random_meta_data_key() bool protected_fs_file::restore_current_meta_data_key(const sgx_aes_gcm_128bit_key_t* import_key) { + if (integrity_only) + { + return true; + } + if (import_key != NULL) - { + { memcpy(&cur_key, import_key, sizeof(sgx_aes_gcm_128bit_key_t)); return true; } @@ -283,5 +313,3 @@ bool protected_fs_file::restore_current_meta_data_key(const sgx_aes_gcm_128bit_k return true; } - - diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_flush.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_flush.cpp index cbfbbc8d7..969e5e47b 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_flush.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_flush.cpp @@ -37,7 +37,7 @@ #include -bool protected_fs_file::flush(/*bool mc*/) +bool protected_fs_file::flush() { bool result = false; @@ -55,8 +55,8 @@ bool protected_fs_file::flush(/*bool mc*/) sgx_thread_mutex_unlock(&mutex); return false; } - - result = internal_flush(/*mc,*/ true); + + result = internal_flush(true); if (result == false) { assert(file_status != SGX_FILE_STATUS_OK); @@ -70,18 +70,11 @@ bool protected_fs_file::flush(/*bool mc*/) } -bool protected_fs_file::internal_flush(/*bool mc,*/ bool flush_to_disk) +bool protected_fs_file::internal_flush(bool flush_to_disk) { if (need_writing == false) // no changes at all return true; -/* - if (mc == true && encrypted_part_plain.mc_value > (UINT_MAX-2)) - { - last_error = SGX_ERROR_FILE_MONOTONIC_COUNTER_AT_MAX; - return false; - } -*/ if (encrypted_part_plain.size > MD_USER_DATA_SIZE && root_mht.need_writing == true) // otherwise it's just one write - the meta-data node { if (_RECOVERY_HOOK_(0) || write_recovery_file() != true) @@ -104,44 +97,17 @@ bool protected_fs_file::internal_flush(/*bool mc,*/ bool flush_to_disk) } } -/* - sgx_status_t status; - - if (mc == true) - { - // increase monotonic counter local value - only if everything is ok, we will increase the real counter - if (encrypted_part_plain.mc_value == 0) - { - // no monotonic counter so far, need to create a new one - status = sgx_create_monotonic_counter(&encrypted_part_plain.mc_uuid, &encrypted_part_plain.mc_value); - if (status != SGX_SUCCESS) - { - clear_update_flag(); - file_status = SGX_FILE_STATUS_FLUSH_ERROR; - last_error = status; - return false; - } - } - encrypted_part_plain.mc_value++; - } -*/ if (_RECOVERY_HOOK_(3) || update_meta_data_node() != true) { clear_update_flag(); - /* - if (mc == true) - encrypted_part_plain.mc_value--; // don't have to do this as the file cannot be fixed, but doing it anyway to prevent future errors - */ + file_status = SGX_FILE_STATUS_CRYPTO_ERROR; // this is something that shouldn't happen, can't fix this... return false; } if (_RECOVERY_HOOK_(4) || write_all_changes_to_disk(flush_to_disk) != true) { - //if (mc == false) - file_status = SGX_FILE_STATUS_WRITE_TO_DISK_FAILED; // special case, need only to repeat write_all_changes_to_disk in order to repair it - //else - //file_status = SGX_FILE_STATUS_WRITE_TO_DISK_FAILED_NEED_MC; // special case, need to repeat write_all_changes_to_disk AND increase the monotonic counter in order to repair it + file_status = SGX_FILE_STATUS_WRITE_TO_DISK_FAILED; // special case, need only to repeat write_all_changes_to_disk in order to repair it return false; } @@ -156,20 +122,7 @@ bool protected_fs_file::internal_flush(/*bool mc,*/ bool flush_to_disk) erase_recovery_file(); } */ -/* - if (mc == true) - { - uint32_t mc_value; - status = sgx_increment_monotonic_counter(&encrypted_part_plain.mc_uuid, &mc_value); - if (status != SGX_SUCCESS) - { - file_status = SGX_FILE_STATUS_MC_NOT_INCREMENTED; // special case - need only to increase the MC in order to repair it - last_error = status; - return false; - } - assert(mc_value == encrypted_part_plain.mc_value); - } -*/ + return true; } @@ -259,7 +212,7 @@ bool protected_fs_file::set_update_flag(bool flush_to_disk) file_meta_data.plain_part.update_flag = 0; // turn it off in memory. at the end of the flush, when we'll write the meta-data to disk, this flag will also be cleared there. if (status != SGX_SUCCESS || result32 != 0) { - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : EIO; return false; } @@ -327,8 +280,16 @@ bool protected_fs_file::update_all_data_and_mht_nodes() gcm_crypto_data_t* gcm_crypto_data = &data_node->parent->plain.data_nodes_crypto[data_node->data_node_number % ATTACHED_DATA_NODES_COUNT]; // encrypt the data, this also saves the gmac of the operation in the mht crypto node - status = sgx_rijndael128GCM_encrypt(&cur_key, data_node->plain.data, NODE_SIZE, data_node->encrypted.cipher, - empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &gcm_crypto_data->gmac); + if(!integrity_only) { + status = sgx_rijndael128GCM_encrypt(&cur_key, data_node->plain.data, NODE_SIZE, data_node->encrypted.cipher, + empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &gcm_crypto_data->gmac); + } + // calculate the MAC only + else { + status = sgx_rijndael128GCM_encrypt(&cur_key, NULL, 0, NULL, + empty_iv, SGX_AESGCM_IV_SIZE, data_node->plain.data, NODE_SIZE, &gcm_crypto_data->gmac); + memcpy(data_node->encrypted.cipher, data_node->plain.data, NODE_SIZE); + } if (status != SGX_SUCCESS) { last_error = status; @@ -380,9 +341,15 @@ bool protected_fs_file::update_all_data_and_mht_nodes() mht_list.clear(); return false; } - - status = sgx_rijndael128GCM_encrypt(&cur_key, (const uint8_t*)&file_mht_node->plain, NODE_SIZE, file_mht_node->encrypted.cipher, - empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &gcm_crypto_data->gmac); + if(!integrity_only) { + status = sgx_rijndael128GCM_encrypt(&cur_key, (const uint8_t*)&file_mht_node->plain, NODE_SIZE, file_mht_node->encrypted.cipher, + empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &gcm_crypto_data->gmac); + } + else { + status = sgx_rijndael128GCM_encrypt(&cur_key, NULL ,0, NULL, + empty_iv, SGX_AESGCM_IV_SIZE, (const uint8_t*)&file_mht_node->plain, NODE_SIZE, &gcm_crypto_data->gmac); + memcpy(file_mht_node->encrypted.cipher, (const uint8_t*)&file_mht_node->plain, NODE_SIZE); + } if (status != SGX_SUCCESS) { mht_list.clear(); @@ -399,8 +366,15 @@ bool protected_fs_file::update_all_data_and_mht_nodes() if (derive_random_node_key(root_mht.physical_node_number) == false) return false; - status = sgx_rijndael128GCM_encrypt(&cur_key, (const uint8_t*)&root_mht.plain, NODE_SIZE, root_mht.encrypted.cipher, - empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &encrypted_part_plain.mht_gmac); + if(!integrity_only) { + status = sgx_rijndael128GCM_encrypt(&cur_key, (const uint8_t*)&root_mht.plain, NODE_SIZE, root_mht.encrypted.cipher, + empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &encrypted_part_plain.mht_gmac); + } + else { + status = sgx_rijndael128GCM_encrypt(&cur_key, NULL, 0, NULL, + empty_iv, SGX_AESGCM_IV_SIZE, (const uint8_t*)&root_mht.plain, NODE_SIZE, &encrypted_part_plain.mht_gmac); + memcpy(root_mht.encrypted.cipher, (const uint8_t*)&root_mht.plain, NODE_SIZE); + } if (status != SGX_SUCCESS) { last_error = status; @@ -416,20 +390,31 @@ bool protected_fs_file::update_all_data_and_mht_nodes() bool protected_fs_file::update_meta_data_node() { sgx_status_t status; - + // randomize a new key, saves the key _id_ in the meta data plain part if (generate_random_meta_data_key() != true) { // last error already set return false; } - - // encrypt meta data encrypted part, also updates the gmac in the meta data plain part - status = sgx_rijndael128GCM_encrypt(&cur_key, - (const uint8_t*)&encrypted_part_plain, sizeof(meta_data_encrypted_t), (uint8_t*)&file_meta_data.encrypted_part, - empty_iv, SGX_AESGCM_IV_SIZE, - NULL, 0, - &file_meta_data.plain_part.meta_data_gmac); + + if (!integrity_only) { + // encrypt meta data encrypted part, also updates the gmac in the meta data plain part + status = sgx_rijndael128GCM_encrypt(&cur_key, + (const uint8_t*)&encrypted_part_plain, sizeof(meta_data_encrypted_t), (uint8_t*)&file_meta_data.encrypted_part, + empty_iv, SGX_AESGCM_IV_SIZE, + NULL, 0, + &file_meta_data.plain_part.meta_data_gmac); + } + else { + status = sgx_rijndael128GCM_encrypt(&cur_key, + NULL, 0, NULL, + empty_iv, SGX_AESGCM_IV_SIZE, + (const uint8_t*)&encrypted_part_plain, sizeof(meta_data_encrypted_t), + &file_meta_data.plain_part.meta_data_gmac); + memcpy((uint8_t*)&file_meta_data.encrypted_part, (const uint8_t*)&encrypted_part_plain, sizeof(meta_data_encrypted_t)); + } + if (status != SGX_SUCCESS) { last_error = status; @@ -482,7 +467,7 @@ bool protected_fs_file::write_all_changes_to_disk(bool flush_to_disk) status = u_sgxprotectedfs_fwrite_node(&result32, file, node_number, data_to_write, NODE_SIZE); if (status != SGX_SUCCESS || result32 != 0) { - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : EIO; return false; } @@ -504,7 +489,7 @@ bool protected_fs_file::write_all_changes_to_disk(bool flush_to_disk) status = u_sgxprotectedfs_fwrite_node(&result32, file, 1, (uint8_t*)&root_mht.encrypted, NODE_SIZE); if (status != SGX_SUCCESS || result32 != 0) { - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : EIO; return false; } @@ -515,7 +500,7 @@ bool protected_fs_file::write_all_changes_to_disk(bool flush_to_disk) status = u_sgxprotectedfs_fwrite_node(&result32, file, 0, (uint8_t*)&file_meta_data, NODE_SIZE); if (status != SGX_SUCCESS || result32 != 0) { - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : EIO; return false; } @@ -545,5 +530,3 @@ void protected_fs_file::erase_recovery_file() status = u_sgxprotectedfs_remove(&result32, recovery_filename); (void)status; // don't care if it succeeded or failed...just remove the warning } - - diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_init.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_init.cpp index a68e3639d..64c0cffd0 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_init.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_init.cpp @@ -67,15 +67,15 @@ bool protected_fs_file::cleanup_filename(const char* src, char* dest) } -protected_fs_file::protected_fs_file(const char* filename, const char* mode, const sgx_aes_gcm_128bit_key_t* import_key, const sgx_aes_gcm_128bit_key_t* kdk_key) +protected_fs_file::protected_fs_file(const char* filename, const char* mode, const sgx_aes_gcm_128bit_key_t* import_key, const sgx_aes_gcm_128bit_key_t* kdk_key, bool _integrity_only, const uint64_t cache_page) { sgx_status_t status = SGX_SUCCESS; uint8_t result = 0; int32_t result32 = 0; - - init_fields(); - if (filename == NULL || mode == NULL || + init_fields(cache_page); + + if (filename == NULL || mode == NULL || strnlen(filename, 1) == 0 || strnlen(mode, 1) == 0) { last_error = EINVAL; @@ -108,7 +108,7 @@ protected_fs_file::protected_fs_file(const char* filename, const char* mode, con return; } - if (init_session_master_key() == false) + if (init_session_master_key() == false) // last_error already set return; @@ -116,16 +116,16 @@ protected_fs_file::protected_fs_file(const char* filename, const char* mode, con { // for new file, this value will later be saved in the meta data plain part (init_new_file) // for existing file, we will later compare this value with the value from the file (init_existing_file) - use_user_kdk_key = 1; + use_user_kdk_key = 1; memcpy(user_kdk_key, kdk_key, sizeof(sgx_aes_gcm_128bit_key_t)); } - + // get the clean file name (original name might be clean or with relative path or with absolute path...) char clean_filename[FILENAME_MAX_LEN]; if (cleanup_filename(filename, clean_filename) == false) // last_error already set return; - + if (import_key != NULL) {// verify the key is not empty - note from SAFE review sgx_aes_gcm_128bit_key_t empty_aes_key = {0}; @@ -183,6 +183,8 @@ protected_fs_file::protected_fs_file(const char* filename, const char* mode, con return; } + integrity_only = _integrity_only; + // now open the file read_only = (open_mode.read == 1 && open_mode.update == 0); // read only files can be opened simultaneously by many enclaves @@ -206,7 +208,7 @@ protected_fs_file::protected_fs_file(const char* filename, const char* mode, con last_error = SGX_ERROR_FILE_NOT_SGX_FILE; break; } - + strncpy(recovery_filename, filename, FULLNAME_MAX_LEN - 1); // copy full file name recovery_filename[FULLNAME_MAX_LEN - 1] = '\0'; // just to be safe size_t full_name_len = strnlen(recovery_filename, RECOVERY_FILE_MAX_LEN); @@ -222,7 +224,7 @@ protected_fs_file::protected_fs_file(const char* filename, const char* mode, con if (init_existing_file(filename, clean_filename, import_key) == false) break; - + if (open_mode.append == 1 && open_mode.update == 0) offset = encrypted_part_plain.size; } @@ -247,11 +249,12 @@ protected_fs_file::protected_fs_file(const char* filename, const char* mode, con } -void protected_fs_file::init_fields() +void protected_fs_file::init_fields(const uint64_t cache_page) { meta_data_node_number = 0; memset(&file_meta_data, 0, sizeof(meta_data_node_t)); memset(&encrypted_part_plain, 0, sizeof(meta_data_encrypted_t)); + memset(&cur_key, 0, sizeof(sgx_aes_gcm_128bit_key_t)); memset(&empty_iv, 0, sizeof(sgx_iv_t)); @@ -261,25 +264,29 @@ void protected_fs_file::init_fields() root_mht.mht_node_number = 0; root_mht.new_node = true; root_mht.need_writing = false; - + offset = 0; file = NULL; end_of_file = false; + integrity_only = false; need_writing = false; read_only = 0; file_status = SGX_FILE_STATUS_NOT_INITIALIZED; last_error = SGX_SUCCESS; - real_file_size = 0; + real_file_size = 0; open_mode.raw = 0; use_user_kdk_key = 0; master_key_count = 0; + max_cache_page = 0; recovery_filename[0] = '\0'; - - memset(&mutex, 0, sizeof(sgx_thread_mutex_t)); - // set hash size to fit MAX_PAGES_IN_CACHE - cache.rehash(MAX_PAGES_IN_CACHE); + max_cache_page = cache_page; + + // set hash size + cache.rehash(max_cache_page); + + memset(&mutex, 0, sizeof(sgx_thread_mutex_t)); } @@ -343,7 +350,7 @@ bool protected_fs_file::file_recovery(const char* filename) status = u_sgxprotectedfs_fclose(&result32, file); if (status != SGX_SUCCESS || result32 != 0) { - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : EINVAL; return false; } @@ -361,7 +368,7 @@ bool protected_fs_file::file_recovery(const char* filename) status = u_sgxprotectedfs_exclusive_file_open(&file, filename, read_only, &new_file_size, &result32); if (status != SGX_SUCCESS || file == NULL) { - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != 0) ? result32 : EACCES; return false; } @@ -376,7 +383,7 @@ bool protected_fs_file::file_recovery(const char* filename) status = u_sgxprotectedfs_fread_node(&result32, file, 0, (uint8_t*)&file_meta_data, NODE_SIZE); if (status != SGX_SUCCESS || result32 != 0) { - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : EIO; return false; } @@ -394,7 +401,7 @@ bool protected_fs_file::init_existing_file(const char* filename, const char* cle status = u_sgxprotectedfs_fread_node(&result32, file, 0, (uint8_t*)&file_meta_data, NODE_SIZE); if (status != SGX_SUCCESS || result32 != 0) { - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : EIO; return false; } @@ -439,15 +446,31 @@ bool protected_fs_file::init_existing_file(const char* filename, const char* cle return false; } + if (file_meta_data.plain_part.integrity_only != integrity_only) + { + last_error = EINVAL; + return false; + } + if (restore_current_meta_data_key(import_key) == false) return false; - // decrypt the encrypted part of the meta-data - status = sgx_rijndael128GCM_decrypt(&cur_key, - (const uint8_t*)file_meta_data.encrypted_part, sizeof(meta_data_encrypted_blob_t), (uint8_t*)&encrypted_part_plain, - empty_iv, SGX_AESGCM_IV_SIZE, - NULL, 0, - &file_meta_data.plain_part.meta_data_gmac); + if(!integrity_only) { + // decrypt the encrypted part of the meta-data + status = sgx_rijndael128GCM_decrypt(&cur_key, + (const uint8_t*)file_meta_data.encrypted_part, sizeof(meta_data_encrypted_blob_t), (uint8_t*)&encrypted_part_plain, + empty_iv, SGX_AESGCM_IV_SIZE, + NULL, 0, + &file_meta_data.plain_part.meta_data_gmac); + } + else { + status = sgx_rijndael128GCM_decrypt(&cur_key, + NULL, 0, NULL, + empty_iv, SGX_AESGCM_IV_SIZE, + (const uint8_t*)file_meta_data.encrypted_part, sizeof(meta_data_encrypted_blob_t), + &file_meta_data.plain_part.meta_data_gmac); + memcpy((uint8_t*)&encrypted_part_plain, (const uint8_t*)file_meta_data.encrypted_part, sizeof(meta_data_encrypted_blob_t)); + } if (status != SGX_SUCCESS) { last_error = status; @@ -460,66 +483,30 @@ bool protected_fs_file::init_existing_file(const char* filename, const char* cle return false; } -/* - sgx_mc_uuid_t empty_mc_uuid = {0}; - - // check if the file contains an active monotonic counter - if (consttime_memequal(&empty_mc_uuid, &encrypted_part_plain.mc_uuid, sizeof(sgx_mc_uuid_t)) == 0) - { - uint32_t mc_value = 0; - - status = sgx_read_monotonic_counter(&encrypted_part_plain.mc_uuid, &mc_value); - if (status != SGX_SUCCESS) - { - last_error = status; - return false; - } - - if (encrypted_part_plain.mc_value < mc_value) - { - last_error = SGX_ERROR_FILE_MONOTONIC_COUNTER_IS_BIGGER; - return false; - } - - if (encrypted_part_plain.mc_value == mc_value + 1) // can happen if AESM failed - file value stayed one higher - { - sgx_status_t status = sgx_increment_monotonic_counter(&encrypted_part_plain.mc_uuid, &mc_value); - if (status != SGX_SUCCESS) - { - file_status = SGX_FILE_STATUS_MC_NOT_INCREMENTED; - last_error = status; - return false; - } - } - - if (encrypted_part_plain.mc_value != mc_value) - { - file_status = SGX_FILE_STATUS_CORRUPTED; - last_error = SGX_ERROR_UNEXPECTED; - return false; - } - } - else - { - assert(encrypted_part_plain.mc_value == 0); - encrypted_part_plain.mc_value = 0; // do this anyway for release... - } -*/ if (encrypted_part_plain.size > MD_USER_DATA_SIZE) { // read the root node of the mht status = u_sgxprotectedfs_fread_node(&result32, file, 1, root_mht.encrypted.cipher, NODE_SIZE); if (status != SGX_SUCCESS || result32 != 0) { - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : EIO; return false; } - // this also verifies the root mht gmac against the gmac in the meta-data encrypted part - status = sgx_rijndael128GCM_decrypt(&encrypted_part_plain.mht_key, - root_mht.encrypted.cipher, NODE_SIZE, (uint8_t*)&root_mht.plain, - empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &encrypted_part_plain.mht_gmac); + if(!integrity_only){ + // this also verifies the root mht gmac against the gmac in the meta-data encrypted part + status = sgx_rijndael128GCM_decrypt(&encrypted_part_plain.mht_key, + root_mht.encrypted.cipher, NODE_SIZE, (uint8_t*)&root_mht.plain, + empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &encrypted_part_plain.mht_gmac); + } + else { + status = sgx_rijndael128GCM_decrypt(&encrypted_part_plain.mht_key, + NULL, 0, NULL, + empty_iv, SGX_AESGCM_IV_SIZE, root_mht.encrypted.cipher, NODE_SIZE, &encrypted_part_plain.mht_gmac); + memcpy((uint8_t*)&root_mht.plain, root_mht.encrypted.cipher, NODE_SIZE); + } + if (status != SGX_SUCCESS) { last_error = status; @@ -540,9 +527,10 @@ bool protected_fs_file::init_new_file(const char* clean_filename) file_meta_data.plain_part.minor_version = SGX_FILE_MINOR_VERSION; file_meta_data.plain_part.use_user_kdk_key = use_user_kdk_key; + file_meta_data.plain_part.integrity_only = integrity_only; strncpy(encrypted_part_plain.clean_filename, clean_filename, FILENAME_MAX_LEN); - + need_writing = true; return true; @@ -552,7 +540,7 @@ bool protected_fs_file::init_new_file(const char* clean_filename) protected_fs_file::~protected_fs_file() { void* data; - + while ((data = cache.get_last()) != NULL) { if (((file_data_node_t*)data)->type == FILE_DATA_NODE_TYPE) // type is in the same offset in both node types, need to scrub the plaintext @@ -573,7 +561,7 @@ protected_fs_file::~protected_fs_file() // scrub the last encryption key and the session key memset_s(&cur_key, sizeof(sgx_aes_gcm_128bit_key_t), 0, sizeof(sgx_aes_gcm_128bit_key_t)); memset_s(&session_master_key, sizeof(sgx_aes_gcm_128bit_key_t), 0, sizeof(sgx_aes_gcm_128bit_key_t)); - + // scrub first 3KB of user data and the gmac_key memset_s(&encrypted_part_plain, sizeof(meta_data_encrypted_t), 0, sizeof(meta_data_encrypted_t)); @@ -616,7 +604,7 @@ bool protected_fs_file::pre_close(sgx_key_128bit_t* key, bool import) status = u_sgxprotectedfs_fclose(&result32, file); if (status != SGX_SUCCESS || result32 != 0) { - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : SGX_ERROR_FILE_CLOSE_FAILED; retval = false; } @@ -624,7 +612,7 @@ bool protected_fs_file::pre_close(sgx_key_128bit_t* key, bool import) file = NULL; } - if (file_status == SGX_FILE_STATUS_OK && + if (file_status == SGX_FILE_STATUS_OK && last_error == SGX_SUCCESS) // else...maybe something bad happened and the recovery file will be needed erase_recovery_file(); @@ -649,4 +637,3 @@ bool protected_fs_file::pre_close(sgx_key_128bit_t* key, bool import) return retval; } - diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_other.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_other.cpp index ea708687d..a5ccc657d 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_other.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_other.cpp @@ -45,105 +45,9 @@ int32_t protected_fs_file::remove(const char* filename) sgx_status_t status; int32_t result32 = 0; -/* - void* file = NULL; - int64_t real_file_size = 0; - - if (filename == NULL) - return 1; - - meta_data_node_t* file_meta_data = NULL; - meta_data_encrypted_t* encrypted_part_plain = NULL; - - // if we have a problem in any of the stages, we simply jump to the end and try to remove the file... - do { - status = u_sgxprotectedfs_check_if_file_exists(&result, filename); - if (status != SGX_SUCCESS) - break; - - if (result == 0) - { - errno = EINVAL; - return 1; // no such file, or file locked so we can't delete it anyways - } - - try { - file_meta_data = new meta_data_node_t; - encrypted_part_plain = new meta_data_encrypted_t; - } - catch (std::bad_alloc e) { - break; - } - - status = u_sgxprotectedfs_exclusive_file_open(&file, filename, 1, &real_file_size, &result32); - if (status != SGX_SUCCESS || file == NULL) - break; - - if (real_file_size == 0 || real_file_size % NODE_SIZE != 0) - break; // empty file or not an SGX protected FS file - - // might be an SGX protected FS file - status = u_sgxprotectedfs_fread_node(&result32, file, 0, (uint8_t*)file_meta_data, NODE_SIZE); - if (status != SGX_SUCCESS || result32 != 0) - break; - - if (file_meta_data->plain_part.major_version != SGX_FILE_MAJOR_VERSION) - break; - - sgx_aes_gcm_128bit_key_t zero_key_id = {0}; - sgx_aes_gcm_128bit_key_t key = {0}; - if (consttime_memequal(&file_meta_data->plain_part.key_id, &zero_key_id, sizeof(sgx_aes_gcm_128bit_key_t)) == 1) - break; // shared file - no monotonic counter - - sgx_key_request_t key_request = {0}; - key_request.key_name = SGX_KEYSELECT_SEAL; - key_request.key_policy = SGX_KEYPOLICY_MRENCLAVE; - memcpy(&key_request.key_id, &file_meta_data->plain_part.key_id, sizeof(sgx_key_id_t)); - - status = sgx_get_key(&key_request, &key); - if (status != SGX_SUCCESS) - break; - - status = sgx_rijndael128GCM_decrypt(&key, - file_meta_data->encrypted_part, sizeof(meta_data_encrypted_blob_t), - (uint8_t*)encrypted_part_plain, - file_meta_data->plain_part.meta_data_iv, SGX_AESGCM_IV_SIZE, - NULL, 0, - &file_meta_data->plain_part.meta_data_gmac); - if (status != SGX_SUCCESS) - break; - - sgx_mc_uuid_t empty_mc_uuid = {0}; - if (consttime_memequal(&empty_mc_uuid, &encrypted_part_plain->mc_uuid, sizeof(sgx_mc_uuid_t)) == 0) - { - status = sgx_destroy_monotonic_counter(&encrypted_part_plain->mc_uuid); - if (status != SGX_SUCCESS) - break; - - // monotonic counter was deleted, mission accomplished!! - } - } - while (0); - - // cleanup - if (file_meta_data != NULL) - delete file_meta_data; - - if (encrypted_part_plain != NULL) - { - // scrub the encrypted part - memset_s(encrypted_part_plain, sizeof(meta_data_encrypted_t), 0, sizeof(meta_data_encrypted_t)); - delete encrypted_part_plain; - } - - if (file != NULL) - u_sgxprotectedfs_fclose(&result32, file); - -*/ - // do the actual file removal status = u_sgxprotectedfs_remove(&result32, filename); - if (status != SGX_SUCCESS) + if (status != SGX_SUCCESS) { errno = status; return 1; @@ -197,13 +101,6 @@ int protected_fs_file::seek(int64_t new_offset, int origin) return -1; } - //if (open_mode.binary == 0 && origin != SEEK_SET && new_offset != 0) - //{ - // last_error = EINVAL; - // sgx_thread_mutex_unlock(&mutex); - // return -1; - //} - int result = -1; switch (origin) @@ -232,7 +129,7 @@ int protected_fs_file::seek(int64_t new_offset, int origin) } break; - default: + default: break; } @@ -299,33 +196,6 @@ void protected_fs_file::clear_error() } } -/* - if (file_status == SGX_FILE_STATUS_WRITE_TO_DISK_FAILED_NEED_MC) - { - if (write_all_changes_to_disk(true) == true) - { - need_writing = false; - file_status = SGX_FILE_STATUS_MC_NOT_INCREMENTED; // fall through...next 'if' should take care of this one - } - } - - if ((file_status == SGX_FILE_STATUS_MC_NOT_INCREMENTED) && - (encrypted_part_plain.mc_value <= (UINT_MAX-2))) - { - uint32_t mc_value; - sgx_status_t status = sgx_increment_monotonic_counter(&encrypted_part_plain.mc_uuid, &mc_value); - if (status == SGX_SUCCESS) - { - assert(mc_value == encrypted_part_plain.mc_value); - file_status = SGX_FILE_STATUS_OK; - } - else - { - last_error = status; - } - } -*/ - if (file_status == SGX_FILE_STATUS_OK) { last_error = SGX_SUCCESS; @@ -364,13 +234,13 @@ int32_t protected_fs_file::clear_cache() assert(data != NULL); assert(((file_data_node_t*)data)->need_writing == false); // need_writing is in the same offset in both node types - // for production - + // for production - if (data == NULL || ((file_data_node_t*)data)->need_writing == true) { sgx_thread_mutex_unlock(&mutex); return 1; } - + cache.remove_last(); // before deleting the memory, need to scrub the plain secrets @@ -393,3 +263,7 @@ int32_t protected_fs_file::clear_cache() return 0; } +int32_t protected_fs_file::get_root_mac(sgx_aes_gcm_128bit_tag_t* mac) { + memcpy(mac, file_meta_data.plain_part.meta_data_gmac, sizeof(*mac)); + return 0; +} diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_read_write.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_read_write.cpp index 8d0c5f18c..410476c57 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_read_write.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_read_write.cpp @@ -110,7 +110,7 @@ size_t protected_fs_file::write(const void* ptr, size_t size, size_t count) data_to_write += empty_place_left_in_md; data_left_to_write -= empty_place_left_in_md; } - + if (offset > encrypted_part_plain.size) encrypted_part_plain.size = offset; // file grew, update the new file size @@ -126,7 +126,7 @@ size_t protected_fs_file::write(const void* ptr, size_t size, size_t count) size_t offset_in_node = (size_t)((offset - MD_USER_DATA_SIZE) % NODE_SIZE); size_t empty_place_left_in_node = NODE_SIZE - offset_in_node; - + if (data_left_to_write <= empty_place_left_in_node) { // this will be the last write memcpy(&file_data_node->plain.data[offset_in_node], data_to_write, data_left_to_write); @@ -272,7 +272,7 @@ size_t protected_fs_file::read(void* ptr, size_t size, size_t count) size_t offset_in_node = (offset - MD_USER_DATA_SIZE) % NODE_SIZE; size_t data_left_in_node = NODE_SIZE - offset_in_node; - + if (data_left_to_read <= data_left_in_node) { memcpy(out_buffer, &file_data_node->plain.data[offset_in_node], data_left_to_read); @@ -304,15 +304,15 @@ size_t protected_fs_file::read(void* ptr, size_t size, size_t count) } -// this is a very 'specific' function, tied to the architecture of the file layout, returning the node numbers according to the offset in the file -void get_node_numbers(uint64_t offset, uint64_t* mht_node_number, uint64_t* data_node_number, +// this is a very 'specific' function, tied to the architecture of the file layout, returning the node numbers according to the offset in the file +void get_node_numbers(uint64_t offset, uint64_t* mht_node_number, uint64_t* data_node_number, uint64_t* physical_mht_node_number, uint64_t* physical_data_node_number) { // node 0 - meta data node // node 1 - mht // nodes 2-97 - data (ATTACHED_DATA_NODES_COUNT == 96) // node 98 - mht - // node 99-195 - data + // node 99-194 - data // etc. uint64_t _mht_node_number; uint64_t _data_node_number; @@ -348,7 +348,7 @@ file_data_node_t* protected_fs_file::get_data_node() return NULL; } - if ((offset - MD_USER_DATA_SIZE) % NODE_SIZE == 0 && + if ((offset - MD_USER_DATA_SIZE) % NODE_SIZE == 0 && offset == encrypted_part_plain.size) {// new node file_data_node = append_data_node(); @@ -370,11 +370,11 @@ file_data_node_t* protected_fs_file::get_data_node() } // even if we didn't get the required data_node, we might have read other nodes in the process - while (cache.size() > MAX_PAGES_IN_CACHE) + while (cache.size() > max_cache_page) { void* data = cache.get_last(); assert(data != NULL); - // for production - + // for production - if (data == NULL) { last_error = SGX_ERROR_UNEXPECTED; @@ -409,7 +409,7 @@ file_data_node_t* protected_fs_file::get_data_node() } } } - + return file_data_node; } @@ -461,7 +461,7 @@ file_data_node_t* protected_fs_file::read_data_node() file_data_node_t* file_data_node = (file_data_node_t*)cache.get(physical_node_number); if (file_data_node != NULL) return file_data_node; - + // need to read the data node from the disk file_mht_node = get_mht_node(); @@ -481,20 +481,32 @@ file_data_node_t* protected_fs_file::read_data_node() file_data_node->data_node_number = data_node_number; file_data_node->physical_node_number = physical_node_number; file_data_node->parent = file_mht_node; - + status = u_sgxprotectedfs_fread_node(&result32, file, file_data_node->physical_node_number, file_data_node->encrypted.cipher, NODE_SIZE); if (status != SGX_SUCCESS || result32 != 0) { delete file_data_node; - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : EIO; return NULL; } gcm_crypto_data_t* gcm_crypto_data = &file_data_node->parent->plain.data_nodes_crypto[file_data_node->data_node_number % ATTACHED_DATA_NODES_COUNT]; - // this function decrypt the data _and_ checks the integrity of the data against the gmac - status = sgx_rijndael128GCM_decrypt(&gcm_crypto_data->key, file_data_node->encrypted.cipher, NODE_SIZE, file_data_node->plain.data, empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &gcm_crypto_data->gmac); + if(!integrity_only) { + // this function decrypt the data _and_ checks the integrity of the data against the gmac + status = sgx_rijndael128GCM_decrypt(&gcm_crypto_data->key, + file_data_node->encrypted.cipher, + NODE_SIZE, file_data_node->plain.data, + empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &gcm_crypto_data->gmac); + } + else { + status = sgx_rijndael128GCM_decrypt(&gcm_crypto_data->key, + NULL, 0, NULL, + empty_iv, SGX_AESGCM_IV_SIZE, + file_data_node->encrypted.cipher, NODE_SIZE, &gcm_crypto_data->gmac); + memcpy(file_data_node->plain.data, file_data_node->encrypted.cipher, NODE_SIZE); + } if (status != SGX_SUCCESS) { delete file_data_node; @@ -505,7 +517,7 @@ file_data_node_t* protected_fs_file::read_data_node() } return NULL; } - + if (cache.add(file_data_node->physical_node_number, file_data_node) == false) { memset_s(&file_data_node->plain, sizeof(data_node_t), 0, sizeof(data_node_t)); // scrub the plaintext data @@ -536,7 +548,7 @@ file_mht_node_t* protected_fs_file::get_mht_node() return &root_mht; // file is constructed from 128*4KB = 512KB per MHT node. - if ((offset - MD_USER_DATA_SIZE) % (ATTACHED_DATA_NODES_COUNT * NODE_SIZE) == 0 && + if ((offset - MD_USER_DATA_SIZE) % (ATTACHED_DATA_NODES_COUNT * NODE_SIZE) == 0 && offset == encrypted_part_plain.size) { file_mht_node = append_mht_node(mht_node_number); @@ -582,7 +594,7 @@ file_mht_node_t* protected_fs_file::append_mht_node(uint64_t mht_node_number) last_error = ENOMEM; return NULL; } - + return new_file_mht_node; } @@ -619,20 +631,32 @@ file_mht_node_t* protected_fs_file::read_mht_node(uint64_t mht_node_number) file_mht_node->mht_node_number = mht_node_number; file_mht_node->physical_node_number = physical_node_number; file_mht_node->parent = parent_file_mht_node; - + status = u_sgxprotectedfs_fread_node(&result32, file, file_mht_node->physical_node_number, file_mht_node->encrypted.cipher, NODE_SIZE); if (status != SGX_SUCCESS || result32 != 0) { delete file_mht_node; - last_error = (status != SGX_SUCCESS) ? status : + last_error = (status != SGX_SUCCESS) ? status : (result32 != -1) ? result32 : EIO; return NULL; } - + gcm_crypto_data_t* gcm_crypto_data = &file_mht_node->parent->plain.mht_nodes_crypto[(file_mht_node->mht_node_number - 1) % CHILD_MHT_NODES_COUNT]; - // this function decrypt the data _and_ checks the integrity of the data against the gmac - status = sgx_rijndael128GCM_decrypt(&gcm_crypto_data->key, file_mht_node->encrypted.cipher, NODE_SIZE, (uint8_t*)&file_mht_node->plain, empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &gcm_crypto_data->gmac); + if(!integrity_only){ + // this function decrypt the data _and_ checks the integrity of the data against the gmac + status = sgx_rijndael128GCM_decrypt(&gcm_crypto_data->key, + file_mht_node->encrypted.cipher, + NODE_SIZE, (uint8_t*)&file_mht_node->plain, + empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &gcm_crypto_data->gmac); + } + else { + status = sgx_rijndael128GCM_decrypt(&gcm_crypto_data->key, + NULL, 0, NULL, + empty_iv, SGX_AESGCM_IV_SIZE, + file_mht_node->encrypted.cipher, NODE_SIZE, &gcm_crypto_data->gmac); + memcpy((uint8_t*)&file_mht_node->plain, file_mht_node->encrypted.cipher, NODE_SIZE); + } if (status != SGX_SUCCESS) { delete file_mht_node; @@ -654,4 +678,3 @@ file_mht_node_t* protected_fs_file::read_mht_node(uint64_t mht_node_number) return file_mht_node; } - diff --git a/sdk/protected_fs/sgx_tprotected_fs/lru_cache.cpp b/sdk/protected_fs/sgx_tprotected_fs/lru_cache.cpp index 5b7918beb..bacc28526 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/lru_cache.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/lru_cache.cpp @@ -61,7 +61,7 @@ lru_cache::~lru_cache() } -void lru_cache::rehash(uint32_t size_) +void lru_cache::rehash(uint64_t size_) { map.rehash(size_); } @@ -272,4 +272,3 @@ void lru_cache::remove_last() map.erase(key); delete map_node; } - diff --git a/sdk/protected_fs/sgx_tprotected_fs/lru_cache.h b/sdk/protected_fs/sgx_tprotected_fs/lru_cache.h index f024f7e25..64b43eb83 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/lru_cache.h +++ b/sdk/protected_fs/sgx_tprotected_fs/lru_cache.h @@ -83,7 +83,7 @@ class lru_cache lru_cache(); ~lru_cache(); - void rehash(uint32_t size_); + void rehash(uint64_t size_); bool add(uint64_t key, void* p); void* get(uint64_t key); diff --git a/sdk/protected_fs/sgx_tprotected_fs/protected_fs_file.h b/sdk/protected_fs/sgx_tprotected_fs/protected_fs_file.h index f02b208f1..66fef67e8 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/protected_fs_file.h +++ b/sdk/protected_fs/sgx_tprotected_fs/protected_fs_file.h @@ -52,12 +52,15 @@ typedef enum SGX_FILE_STATUS_CRYPTO_ERROR, SGX_FILE_STATUS_CORRUPTED, SGX_FILE_STATUS_MEMORY_CORRUPTED, - //SGX_FILE_STATUS_WRITE_TO_DISK_FAILED_NEED_MC, - //SGX_FILE_STATUS_MC_NOT_INCREMENTED, SGX_FILE_STATUS_CLOSED, } protected_fs_status_e; +#ifndef SE_PAGE_SIZE +#define SE_PAGE_SIZE 0x1000 +#endif + #define MAX_PAGES_IN_CACHE 48 +#define DEFAULT_CACHE_SIZE (MAX_PAGES_IN_CACHE * SE_PAGE_SIZE) COMPILE_TIME_ASSERT(filename_length, FILENAME_MAX_LEN == FILENAME_MAX); @@ -143,22 +146,23 @@ class protected_fs_file }; meta_data_encrypted_t encrypted_part_plain; // encrypted part of meta data node, decrypted - + file_mht_node_t root_mht; // the root of the mht is always needed (for files bigger than 3KB) FILE* file; // OS's FILE pointer - + open_mode_t open_mode; uint8_t read_only; int64_t offset; // current file position (user's view) bool end_of_file; // flag + uint64_t max_cache_page; int64_t real_file_size; - + bool integrity_only; // If true, no encryption, only MAC. Default: false. bool need_writing; // flag uint32_t last_error; // last operation error protected_fs_status_e file_status; - + sgx_thread_mutex_t mutex; uint8_t use_user_kdk_key; @@ -167,7 +171,7 @@ class protected_fs_file sgx_aes_gcm_128bit_key_t cur_key; sgx_aes_gcm_128bit_key_t session_master_key; uint32_t master_key_count; - + char recovery_filename[RECOVERY_FILE_MAX_LEN]; // might include full path to the file lru_cache cache; @@ -176,21 +180,21 @@ class protected_fs_file sgx_iv_t empty_iv; sgx_report_t report; - void init_fields(); + void init_fields(const uint64_t cache_page); bool cleanup_filename(const char* src, char* dest); bool parse_mode(const char* mode); bool file_recovery(const char* filename); bool init_existing_file(const char* filename, const char* clean_filename, const sgx_aes_gcm_128bit_key_t* import_key); bool init_new_file(const char* clean_filename); - + bool generate_secure_blob(sgx_aes_gcm_128bit_key_t* key, const char* label, uint64_t physical_node_number, sgx_aes_gcm_128bit_tag_t* output); bool generate_secure_blob_from_user_kdk(bool restore); bool init_session_master_key(); bool derive_random_node_key(uint64_t physical_node_number); bool generate_random_meta_data_key(); bool restore_current_meta_data_key(const sgx_aes_gcm_128bit_key_t* import_key); - - + + file_data_node_t* get_data_node(); file_data_node_t* read_data_node(); file_data_node_t* append_data_node(); @@ -204,10 +208,10 @@ class protected_fs_file bool update_meta_data_node(); bool write_all_changes_to_disk(bool flush_to_disk); void erase_recovery_file(); - bool internal_flush(/*bool mc,*/ bool flush_to_disk); + bool internal_flush(bool flush_to_disk); public: - protected_fs_file(const char* filename, const char* mode, const sgx_aes_gcm_128bit_key_t* import_key, const sgx_aes_gcm_128bit_key_t* kdk_key); + protected_fs_file(const char* filename, const char* mode, const sgx_aes_gcm_128bit_key_t* import_key, const sgx_aes_gcm_128bit_key_t* kdk_key, bool integrity_only, const uint64_t cache_page); ~protected_fs_file(); size_t write(const void* ptr, size_t size, size_t count); @@ -218,8 +222,9 @@ class protected_fs_file uint32_t get_error(); void clear_error(); int32_t clear_cache(); - bool flush(/*bool mc*/); + bool flush(); bool pre_close(sgx_key_128bit_t* key, bool import); + int32_t get_root_mac(sgx_aes_gcm_128bit_tag_t* root_mac); static int32_t remove(const char* filename); }; diff --git a/sdk/protected_fs/sgx_tprotected_fs/protected_fs_nodes.h b/sdk/protected_fs/sgx_tprotected_fs/protected_fs_nodes.h index e360cca7d..8541ed474 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/protected_fs_nodes.h +++ b/sdk/protected_fs/sgx_tprotected_fs/protected_fs_nodes.h @@ -66,8 +66,9 @@ typedef struct _meta_data_plain sgx_attributes_t attribute_mask; sgx_aes_gcm_128bit_tag_t meta_data_gmac; - + uint8_t update_flag; + uint8_t integrity_only; } meta_data_plain_t; // these are all defined as relative to node size, so we can decrease node size in tests and have deeper tree @@ -83,7 +84,7 @@ typedef struct _meta_data_encrypted { char clean_filename[FILENAME_MAX_LEN]; int64_t size; - + sgx_mc_uuid_t mc_uuid; // not used uint32_t mc_value; // not used @@ -153,4 +154,3 @@ typedef struct _recovery_node #pragma pack(pop) #endif // _PROTECTED_FS_NODES_H_ - diff --git a/sdk/protected_fs/sgx_tprotected_fs/sgx_tprotected_fs.cpp b/sdk/protected_fs/sgx_tprotected_fs/sgx_tprotected_fs.cpp index fe8634acc..2cf3681b1 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/sgx_tprotected_fs.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/sgx_tprotected_fs.cpp @@ -35,19 +35,22 @@ #include - -static SGX_FILE* sgx_fopen_internal(const char* filename, const char* mode, const sgx_key_128bit_t *auto_key, const sgx_key_128bit_t *kdk_key) +static SGX_FILE* sgx_fopen_internal(const char* filename, const char* mode, const sgx_key_128bit_t *auto_key, const sgx_key_128bit_t *kdk_key, bool integrity_only, const uint64_t cache_size) { protected_fs_file* file = NULL; + uint64_t cache_page = 0; - if (filename == NULL || mode == NULL) + if (filename == NULL || mode == NULL || + cache_size < DEFAULT_CACHE_SIZE || cache_size % SE_PAGE_SIZE != 0) { errno = EINVAL; return NULL; } + cache_page = cache_size / SE_PAGE_SIZE; + try { - file = new protected_fs_file(filename, mode, auto_key, kdk_key); + file = new protected_fs_file(filename, mode, auto_key, kdk_key, integrity_only, cache_page); } catch (std::bad_alloc& e) { (void)e; // remove warning @@ -68,13 +71,23 @@ static SGX_FILE* sgx_fopen_internal(const char* filename, const char* mode, cons SGX_FILE* sgx_fopen_auto_key(const char* filename, const char* mode) { - return sgx_fopen_internal(filename, mode, NULL, NULL); + return sgx_fopen_internal(filename, mode, NULL, NULL, false, DEFAULT_CACHE_SIZE); } +SGX_FILE* sgx_fopen_integrity_only(const char* filename, const char* mode) +{ + sgx_key_128bit_t empty_key = {0}; + return sgx_fopen_internal(filename, mode, NULL, &empty_key, true, DEFAULT_CACHE_SIZE); +} SGX_FILE* sgx_fopen(const char* filename, const char* mode, const sgx_key_128bit_t *key) { - return sgx_fopen_internal(filename, mode, NULL, key); + return sgx_fopen_internal(filename, mode, NULL, key, false, DEFAULT_CACHE_SIZE); +} + +SGX_FILE* SGXAPI sgx_fopen_ex(const char* filename, const char* mode, const sgx_key_128bit_t *key, const uint64_t cache_size) +{ + return sgx_fopen_internal(filename, mode, NULL, key, false, cache_size); } @@ -133,30 +146,6 @@ int32_t sgx_fflush(SGX_FILE* stream) } -/* sgx_fflush_and_increment_mc - * Purpose: force actual write of all the cached data to the disk (see c++ fflush documentation for more details). - * in addition, in the first time this function is called, it adds a monotonic counter to the file - * in subsequent calls, the monotonic counter is incremented by one every time this function is called - * the monotonic counter is a limited resource, please read the SGX documentation for more details - * - * Parameters: - * stream - [IN] the file handle (opened with sgx_fopen or sgx_fopen_auto_key) - * - * Return value: - * int32_t - result, 0 on success, 1 in case of an error - check sgx_ferror for error code - * -int32_t sgx_fflush_and_increment_mc(SGX_FILE* stream) -{ - if (stream == NULL) - return 1; - - protected_fs_file* file = (protected_fs_file*)stream; - - return file->flush(true) == true ? 0 : 1; -} -*/ - - int32_t sgx_ferror(SGX_FILE* stream) { if (stream == NULL) @@ -172,7 +161,7 @@ int32_t sgx_feof(SGX_FILE* stream) { if (stream == NULL) return -1; - + protected_fs_file* file = (protected_fs_file*)stream; return ((file->get_eof() == true) ? 1 : 0); @@ -222,7 +211,7 @@ int32_t sgx_remove(const char* filename) int32_t sgx_fexport_auto_key(const char* filename, sgx_key_128bit_t *key) { - SGX_FILE* stream = sgx_fopen_internal(filename, "r", NULL, NULL); + SGX_FILE* stream = sgx_fopen_internal(filename, "r", NULL, NULL, false, DEFAULT_CACHE_SIZE); if (stream == NULL) return 1; @@ -232,7 +221,7 @@ int32_t sgx_fexport_auto_key(const char* filename, sgx_key_128bit_t *key) int32_t sgx_fimport_auto_key(const char* filename, const sgx_key_128bit_t *key) { - SGX_FILE* stream = sgx_fopen_internal(filename, "r+", key, NULL); + SGX_FILE* stream = sgx_fopen_internal(filename, "r+", key, NULL, false, DEFAULT_CACHE_SIZE); if (stream == NULL) return 1; @@ -251,4 +240,14 @@ int32_t sgx_fclear_cache(SGX_FILE* stream) } +int32_t SGXAPI sgx_fget_mac(SGX_FILE* stream, sgx_aes_gcm_128bit_tag_t* mac) +{ + if (stream == NULL) + return 1; + + protected_fs_file* file = (protected_fs_file*)stream; + if (file->flush() == false) + return 1; + return file->get_root_mac(mac); +} diff --git a/sdk/protected_fs/sgx_uprotected_fs/sgx_uprotected_fs.cpp b/sdk/protected_fs/sgx_uprotected_fs/sgx_uprotected_fs.cpp index d38cb46a7..7e451cc27 100644 --- a/sdk/protected_fs/sgx_uprotected_fs/sgx_uprotected_fs.cpp +++ b/sdk/protected_fs/sgx_uprotected_fs/sgx_uprotected_fs.cpp @@ -58,7 +58,7 @@ void* u_sgxprotectedfs_exclusive_file_open(const char* filename, uint8_t read_on int fd = -1; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; struct stat stat_st; - + memset(&stat_st, 0, sizeof(struct stat)); if (filename == NULL || strnlen(filename, 1) == 0) @@ -99,7 +99,7 @@ void* u_sgxprotectedfs_exclusive_file_open(const char* filename, uint8_t read_on assert(result == 0); return NULL; } - + // convert the file handle to standard 'C' API file pointer f = fdopen(fd, read_only ? "rb" : "r+b"); if (f == NULL) @@ -122,7 +122,7 @@ void* u_sgxprotectedfs_exclusive_file_open(const char* filename, uint8_t read_on uint8_t u_sgxprotectedfs_check_if_file_exists(const char* filename) { struct stat stat_st; - + memset(&stat_st, 0, sizeof(struct stat)); if (filename == NULL || strnlen(filename, 1) == 0) @@ -130,8 +130,8 @@ uint8_t u_sgxprotectedfs_check_if_file_exists(const char* filename) DEBUG_PRINT("filename is NULL or empty\n"); return 1; } - - return (stat(filename, &stat_st) == 0); + + return (stat(filename, &stat_st) == 0); } @@ -247,7 +247,7 @@ int32_t u_sgxprotectedfs_fclose(void* f) DEBUG_PRINT("fileno returned -1\n"); else flock(fd, LOCK_UN); - + if ((result = fclose(file)) != 0) { if (errno != 0) @@ -274,13 +274,13 @@ uint8_t u_sgxprotectedfs_fflush(void* f) DEBUG_PRINT("file is NULL\n"); return 1; } - + if ((result = fflush(file)) != 0) { DEBUG_PRINT("fflush returned %d\n", result); return 1; } - + return 0; } @@ -302,7 +302,7 @@ int32_t u_sgxprotectedfs_remove(const char* filename) return errno; return -1; } - + return 0; } @@ -317,7 +317,7 @@ void* u_sgxprotectedfs_recovery_file_open(const char* filename) DEBUG_PRINT("recovery filename is NULL or empty\n"); return NULL; } - + for (int i = 0; i < MAX_FOPEN_RETRIES; i++) { f = fopen(filename, "wb"); @@ -330,7 +330,7 @@ void* u_sgxprotectedfs_recovery_file_open(const char* filename) DEBUG_PRINT("fopen (%s) returned NULL\n", filename); return NULL; } - + return f; } @@ -344,7 +344,7 @@ uint8_t u_sgxprotectedfs_fwrite_recovery_node(void* f, uint8_t* data, uint32_t d DEBUG_PRINT("file is NULL\n"); return 1; } - + // recovery nodes are written sequentially size_t count = fwrite(data, 1, data_length, file); if (count != data_length) @@ -371,7 +371,7 @@ int32_t u_sgxprotectedfs_do_file_recovery(const char* filename, const char* reco uint8_t* recovery_node = NULL; uint32_t i = 0; - do + do { if (filename == NULL || strnlen(filename, 1) == 0) { @@ -384,7 +384,7 @@ int32_t u_sgxprotectedfs_do_file_recovery(const char* filename, const char* reco DEBUG_PRINT("recovery filename is NULL or empty\n"); return (int32_t)NULL; } - + recovery_file = fopen(recovery_filename, "rb"); if (recovery_file == NULL) { @@ -402,7 +402,7 @@ int32_t u_sgxprotectedfs_do_file_recovery(const char* filename, const char* reco } file_size = ftello(recovery_file); - + if ((result = fseeko(recovery_file, 0, SEEK_SET)) != 0) { DEBUG_PRINT("fseeko returned %d\n", result); @@ -445,7 +445,7 @@ int32_t u_sgxprotectedfs_do_file_recovery(const char* filename, const char* reco err = ferror(recovery_file); if (err != 0) ret = err; - else if (errno != 0) + else if (errno != 0) ret = errno; break; } @@ -466,7 +466,7 @@ int32_t u_sgxprotectedfs_do_file_recovery(const char* filename, const char* reco err = ferror(source_file); if (err != 0) ret = err; - else if (errno != 0) + else if (errno != 0) ret = errno; break; } @@ -503,6 +503,6 @@ int32_t u_sgxprotectedfs_do_file_recovery(const char* filename, const char* reco if (ret == 0) remove(recovery_filename); - + return ret; } diff --git a/sdk/sign_tool/SignTool/enclave_creator_sign.cpp b/sdk/sign_tool/SignTool/enclave_creator_sign.cpp index b1585a4b6..9d5896e78 100644 --- a/sdk/sign_tool/SignTool/enclave_creator_sign.cpp +++ b/sdk/sign_tool/SignTool/enclave_creator_sign.cpp @@ -305,6 +305,15 @@ int EnclaveCreatorST::get_enclave_info(uint8_t *hash, int size, uint64_t *quota) return SGX_SUCCESS; } +int EnclaveCreatorST::alloc(uint64_t addr, uint64_t size, int flag) +{ + UNUSED(addr); + UNUSED(size); + UNUSED(flag); + + return SGX_SUCCESS; +} + int EnclaveCreatorST::emodpr(uint64_t addr, uint64_t size, uint64_t flag) { UNUSED(addr); @@ -337,14 +346,6 @@ int EnclaveCreatorST::trim_accept(uint64_t addr) return SGX_SUCCESS; } -int EnclaveCreatorST::remove_range(uint64_t fromaddr, uint64_t numpages) -{ - UNUSED(fromaddr); - UNUSED(numpages); - - return SGX_SUCCESS; -} - static EnclaveCreatorST g_enclave_creator_st; EnclaveCreator* g_enclave_creator = &g_enclave_creator_st; diff --git a/sdk/sign_tool/SignTool/enclave_creator_sign.h b/sdk/sign_tool/SignTool/enclave_creator_sign.h index dd23c83ef..4703d8fc8 100644 --- a/sdk/sign_tool/SignTool/enclave_creator_sign.h +++ b/sdk/sign_tool/SignTool/enclave_creator_sign.h @@ -56,12 +56,11 @@ class EnclaveCreatorST : public EnclaveCreator bool is_EDMM_supported(sgx_enclave_id_t enclave_id); bool is_driver_compatible(); int get_enclave_info(uint8_t *hash, int size, uint64_t *quota); + int alloc(uint64_t addr, uint64_t size, int flag); int emodpr(uint64_t addr, uint64_t size, uint64_t flag); int mktcs(uint64_t tcs_addr); int trim_range(uint64_t fromaddr, uint64_t toaddr); int trim_accept(uint64_t addr); - int remove_range(uint64_t fromaddr, uint64_t numpages); - private: uint8_t m_enclave_hash[SGX_HASH_SIZE]; EVP_MD_CTX *m_ctx; diff --git a/sdk/sign_tool/SignTool/manage_metadata.cpp b/sdk/sign_tool/SignTool/manage_metadata.cpp index e75a18fe2..e97d16c08 100644 --- a/sdk/sign_tool/SignTool/manage_metadata.cpp +++ b/sdk/sign_tool/SignTool/manage_metadata.cpp @@ -48,6 +48,8 @@ #include "crypto_wrapper.h" #include "global_data.h" #include "se_version.h" +#include "ema_imp.h" +#include "bit_array_imp.h" #include #include @@ -401,7 +403,8 @@ bool CMetadata::modify_metadata(const xml_parameter_t *parameter) //set bits that have been set '1' and need to be checked m_metadata->attributes.xfrm |= (m_metadata->enclave_css.body.attributes.xfrm & m_metadata->enclave_css.body.attribute_mask.xfrm); - return true; + bool ret = check_config(); + return ret; } bool CMetadata::check_xml_parameter(const xml_parameter_t *parameter) @@ -489,6 +492,12 @@ bool CMetadata::check_xml_parameter(const xml_parameter_t *parameter) } } + if ((parameter[USERREGIONSIZE].value % ALIGN_SIZE)) + { + se_trace(SE_TRACE_ERROR, SET_USER_REGION_SIZE_ALIGN_ERROR); + return false; + } + // LE setting: HW != 0, Licensekey = 1 // Other enclave setting: HW = 0, Licensekey = 0 if((parameter[HW].value == 0 && parameter[LAUNCHKEY].value != 0) || @@ -547,6 +556,7 @@ bool CMetadata::check_xml_parameter(const xml_parameter_t *parameter) m_create_param.rsrv_min_size = parameter[RSRVMINSIZE].value; m_create_param.rsrv_max_size = parameter[RSRVMAXSIZE].value; m_create_param.rsrv_executable = parameter[RSRVEXECUTABLE].flag ? parameter[RSRVEXECUTABLE].value : 0; + m_create_param.user_region_size = parameter[USERREGIONSIZE].value; m_create_param.stack_max_size = parameter[STACKMAXSIZE].value; m_create_param.stack_min_size = parameter[STACKMINSIZE].value; m_create_param.tcs_num = (uint32_t)parameter[TCSNUM].value; @@ -558,10 +568,152 @@ bool CMetadata::check_xml_parameter(const xml_parameter_t *parameter) SE_TRACE_DEBUG("RSRV_MIN_SIZE = 0x%016llX\n", m_create_param.rsrv_min_size); SE_TRACE_DEBUG("RSRV_INIT_SIZE = 0x%016llX\n", m_create_param.rsrv_init_size); SE_TRACE_DEBUG("RSRV_MAX_SIZE = 0x%016llX\n", m_create_param.rsrv_max_size); + SE_TRACE_DEBUG("USER_REGION_SIZE = 0x%016llX\n", m_create_param.user_region_size); return true; } +uint64_t CMetadata::calculate_rts_bk_overhead() +{ + uint64_t ema_overhead = sizeof(struct ema_t_); + uint64_t bit_array_overhead = sizeof(struct bit_array_); + + // MIN heap + uint32_t page_count = (uint32_t)(m_create_param.heap_min_size >> SE_PAGE_SHIFT); + uint64_t heap_node_overhead = ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + + if(m_create_param.heap_init_size > m_create_param.heap_min_size) + { + // INIT heap + page_count = (uint32_t)((m_create_param.heap_init_size - m_create_param.heap_min_size) >> SE_PAGE_SHIFT); + heap_node_overhead += ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + } + + if(m_create_param.heap_max_size > m_create_param.heap_init_size) + { + page_count = (uint32_t)((m_create_param.heap_max_size - m_create_param.heap_init_size) >> SE_PAGE_SHIFT); + heap_node_overhead += ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + } + + page_count = (uint32_t)(m_create_param.rsrv_min_size >> SE_PAGE_SHIFT); + uint64_t rsrv_node_overhead = ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + + if(m_create_param.rsrv_init_size > m_create_param.rsrv_min_size) + { + // INIT RSRV + page_count = (uint32_t)((m_create_param.rsrv_init_size - m_create_param.rsrv_min_size) >> SE_PAGE_SHIFT); + rsrv_node_overhead += ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + } + + if(m_create_param.rsrv_max_size > m_create_param.rsrv_init_size) + { + page_count = (uint32_t)((m_create_param.rsrv_max_size - m_create_param.rsrv_init_size) >> SE_PAGE_SHIFT); + rsrv_node_overhead += ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + } + // guard page | stack | guard page | TCS | SSA | guard page | TLS + + // guard page + uint64_t non_removed_ctx_overhead = ema_overhead; + uint64_t removed_ctx_overhead = ema_overhead; + + // stack + page_count = (uint32_t)(m_create_param.stack_min_size >> SE_PAGE_SHIFT); + non_removed_ctx_overhead += ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + removed_ctx_overhead += ema_overhead; + + if(m_create_param.stack_max_size > m_create_param.stack_min_size) + { + page_count = (uint32_t)((m_create_param.stack_max_size - m_create_param.stack_min_size) >> SE_PAGE_SHIFT); + non_removed_ctx_overhead += ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + removed_ctx_overhead += ema_overhead; + } + + // guard page + non_removed_ctx_overhead += ema_overhead; + removed_ctx_overhead += ema_overhead; + + // tcs + page_count = TCS_SIZE >> SE_PAGE_SHIFT; + non_removed_ctx_overhead += ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + removed_ctx_overhead += ema_overhead; + + // ssa + page_count = SSA_FRAME_SIZE * SSA_NUM; + non_removed_ctx_overhead += ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + removed_ctx_overhead += ema_overhead; + + // guard page + non_removed_ctx_overhead += ema_overhead; + removed_ctx_overhead += ema_overhead; + + // td + page_count = 1; + const Section *section = m_parser->get_tls_section(); + if(section) + { + page_count += (uint32_t)(ROUND_TO_PAGE(section->virtual_size()) >> SE_PAGE_SHIFT); + } + non_removed_ctx_overhead += ema_overhead + bit_array_overhead + (ROUND_TO(page_count, 8) >> 3); + removed_ctx_overhead += ema_overhead; + + uint32_t tcs_min_pool = 0; /* Number of static threads (EADD) */ + uint32_t tcs_eremove = 0; + if(m_create_param.tcs_min_pool > m_create_param.tcs_num - 1) + { + tcs_min_pool = m_create_param.tcs_num - 1; + tcs_eremove = 0; + } + else + { + tcs_min_pool = m_create_param.tcs_min_pool; + tcs_eremove = m_create_param.tcs_num -1 - m_create_param.tcs_min_pool; + } + + // static thread contexts + uint64_t total_non_removed_ctx_overhead = non_removed_ctx_overhead; + if (tcs_min_pool > 0) + { + total_non_removed_ctx_overhead += non_removed_ctx_overhead; + + if (tcs_min_pool > 1) + { + total_non_removed_ctx_overhead += non_removed_ctx_overhead * (tcs_min_pool - 1); + } + } + + // eremoved thread contexts + uint64_t total_removed_ctx_overhead = removed_ctx_overhead; + if (tcs_eremove > 0) + { + total_removed_ctx_overhead += removed_ctx_overhead; + + if (tcs_eremove > 1) + { + total_removed_ctx_overhead += removed_ctx_overhead * (tcs_eremove - 1); + } + } + + // dynamic thread contexts + if (m_create_param.tcs_max_num > tcs_min_pool + 1) + { + total_non_removed_ctx_overhead += non_removed_ctx_overhead * (m_create_param.tcs_max_num - tcs_min_pool); + } + + // PT_LOAD segments + uint64_t total_sections_overhead = 0; + std::vector sections = m_parser->get_sections(); + for (auto s : sections) { + uint32_t p_count = (uint32_t)(ROUND_TO_PAGE(s->virtual_size()) >> SE_PAGE_SHIFT); + total_sections_overhead += ema_overhead + bit_array_overhead + (ROUND_TO(p_count, 8) >> 3); + } + + return heap_node_overhead + + rsrv_node_overhead + + total_non_removed_ctx_overhead + + total_removed_ctx_overhead + + total_sections_overhead; +} + void *CMetadata::alloc_buffer_from_metadata(uint32_t size) { void *addr = GET_PTR(void, m_metadata, m_metadata->size); @@ -998,6 +1150,27 @@ bool CMetadata::build_layout_table() } } + // USER_REGION + uint8_t meta_versions = get_meta_versions(); + // SGX2 metadata required + if ((meta_versions & 2u) == 2u) + { + uint64_t rts_bk_overhead = calculate_rts_bk_overhead() + 0x20000; + uint64_t user_region_size = ROUND_TO_PAGE(rts_bk_overhead); + se_trace(SE_TRACE_ERROR, "RTS bookkeeping overhead: 0x%016llX\n", user_region_size); + + if (m_create_param.user_region_size > 0) + { + user_region_size += m_create_param.user_region_size; + } + memset(&layout, 0, sizeof(layout)); + layout.entry.id = LAYOUT_ID_USER_REGION; + layout.entry.page_count = (uint32_t)(user_region_size >> SE_PAGE_SHIFT); + layout.entry.attributes = PAGE_ATTR_POST_ADD; + layout.entry.si_flags = SI_FLAGS_RW; + m_layouts.push_back(layout); + } + // update layout entries if(false == update_layout_entries()) { @@ -1219,6 +1392,16 @@ bool CMetadata::build_gd_template(uint8_t *data, uint32_t *data_size) m_create_param.rsrv_offset = (size_t)layout_rsrv->rva; } + layout_entry_t * layout_user = get_entry_by_id(LAYOUT_ID_USER_REGION, false); + if (NULL == layout_user) + { + m_create_param.user_region_offset = (size_t)0; + } + else + { + m_create_param.user_region_offset = (size_t)layout_user->rva; + } + size_t tmp_tls_addr = (size_t)(get_entry_by_id(LAYOUT_ID_TD)->rva - get_entry_by_id(LAYOUT_ID_TCS)->rva); m_create_param.td_addr = tmp_tls_addr + (size_t)((get_entry_by_id(LAYOUT_ID_TD)->page_count - 1) << SE_PAGE_SHIFT); @@ -1327,6 +1510,117 @@ uint64_t CMetadata::calculate_enclave_size(uint64_t size) return round_size; } +bool CMetadata::rts_dynamic() +{ + bool no_dynamic_heap = + ((m_create_param.heap_init_size == m_create_param.heap_min_size) && + (m_create_param.heap_init_size == m_create_param.heap_max_size)); + + bool no_dynamic_stack = + (m_create_param.stack_max_size == m_create_param.stack_min_size); + + bool no_dynamic_rsrv = + ((m_create_param.rsrv_init_size == m_create_param.rsrv_min_size) && + (m_create_param.rsrv_init_size == m_create_param.rsrv_max_size)); + + + uint32_t tcs_min_pool = 0; + if(m_create_param.tcs_min_pool > m_create_param.tcs_num - 1) + { + tcs_min_pool = m_create_param.tcs_num - 1; + } + else + { + tcs_min_pool = m_create_param.tcs_min_pool; + } + + bool no_dynamic_thread = (m_create_param.tcs_max_num == tcs_min_pool + 1); + + bool no_rts_dynamic = (no_dynamic_heap && no_dynamic_stack && + no_dynamic_rsrv && no_dynamic_thread); + + return !no_rts_dynamic; +} + +bool CMetadata::user_dynamic() +{ + return (m_create_param.user_region_size > 0); +} + +sgx_misc_select_t CMetadata::get_config_misc_select() +{ + return m_metadata->enclave_css.body.misc_select; +} + +sgx_misc_select_t CMetadata::get_config_misc_mask() +{ + return m_metadata->enclave_css.body.misc_mask; +} + +bool CMetadata::check_config() +{ + uint32_t misc_select_0 = (uint32_t)get_config_misc_select() & 1u; + uint32_t misc_mask_0 = (uint32_t)get_config_misc_mask() & 1u; + + bool has_rts_dynamic = rts_dynamic(); + bool has_user_dynamic = user_dynamic(); + + // user region configured, either mask or select, or both are zero + if (has_user_dynamic) + { + if ((misc_mask_0 && misc_select_0) == 0) + { + m_meta_verions = 0; + se_trace(SE_TRACE_ERROR, "\033[0;31mERROR: Enclave configuration 'UserRegionSize' requires MiscSelect[0] and MiscMask[0] set to 1.\n\033[0m"); + return false; + } + else + { + // SGX2 metadata only + m_meta_verions = 1u << 1; + se_trace(SE_TRACE_ERROR, "\033[0;32mINFO: Enclave configuration 'UserRegionSize' requires the enclave to be run on SGX2 platform.\n\033[0m"); + return true; + } + } + + if (has_rts_dynamic) + { + if (misc_select_0 == 0) + { + // SGX1 metadata only + m_meta_verions = 1u; + se_trace(SE_TRACE_ERROR, "\033[0;32mINFO: Enclave configuration 'MiscSelect' and 'MiscSelectMask' will prevent enclave from using dynamic features. To use the dynamic features on SGX2 platform, suggest to set MiscSelectMask[0]=0 and MiscSelect[0]=1.\n\033[0m"); + return true; + } + + if (misc_mask_0 == 1) + { + // SGX2 metadata only + m_meta_verions = 1u << 1; + se_trace(SE_TRACE_ERROR, "\033[0;32mINFO: Enclave configuration 'MiscSelect' and 'MiscSelectMask' will prevent enclave from running on SGX1 platform. To make it run on SGX1 platform, suggest to set MiscSelectMask[0]=0 and MiscSelect[0]=1.\n\033[0m"); + return true; + } + + // SGX1 and SGX2 metadata + m_meta_verions = (1u << 1) | 1u; + se_trace(SE_TRACE_ERROR, "\033[0;32mINFO: Enclave configuration 'MiscSelect' and 'MiscSelectMask' will work on SGX1 and SGX2 platforms with respective metadata.\n\033[0m"); + return true; + } + + // SGX1 metadata only + m_meta_verions = 1u; + if (misc_select_0 == 1) + { + se_trace(SE_TRACE_ERROR, "\033[0;32mINFO: Enclave configuration 'MiscSelect' and 'MiscSelectMask' will prevent enclave from running on SGX1 platform.\n\033[0m"); + return true; + } + else + { + se_trace(SE_TRACE_ERROR, "\033[0;32mINFO: SGX1 only enclave, which will run on all platforms.\n\033[0m"); + return true; + } +} + bool update_metadata(const char *path, const metadata_t *metadata, uint64_t meta_offset) { assert(path != NULL && metadata != NULL); diff --git a/sdk/sign_tool/SignTool/manage_metadata.h b/sdk/sign_tool/SignTool/manage_metadata.h index 856e6abc8..df5bb4a02 100644 --- a/sdk/sign_tool/SignTool/manage_metadata.h +++ b/sdk/sign_tool/SignTool/manage_metadata.h @@ -83,7 +83,8 @@ typedef enum _para_type_t ENCLAVEIMAGEADDRESS, ELRANGESTARTADDRESS, ELRANGESIZE, - PKRU + PKRU, + USERREGIONSIZE } para_type_t; typedef struct _xml_parameter_t @@ -106,6 +107,11 @@ class CMetadata: private Uncopyable CMetadata(metadata_t *metadata, BinParser *parser); ~CMetadata(); bool build_metadata(const xml_parameter_t *parameter); + bool rts_dynamic(); + bool user_dynamic(); + sgx_misc_select_t get_config_misc_select(); + sgx_misc_select_t get_config_misc_mask(); + uint8_t get_meta_versions() { return m_meta_verions; } private: bool get_time(uint32_t *date); bool modify_metadata(const xml_parameter_t *parameter); @@ -128,6 +134,9 @@ class CMetadata: private Uncopyable void* get_rawdata_by_rva(uint64_t rva); bool vaildate_elrange_config(); bool build_elrange_config_entry(); + uint64_t calculate_rts_bk_overhead(); + bool check_config(); + uint8_t m_meta_verions; metadata_t *m_metadata; BinParser *m_parser; diff --git a/sdk/sign_tool/SignTool/sign_tool.cpp b/sdk/sign_tool/SignTool/sign_tool.cpp index ea9f5317f..a6710ec1e 100644 --- a/sdk/sign_tool/SignTool/sign_tool.cpp +++ b/sdk/sign_tool/SignTool/sign_tool.cpp @@ -141,9 +141,9 @@ static bool get_enclave_info(BinParser *parser, bin_fmt_t *bf, uint64_t * meta_o // measure_enclave(): // 1. Get the enclave hash by loading enclave // 2. Get the enclave info - metadata offset and enclave file format -static bool measure_enclave(uint8_t *hash, const char *dllpath, const xml_parameter_t *parameter, uint32_t option_flag_bits, metadata_t *metadata, uint64_t *meta_offset) +static bool measure_enclave(uint8_t *hash, const char *dllpath, const xml_parameter_t *parameter, uint32_t option_flag_bits, metadata_t *metadata, uint64_t *meta_offset, uint8_t *meta_versions) { - assert(hash && dllpath && metadata && meta_offset); + assert(hash && dllpath && metadata && meta_offset && meta_versions); bool res = false; off_t file_size = 0; uint64_t quota = 0; @@ -189,6 +189,9 @@ static bool measure_enclave(uint8_t *hash, const char *dllpath, const xml_parame return false; } + // get the versions of metadata we need to output + *meta_versions = meta.get_meta_versions(); + // Collect enclave info if(get_enclave_info(parser.get(), &bin_fmt, meta_offset, false, ENABLE_RESIGN(option_flag_bits)) == false) { @@ -1066,29 +1069,67 @@ static bool append_compatible_metadata(metadata_t *compat_metadata, metadata_t * return true; } -static bool generate_compatible_metadata(metadata_t *metadata, const xml_parameter_t *parameter) +static bool handle_compatible_metadata(metadata_t *compat_metadata, metadata_t *metadata, bool append) +{ + if (append) { + se_trace(SE_TRACE_ERROR, "%s: Append metadata version 0x%lx\n", __FUNCTION__, compat_metadata->version); + return append_compatible_metadata(compat_metadata, metadata); + } else { + // overwrite + memset(metadata, 0, METADATA_SIZE); + if(memcpy_s(metadata, METADATA_SIZE, compat_metadata, compat_metadata->size)) + return false; + se_trace(SE_TRACE_ERROR, "%s: Overwrite with metadata version 0x%lx\n", __FUNCTION__, metadata->version); + return true; + } +} + +static bool generate_compatible_metadata(metadata_t *metadata, const xml_parameter_t *parameter, uint8_t meta_versions) { + if(meta_versions == 0) + { + se_trace(SE_TRACE_ERROR, "metadata version is invalid"); + return false; + } + + bool meta_sgx1_only = ((meta_versions & 3u) == 1u); + bool meta_sgx2_only = ((meta_versions & 3u) == 2u); + bool append = (meta_sgx1_only ? false : true); + + if (meta_sgx2_only) { + se_trace(SE_TRACE_ERROR, "%s: Only requires SGX2 metadata\n", __FUNCTION__); + return true; + } + metadata_t *metadata2 = (metadata_t *)malloc(metadata->size); if(!metadata2) { se_trace(SE_TRACE_ERROR, NO_MEMORY_ERROR); return false; } - SE_TRACE_DEBUG("\n"); - - // append 2_0 metadata - memcpy_s(metadata2, metadata->size, metadata, metadata->size); - //if elrange is set, we can remove this metadata - if(parameter[ELRANGESIZE].value == 0) - { - metadata2->version = META_DATA_MAKE_VERSION(SGX_2_0_MAJOR_VERSION,SGX_2_0_MINOR_VERSION); - if (!append_compatible_metadata(metadata2, metadata)) + + if (memcpy_s(metadata2, metadata->size, metadata, metadata->size)) { + se_trace(SE_TRACE_ERROR, "%s: Error memcpy_s failed\n", __FUNCTION__); + free(metadata2); + return false; + } + +#if 0 + if (!meta_sgx1_only) { + // append 2_0 metadata + // if elrange is set, we can remove this metadata + if(parameter[ELRANGESIZE].value == 0) { - free(metadata2); - return false; + metadata2->version = META_DATA_MAKE_VERSION(SGX_2_0_MAJOR_VERSION,SGX_2_0_MINOR_VERSION); + if (!append_compatible_metadata(metadata2, metadata)) + { + free(metadata2); + return false; + } } } +#endif // append 1_9 metadata if(parameter[ELRANGESIZE].value != 0) @@ -1157,7 +1198,7 @@ static bool generate_compatible_metadata(metadata_t *metadata, const xml_paramet { se_trace(SE_TRACE_DEBUG, "%s: Utility thread TD is the last layout\n", __FUNCTION__); metadata_cleanup(metadata2, 0); - ret = append_compatible_metadata(metadata2, metadata); + ret = handle_compatible_metadata(metadata2, metadata, append); free(metadata2); return ret; } @@ -1176,7 +1217,7 @@ static bool generate_compatible_metadata(metadata_t *metadata, const xml_paramet max_rsrv_entry->entry.si_flags = SI_FLAG_NONE; max_rsrv_entry->entry.attributes &= (uint16_t)(~PAGE_ATTR_POST_ADD); } - ret = append_compatible_metadata(metadata2, metadata); + ret = handle_compatible_metadata(metadata2, metadata, append); free(metadata2); return ret; } @@ -1204,7 +1245,7 @@ static bool generate_compatible_metadata(metadata_t *metadata, const xml_paramet if (false == ret) goto end; } - ret = append_compatible_metadata(metadata2, metadata); + ret = handle_compatible_metadata(metadata2, metadata, append); if (false == ret) goto end; ret = dump_metadata_layout(metadata); @@ -1306,7 +1347,8 @@ int main(int argc, char* argv[]) {"EnclaveImageAddress", 0xFFFFFFFFFFFFFFFF, 0x1000, 0, 0}, {"ELRangeStartAddress", 0xFFFFFFFFFFFFFFFF, 0, 0, 0}, {"ELRangeSize", 0xFFFFFFFFFFFFFFFF, 0x1000, 0, 0}, - {"PKRU", FEATURE_LOADER_SELECTS, FEATURE_MUST_BE_DISABLED, FEATURE_MUST_BE_DISABLED, 0}}; + {"PKRU", FEATURE_LOADER_SELECTS, FEATURE_MUST_BE_DISABLED, FEATURE_MUST_BE_DISABLED, 0}, + {"UserRegionSize", ENCLAVE_MAX_SIZE_64/2, 0, USER_REGION_SIZE, 0}}; const char *path[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; uint8_t enclave_hash[SGX_HASH_SIZE] = {0}; uint8_t metadata_raw[METADATA_SIZE]; @@ -1318,7 +1360,7 @@ int main(int argc, char* argv[]) uint32_t option_flag_bits = 0; RSA *rsa = NULL; memset(&metadata_raw, 0, sizeof(metadata_raw)); - + uint8_t meta_versions = 0; #if OPENSSL_VERSION_NUMBER < 0x10100000L OpenSSL_add_all_algorithms(); @@ -1369,7 +1411,7 @@ int main(int argc, char* argv[]) goto clear_return; } - if(measure_enclave(enclave_hash, path[OUTPUT], parameter, option_flag_bits, metadata, &meta_offset) == false) + if(measure_enclave(enclave_hash, path[OUTPUT], parameter, option_flag_bits, metadata, &meta_offset, &meta_versions) == false) { se_trace(SE_TRACE_ERROR, OVERALL_ERROR); goto clear_return; @@ -1388,7 +1430,7 @@ int main(int argc, char* argv[]) se_trace(SE_TRACE_ERROR, OVERALL_ERROR); goto clear_return; } - if(false == generate_compatible_metadata(metadata, parameter)) + if(false == generate_compatible_metadata(metadata, parameter, meta_versions)) { se_trace(SE_TRACE_ERROR, OVERALL_ERROR); goto clear_return; diff --git a/sdk/sign_tool/SignTool/util_st.h b/sdk/sign_tool/SignTool/util_st.h index 8dbe1db28..98b5c1f41 100644 --- a/sdk/sign_tool/SignTool/util_st.h +++ b/sdk/sign_tool/SignTool/util_st.h @@ -140,6 +140,7 @@ #define SET_RSRV_SIZE_INIT_MIN_ERROR "Reserved memory size setting is not correct: min value should not be larger than init value.\n" #define SET_RSRV_SIZE_MAX_MIN_ERROR "Reserved memory size setting is not correct: max value should not be smaller than min value.\n" #define SET_RSRV_EXECUTABLE_ERROR "Reserved memory executable setting is not correct: the executable value should be set to 1 or 0.\n" +#define SET_USER_REGION_SIZE_ALIGN_ERROR "User region size setting is not correct: size is not page aligned.\n" #define SET_HW_LE_ERROR "Conflicting setting between the 'HW' and 'LaunchKey'.\n" #define SET_TCS_MAX_NUM_ERROR "Maximum number of TCS is not correct.\n" #define SET_TCS_MIN_POOL_ERROR "Minimum number of TCS Pool is not correct.\n" diff --git a/sdk/simulation/tinst/t_instructions.cpp b/sdk/simulation/tinst/t_instructions.cpp index 85846a128..ede1e389b 100644 --- a/sdk/simulation/tinst/t_instructions.cpp +++ b/sdk/simulation/tinst/t_instructions.cpp @@ -281,6 +281,28 @@ static void _EREPORT(const sgx_target_info_t* ti, const sgx_report_data_t* rd, s } //////////////////////////////////////////////////////////////////////// +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 + + +static void arch_prctl(int code, unsigned long addr) __attribute__((section(".nipx"))); +static void arch_prctl(int code, unsigned long addr) +{ + int ret; + + __asm__("mov %1, %%edi\n\t" + "movq %2, %%rsi\n\t" + "mov $0x9e,%%eax\n\t" + "syscall\n\t" + "mov %%eax, %0\n\t" + :"=a"(ret) + :"r"(code), "r"(addr) + :"r11", "rcx"); + if(ret != 0) { + // This should never happen. + abort(); + } +} static void _EEXIT(uintptr_t dest, uintptr_t xcx, uintptr_t xdx, uintptr_t xsi, uintptr_t xdi) __attribute__((section(".nipx"))); @@ -301,16 +323,11 @@ _EEXIT(uintptr_t dest, uintptr_t xcx, uintptr_t xdx, uintptr_t xsi, uintptr_t xd tcs_t *tcs = GET_TCS_PTR(xdx); GP_ON(tcs == NULL); - // restore the used _tls_array - GP_ON(td_mngr_restore_td(tcs) == false); - - // check thread is in use or not tcs_sim_t *tcs_sim = reinterpret_cast(tcs->reserved); + // Update the tcs status size_t tcs_target_state = TCS_STATE_INACTIVE; - size_t tcs_current_state = TCS_STATE_INACTIVE; - __atomic_exchange(&tcs_sim->tcs_state, &tcs_target_state, &tcs_current_state, __ATOMIC_RELAXED); - GP_ON(tcs_current_state!= TCS_STATE_ACTIVE); + __atomic_store(&tcs_sim->tcs_state, &tcs_target_state, __ATOMIC_RELAXED); regs.xax = 0; regs.xbx = dest; @@ -318,6 +335,10 @@ _EEXIT(uintptr_t dest, uintptr_t xcx, uintptr_t xdx, uintptr_t xsi, uintptr_t xd regs.xsi = xsi; regs.xdi = xdi; + //restore the FS, GS base address + arch_prctl(ARCH_SET_FS, tcs_sim->saved_fs_base); + arch_prctl(ARCH_SET_GS, tcs_sim->saved_gs_base); + load_regs(®s); // jump back to the instruction after the call to _SE3 diff --git a/sdk/simulation/trtssim/linux/Makefile b/sdk/simulation/trtssim/linux/Makefile index 7a0a9bf52..cb32c4da6 100644 --- a/sdk/simulation/trtssim/linux/Makefile +++ b/sdk/simulation/trtssim/linux/Makefile @@ -62,14 +62,20 @@ TRTS1_OBJS := init_enclave.o \ trts.o \ trts_ecall.o \ trts_ocall.o \ + ema_init.o \ trts_util.o \ trts_veh.o \ trts_xsave.o \ init_optimized_lib.o \ - trts_emodpr.o \ - trts_add_trim.o + trts_interrupt.o \ + trts_version.o \ + trts_add_trim.o \ + TRTS2_OBJS := trts_nsp.o -TRTS_OBJS := $(TRTS1_OBJS) $(TRTS2_OBJS) +TRTS3_OBJS := ema_rt.o + +TRTS_OBJS := $(TRTS1_OBJS) $(TRTS2_OBJS) $(TRTS3_OBJS) + TINST_OBJS := t_instructions.o \ deriv.o @@ -92,6 +98,9 @@ TLDR_OBJS := $(TLDR_ASM_OBJS) $(TLDR_C_OBJS) LIBTRTS := libsgx_trts_sim.a +LIBSGX_MM_PATH = $(LINUX_EXTERNAL_DIR)/sgx-emm +LIBSGX_MM = libsgx_mm.a + vpath %.cpp $(TRTS_DIR):$(TINST_DIR) vpath %.S $(LOWLIB_DIR):$(TLDR_DIR):$(XSAVE_DIR) vpath %.c $(TLS_DIR):$(TLDR_DIR) @@ -101,8 +110,15 @@ vpath %.c $(TLS_DIR):$(TLDR_DIR) all: $(LIBTRTS) | $(BUILD_DIR) $(CP) $< $| -$(LIBTRTS): $(TRTS_OBJS) $(TINST_OBJS) $(LOWLIB_OBJS) $(TLS_OBJS) $(TLDR_OBJS) +$(LIBTRTS): $(TRTS_OBJS) $(TINST_OBJS) $(LOWLIB_OBJS) $(TLS_OBJS) $(TLDR_OBJS) $(LIBSGX_MM) $(AR) rcsD $@ $(TRTS_OBJS) $(TINST_OBJS) $(LOWLIB_OBJS) $(TLS_OBJS) $(TLDR_OBJS) + $(MKDIR) $(BUILD_DIR)/.libsgx_mm + $(RM) $(BUILD_DIR)/.libsgx_mm/* && cd $(BUILD_DIR)/.libsgx_mm && $(AR) x $(LIBSGX_MM_PATH)/libsgx_mm.a + $(AR) rsD $@ $(BUILD_DIR)/.libsgx_mm/*.o + @$(RM) -rf $(BUILD_DIR)/.libsgx_mm + +$(LIBSGX_MM): + $(MAKE) -C $(LIBSGX_MM_PATH) # ------------------------------------------------------------ $(TRTS1_OBJS): CPPFLAGS += -I$(COMMON_DIR)/inc/tlibc \ @@ -110,6 +126,9 @@ $(TRTS1_OBJS): CPPFLAGS += -I$(COMMON_DIR)/inc/tlibc \ $(TRTS2_OBJS): %.o:%.cpp $(CXX) -c $(filter-out -fstack-protector-strong, $(CXXFLAGS)) -I$(SIM_DIR)/tinst/ $(CPPFLAGS) $< -o $@ +$(TRTS3_OBJS): %.o:../%.c + $(CC) -c $(TCFLAGS) $(CFLAGS) -I$(COMMON_DIR)/inc -I$(COMMON_DIR)/inc/internal -I$(COMMON_DIR)/inc/internal/linux -I$(COMMON_DIR)/inc/tlibc -I$(SIM_DIR)/tinst/ -fPIC $< -o $@ + # Explicitly disable optimization for tRTS simulation library, # since the '_SE3' function has assumptions on stack layout. diff --git a/sdk/simulation/uinst/td_mngr.h b/sdk/simulation/uinst/td_mngr.h index 47e082edd..7001ad397 100644 --- a/sdk/simulation/uinst/td_mngr.h +++ b/sdk/simulation/uinst/td_mngr.h @@ -43,6 +43,8 @@ typedef struct _tcs_sim_t size_t tcs_state; uintptr_t saved_dtv; uintptr_t saved_fs_gs_0; + uintptr_t saved_fs_base; + uintptr_t saved_gs_base; uint64_t tcs_offset_update_flag; } tcs_sim_t; diff --git a/sdk/simulation/uinst/u_instructions.cpp b/sdk/simulation/uinst/u_instructions.cpp index 3532a5dbe..8ea8a2336 100644 --- a/sdk/simulation/uinst/u_instructions.cpp +++ b/sdk/simulation/uinst/u_instructions.cpp @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include "arch.h" @@ -59,7 +61,7 @@ static uintptr_t _EINIT(secs_t* secs, enclave_css_t* css, token_t* launch); static uintptr_t _ECREATE (page_info_t* pi); static uintptr_t _EADD (page_info_t* pi, void* epc_lin_addr); static uintptr_t _EREMOVE(const void* epc_lin_addr); -extern "C" void* get_td_addr(void); +extern "C" int arch_prctl(int code, unsigned long addr); extern "C" bool get_elrange_start_address(void* base_address, uint64_t &elrange_start_address); @@ -103,7 +105,6 @@ void call_old_handler(int signum, void* siginfo, void *priv) sigset_t cur_set; pthread_sigmask(SIG_SETMASK, &g_old_sigact[signum].sa_mask, &cur_set); - if(g_old_sigact[signum].sa_flags & SA_SIGINFO) { @@ -120,13 +121,14 @@ void call_old_handler(int signum, void* siginfo, void *priv) g_old_sigact[signum].sa_handler = SIG_DFL; } } - +#define SIGRT_INTERRUPT (64) void sig_handler_sim(int signum, siginfo_t *siginfo, void *priv) __attribute__((optimize(0))) __attribute__((optimize("no-stack-protector"))); void sig_handler_sim(int signum, siginfo_t *siginfo, void *priv) { - GP_ON(signum != SIGFPE && signum != SIGSEGV); + GP_ON(signum != SIGFPE && signum != SIGSEGV && signum != SIGRT_INTERRUPT); - thread_data_t *thread_data = (thread_data_t*)get_td_addr(); + thread_data_t *thread_data = 0; + arch_prctl(ARCH_GET_GS, (unsigned long)&thread_data); if (thread_data != NULL && (uintptr_t)thread_data == (uintptr_t)thread_data->self_addr) { // first SSA can be used to get tcs, even cssa > 0. @@ -137,13 +139,27 @@ void sig_handler_sim(int signum, siginfo_t *siginfo, void *priv) { tcs_sim_t *tcs_sim = reinterpret_cast(tcs->reserved); - size_t tcs_current_state = TCS_STATE_ACTIVE; - __atomic_load(&tcs_sim->tcs_state, &tcs_current_state, __ATOMIC_RELAXED); + size_t tcs_target_state = TCS_STATE_INACTIVE; + size_t tcs_current_state = TCS_STATE_INACTIVE; + __atomic_exchange(&tcs_sim->tcs_state, &tcs_target_state, &tcs_current_state, __ATOMIC_RELAXED); if (tcs_current_state == TCS_STATE_ACTIVE) { - size_t tcs_target_state = TCS_STATE_INACTIVE; - __atomic_store(&tcs_sim->tcs_state, &tcs_target_state, __ATOMIC_RELAXED); + // save FS, GS base address + bool user_interrupt = false; + uint64_t tmp_fs_base = 0, tmp_gs_base = 0; + arch_prctl(ARCH_GET_FS, (unsigned long)&tmp_fs_base); + arch_prctl(ARCH_GET_GS, (unsigned long)&tmp_gs_base); + + // Workaround for Occlum. Occlum only handle user application exception + // the fs_base is used by application which is not same as the gs_base used by Occlum + if (tmp_fs_base == tmp_gs_base) { + return; + } + + // restore FS, GS base address + arch_prctl(ARCH_SET_FS, tcs_sim->saved_fs_base); + arch_prctl(ARCH_SET_GS, tcs_sim->saved_gs_base); CEnclaveMngr *mngr = CEnclaveMngr::get_instance(); assert(mngr != NULL); @@ -154,8 +170,11 @@ void sig_handler_sim(int signum, siginfo_t *siginfo, void *priv) ucontext_t* context = reinterpret_cast(priv); size_t xip = context->uc_mcontext.gregs[REG_RIP]; secs_t *secs = ce->get_secs(); - if (secs && (xip >= (size_t)secs->base) && (xip < (size_t)secs->base + secs->size)) - { + + //Workaround for Occlum. Occlum only handle user application exception + if (secs && (xip >= (size_t)tcs) && (xip < (size_t)secs->base + secs->size)) + { + user_interrupt = true; GP_ON(tcs->cssa >= tcs->nssa); p_ssa_gpr = (ssa_gpr_t*)((size_t)p_ssa_gpr + tcs->cssa * secs->ssa_frame_size * SE_PAGE_SIZE); p_ssa_gpr->REG(ax) = context->uc_mcontext.gregs[REG_RAX]; @@ -175,7 +194,9 @@ void sig_handler_sim(int signum, siginfo_t *siginfo, void *priv) p_ssa_gpr->r13 = context->uc_mcontext.gregs[REG_R13]; p_ssa_gpr->r14 = context->uc_mcontext.gregs[REG_R14]; p_ssa_gpr->r15 = context->uc_mcontext.gregs[REG_R15]; - p_ssa_gpr->rflags = context->uc_flags; + p_ssa_gpr->rflags = context->uc_mcontext.gregs[REG_EFL]; + p_ssa_gpr->fs = tmp_fs_base; + p_ssa_gpr->gs = tmp_gs_base; context->uc_mcontext.gregs[REG_RAX] = SE_ERESUME; context->uc_mcontext.gregs[REG_RBX] = (size_t)tcs; @@ -203,21 +224,34 @@ void sig_handler_sim(int signum, siginfo_t *siginfo, void *priv) p_ssa_gpr->exit_info.vector = 0; //#DE } else - { + { p_ssa_gpr->exit_info.valid = 0; } tcs->cssa +=1; } - } - } + } + + if (user_interrupt == false) { + // restore FS, GS base address + arch_prctl(ARCH_SET_FS, tmp_fs_base); + arch_prctl(ARCH_SET_GS, tmp_gs_base); + } + } } } call_old_handler(signum, siginfo, priv); } #define SIG_STACK_SIZE (4096*10) +#include +std::atomic sig_handler_registed (false); void reg_sig_handler_sim() { + if (sig_handler_registed) + return; + + SE_TRACE(SE_TRACE_DEBUG, "signal hander for simulation registed\n"); + int ret = 0; struct sigaction sig_act; stack_t ss; @@ -240,10 +274,19 @@ void reg_sig_handler_sim() sigdelset(&sig_act.sa_mask, SIGSEGV); sigdelset(&sig_act.sa_mask, SIGFPE); } + + sigdelset(&sig_act.sa_mask, SIGRT_INTERRUPT); + ret = sigaction(SIGSEGV, &sig_act, &g_old_sigact[SIGSEGV]); if (0 != ret) abort(); ret = sigaction(SIGFPE, &sig_act, &g_old_sigact[SIGFPE]); if (0 != ret) abort(); + + ret = sigaction(SIGRT_INTERRUPT, &sig_act, &g_old_sigact[SIGRT_INTERRUPT]); + if (0 != ret) + abort(); + + sig_handler_registed = true; } uintptr_t _EINIT(secs_t* secs, enclave_css_t *css, token_t *launch) @@ -276,6 +319,8 @@ uintptr_t _EINIT(secs_t* secs, enclave_css_t *css, token_t *launch) return SGX_ERROR_INVALID_ATTRIBUTE; } + reg_sig_handler_sim(); + mcp_same_size(&this_secs->mr_enclave, &css->body.enclave_hash, sizeof(sgx_measurement_t)); this_secs->isv_prod_id = css->body.isv_prod_id; this_secs->isv_svn = css->body.isv_svn; @@ -338,16 +383,13 @@ uintptr_t _ECREATE(page_info_t* pi) // `ce' is not checked against NULL, since it is not // allocated with new(std::no_throw). - addr = mmap(secs->base, (size_t)secs->size, PROT_READ | PROT_WRITE, mmap_flag, -1, 0); + addr = mmap(secs->base, (size_t)secs->size, SGX_PROT_NONE, mmap_flag, -1, 0); if(MAP_FAILED == addr) { delete ce; return 0; } - // Mark all the memory inaccessible. - se_virtual_protect(addr, (size_t)secs->size, SGX_PROT_NONE); - //set image_offset if(image_offset != 0) { @@ -471,8 +513,9 @@ void _SE3(uintptr_t xax, uintptr_t xbx, xip = reinterpret_cast(enclave_base_addr); GP_ON_EENTER(xip == 0); - //set the _tls_array to point to the self_addr of TLS section inside the enclave - GP_ON_EENTER(td_mngr_set_td(enclave_base_addr, tcs) == false); + // save FS, GS base address + arch_prctl(ARCH_GET_FS, (unsigned long)&tcs_sim->saved_fs_base); + arch_prctl(ARCH_GET_GS, (unsigned long)&tcs_sim->saved_gs_base); // Destination depends on STATE xip += (uintptr_t)tcs->oentry; @@ -496,6 +539,10 @@ void _SE3(uintptr_t xax, uintptr_t xbx, regs.xsp = p_ssa_gpr->REG(sp_u); regs.xip = xip; + // adjust the FS, GS base address + arch_prctl(ARCH_SET_FS, (unsigned long)enclave_base_addr + tcs->ofs_base); + arch_prctl(ARCH_SET_GS, (unsigned long)enclave_base_addr + tcs->ogs_base); + load_regs(®s); // Returning from this function enters the enclave @@ -523,8 +570,7 @@ void _SE3(uintptr_t xax, uintptr_t xbx, __atomic_exchange(&tcs_sim->tcs_state, &tcs_target_state, &tcs_current_state, __ATOMIC_RELAXED); GP_ON_EENTER(tcs_current_state != TCS_STATE_INACTIVE); - - tcs->cssa -=1; + tcs->cssa -=1; secs = ce->get_secs(); enclave_base_addr = secs->base; @@ -545,6 +591,10 @@ void _SE3(uintptr_t xax, uintptr_t xbx, regs.xbp = p_ssa_gpr->REG(bp); regs.xip = p_ssa_gpr->REG(ip); + // adjust the FS, GS base address + arch_prctl(ARCH_SET_FS, p_ssa_gpr->fs); + arch_prctl(ARCH_SET_GS, p_ssa_gpr->gs); + load_regs(®s); return; diff --git a/sdk/simulation/urtssim/enclave_creator_sim.cpp b/sdk/simulation/urtssim/enclave_creator_sim.cpp index f1da35951..233f63a9f 100644 --- a/sdk/simulation/urtssim/enclave_creator_sim.cpp +++ b/sdk/simulation/urtssim/enclave_creator_sim.cpp @@ -46,7 +46,7 @@ #include #include "sgx_enclave_common.h" #include - +#include #include #include #include @@ -309,6 +309,13 @@ bool EnclaveCreatorSim::get_plat_cap(sgx_misc_attribute_t *se_attr) return false; } +int EnclaveCreatorSim::alloc(uint64_t addr, uint64_t size, int flag) +{ + int ret = mprotect((void*)addr, size, flag); + if (ret) return errno; + return ret; +} + int EnclaveCreatorSim::emodpr(uint64_t addr, uint64_t size, uint64_t flag) { UNUSED(addr); diff --git a/sdk/simulation/urtssim/enclave_creator_sim.h b/sdk/simulation/urtssim/enclave_creator_sim.h index 8896d452c..47a75fc43 100644 --- a/sdk/simulation/urtssim/enclave_creator_sim.h +++ b/sdk/simulation/urtssim/enclave_creator_sim.h @@ -56,6 +56,7 @@ class EnclaveCreatorSim : public EnclaveCreator int trim_range(uint64_t fromaddr, uint64_t toaddr); int trim_accept(uint64_t addr); int remove_range(uint64_t fromaddr, uint64_t numpages); + int alloc(uint64_t addr, uint64_t size, int flag); private: bool m_sig_registered; }; diff --git a/sdk/simulation/urtssim/linux/Makefile b/sdk/simulation/urtssim/linux/Makefile index f2be8b340..77ea7e1b3 100644 --- a/sdk/simulation/urtssim/linux/Makefile +++ b/sdk/simulation/urtssim/linux/Makefile @@ -87,6 +87,7 @@ OBJ2 := urts.o \ sig_handler.o \ debugger_support.o \ get_thread_id.o \ + urts_emm.o \ urts_trim.o \ urts_emodpr.o @@ -120,6 +121,8 @@ vpath %.c .:$(DIR6) LDFLAGS += $(COMMON_LDFLAGS) -Wl,--version-script=$(LINUX_PSW_DIR)/urts/linux/urts.lds LIBURTSSIM_SHARED := libsgx_urts_sim.so +LIBURTSSIM_STATIC := libsgx_urts_sim.a +LIBURTSSIM_STATIC_WITH_EVENT := libsgx_urts_sim_with_se_event.a LIBURTSSIM_DEBUG := libsgx_urts_sim.so.debug LIBURTS_DEPLOY := libsgx_urts_deploy.so @@ -127,8 +130,10 @@ LDLIBS += -lwrapper -lcrypto -Wl,-Bdynamic -Wl,-Bsymbolic -lsgx_uae_service_sim SONAME = $(LIBURTSSIM_SHARED) .PHONY: all -all: $(LIBURTSSIM_SHARED) $(LIBURTSSIM_DEBUG) $(LIBURTS_DEPLOY)| $(BUILD_DIR) +all: $(LIBURTSSIM_SHARED) $(LIBURTSSIM_STATIC) $(LIBURTSSIM_STATIC_WITH_EVENT) $(LIBURTSSIM_DEBUG) $(LIBURTS_DEPLOY)| $(BUILD_DIR) $(CP) $(LIBURTSSIM_SHARED) $| + $(CP) $(LIBURTSSIM_STATIC) $| + $(CP) $(LIBURTSSIM_STATIC_WITH_EVENT) $| $(CP) $(LIBURTS_DEPLOY) $| ifndef DEBUG $(CP) $(LIBURTSSIM_DEBUG) $| @@ -137,6 +142,23 @@ endif $(LIBURTSSIM_SHARED): simasm uinst driver_api wrapper uae_service_sim $(OBJ) $(OBJ6) ittnotify $(CXX) $(CXXFLAGS) -shared -Wl,-soname=$(SONAME) $(OBJ) $(OBJ6) $(LDFLAGS) $(LDLIBS) -o $@ +$(LIBURTSSIM_STATIC): $(LIBURTSSIM_SHARED) + @$(MKDIR) $(BUILD_DIR)/.sgx_static_urts + @$(RM) -f $(BUILD_DIR)/.sgx_static_urts/* + cd $(BUILD_DIR)/.sgx_static_urts && \ + $(AR) x $(COMMON_DIR)/se_wrapper/libwrapper.a && \ + $(AR) x $(VTUNE_DIR)/sdk/src/ittnotify/libittnotify.a && \ + $(RM) -f se_event.o + $(AR) rsD $@ $(OBJ) $(OBJ6) $(BUILD_DIR)/.sgx_static_urts/*.o + +$(LIBURTSSIM_STATIC_WITH_EVENT): $(LIBURTSSIM_SHARED) + @$(MKDIR) $(BUILD_DIR)/.sgx_static_urts + @$(RM) -f $(BUILD_DIR)/.sgx_static_urts/* + cd $(BUILD_DIR)/.sgx_static_urts && \ + $(AR) x $(COMMON_DIR)/se_wrapper/libwrapper.a && \ + $(AR) x $(VTUNE_DIR)/sdk/src/ittnotify/libittnotify.a + $(AR) rsD $@ $(OBJ) $(OBJ6) $(BUILD_DIR)/.sgx_static_urts/*.o + $(LIBURTSSIM_DEBUG): $(LIBURTSSIM_SHARED) ifndef DEBUG $(CP) $(LIBURTSSIM_SHARED) $(LIBURTSSIM_SHARED).orig @@ -185,7 +207,7 @@ $(LIBURTS_DEPLOY):../urts_deploy.c .PHONY: clean clean:: - @$(RM) *.o $(LIBURTSSIM_SHARED) $(LIBURTS_DEPLOY) $(LIBURTSSIM_DEBUG) $(LIBURTSSIM_SHARED).orig + @$(RM) *.o $(LIBURTSSIM_SHARED) $(LIBURTSSIM_STATIC) $(LIBURTSSIM_STATIC_WITH_EVENT) $(LIBURTS_DEPLOY) $(LIBURTSSIM_DEBUG) $(LIBURTSSIM_SHARED).orig @$(RM) $(BUILD_DIR)/$(LIBURTSSIM_SHARED) $(BUILD_DIR)/$(LIBURTS_DEPLOY) $(BUILD_DIR)/$(LIBURTSSIM_DEBUG) $(MAKE) -C $(COMMON_DIR)/se_wrapper clean $(MAKE) -C $(SIM_DIR)/driver_api/ clean diff --git a/sdk/simulation/urtssim/urts_deploy.c b/sdk/simulation/urtssim/urts_deploy.c index ac5f6223b..b9aa79fd4 100644 --- a/sdk/simulation/urtssim/urts_deploy.c +++ b/sdk/simulation/urtssim/urts_deploy.c @@ -70,6 +70,7 @@ void sgx_thread_set_multiple_untrusted_events_ocall(){}; void sgx_thread_set_untrusted_event_ocall(){}; void sgx_thread_setwait_untrusted_events_ocall(){}; void sgx_thread_wait_untrusted_event_ocall(){}; +void sgx_thread_wait_untrusted_event_timeout_ocall(){}; sgx_status_t pthread_create_ocall() { diff --git a/sdk/tlibc/gen/sbrk.c b/sdk/tlibc/gen/sbrk.c index e05a93fed..9dff9a637 100644 --- a/sdk/tlibc/gen/sbrk.c +++ b/sdk/tlibc/gen/sbrk.c @@ -78,7 +78,8 @@ void* sbrk(intptr_t n) size_t prev_heap_used = heap_used; void * start_addr; size_t size = 0; - + assert((heap_used & (SE_PAGE_SIZE - 1)) == 0); + if (!heap_base) return (void *)(~(size_t)0); @@ -113,7 +114,8 @@ void* sbrk(intptr_t n) start_addr = (void *)((size_t)(heap_base) + heap_min_size); size = prev_heap_used - heap_min_size; } - int ret = trim_EPC_pages(start_addr, size >> SE_PAGE_SHIFT); + assert((size & (SE_PAGE_SIZE - 1)) == 0); + int ret = mm_uncommit(start_addr, size); if (ret != 0) { heap_used = prev_heap_used; @@ -131,6 +133,8 @@ void* sbrk(intptr_t n) there's no integer overflow here. */ heap_ptr = (void *)((size_t)heap_base + (size_t)heap_used); + if(n==0) return heap_ptr; + heap_used += n; /* update g_peak_heap_used */ @@ -154,7 +158,8 @@ void* sbrk(intptr_t n) start_addr = (void *)((size_t)(heap_base) + heap_min_size); size = heap_used - heap_min_size; } - int ret = apply_EPC_pages(start_addr, size >> SE_PAGE_SHIFT); + assert((size & (SE_PAGE_SIZE - 1)) == 0); + int ret = mm_commit(start_addr, size); if (ret != 0) { heap_used = prev_heap_used; diff --git a/sdk/tlibthread/Makefile b/sdk/tlibthread/Makefile index a80af671a..5be4e9c1f 100755 --- a/sdk/tlibthread/Makefile +++ b/sdk/tlibthread/Makefile @@ -40,9 +40,11 @@ CPPFLAGS := -I$(COMMON_DIR)/inc/internal \ -I$(LINUX_PSW_DIR) OBJ := sethread_mutex.o \ + sethread_spinlock.o \ sethread_rwlock.o \ sethread_cond.o \ - sethread_utils.o + sethread_utils.o \ + sethread_self.o LIBTLIBTHREAD := libtlibthread.a diff --git a/sdk/tlibthread/sethread_self.cpp b/sdk/tlibthread/sethread_self.cpp new file mode 100644 index 000000000..165143a84 --- /dev/null +++ b/sdk/tlibthread/sethread_self.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sethread_internal.h" +#include "util.h" + +/* Occlum's notes: make TCS avaiable to Occlum */ +extern "C" const void* sgx_thread_get_self(void) { + sgx_thread_t self = (sgx_thread_t)get_thread_data(); + return TD2TCS(self); +} diff --git a/sdk/tlibthread/sethread_spinlock.cpp b/sdk/tlibthread/sethread_spinlock.cpp new file mode 100644 index 000000000..cc2744ae3 --- /dev/null +++ b/sdk/tlibthread/sethread_spinlock.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include +#include + +#include "util.h" +#include "sethread_internal.h" +#include "sethread_spinlock.h" +int sgx_thread_spin_init(sgx_thread_spinlock_t *mutex) +{ + CHECK_PARAMETER(mutex); + + mutex->m_refcount = 0; + mutex->m_owner = SGX_THREAD_T_NULL; + mutex->m_lock = SGX_SPINLOCK_INITIALIZER; + + return 0; +} + +int sgx_thread_spin_destroy(sgx_thread_spinlock_t *mutex) +{ + CHECK_PARAMETER(mutex); + + SPIN_LOCK(&mutex->m_lock); + if (mutex->m_owner != SGX_THREAD_T_NULL) { + SPIN_UNLOCK(&mutex->m_lock); + return EBUSY; + } + + mutex->m_refcount = 0; + SPIN_UNLOCK(&mutex->m_lock); + + return 0; +} + +int sgx_thread_spin_trylock(sgx_thread_spinlock_t *mutex) +{ + CHECK_PARAMETER(mutex); + + sgx_thread_t self = (sgx_thread_t)get_thread_data(); + + SPIN_LOCK(&mutex->m_lock); + + if (mutex->m_owner == self) { + mutex->m_refcount++; + SPIN_UNLOCK(&mutex->m_lock); + return 0; + } + + if (mutex->m_owner == SGX_THREAD_T_NULL) { + mutex->m_owner = self; + mutex->m_refcount++; + SPIN_UNLOCK(&mutex->m_lock); + return 0; + } + + SPIN_UNLOCK(&mutex->m_lock); + return EBUSY; +} + +int sgx_thread_spin_unlock(sgx_thread_spinlock_t *mutex) +{ + CHECK_PARAMETER(mutex); + + sgx_thread_t self = (sgx_thread_t)get_thread_data(); + + SPIN_LOCK(&mutex->m_lock); + /* if the mutux is not locked by anyone */ + if(mutex->m_owner == SGX_THREAD_T_NULL) { + SPIN_UNLOCK(&mutex->m_lock); + return EPERM; + } + + /* if the mutex is locked by another thread */ + if (mutex->m_owner != self) { + SPIN_UNLOCK(&mutex->m_lock); + return EPERM; + } + + /* the mutex is locked by current thread */ + if (--mutex->m_refcount == 0) { + mutex->m_owner = SGX_THREAD_T_NULL; + } + + SPIN_UNLOCK(&mutex->m_lock); + return 0; +} diff --git a/sdk/tmm_rsrv/sgx_rsrv_mem.cpp b/sdk/tmm_rsrv/sgx_rsrv_mem.cpp index c69323b8f..5f8776f47 100644 --- a/sdk/tmm_rsrv/sgx_rsrv_mem.cpp +++ b/sdk/tmm_rsrv/sgx_rsrv_mem.cpp @@ -42,7 +42,7 @@ #include #include #include - +#include "emm_private.h" #define SGX_PAGE_NOACCESS 0x01 // - #define SGX_PAGE_READONLY 0x02 // R #define SGX_PAGE_READWRITE 0x04 // RW @@ -184,7 +184,7 @@ void * sgx_alloc_rsrv_mem_ex(void *desired_addr, size_t length) size = rsrv_mem_committed - rsrv_mem_min_size; } // EACCEPT the new pages - int ret = apply_EPC_pages(start_addr, size >> SE_PAGE_SHIFT); + int ret = mm_commit(start_addr, size); if(ret != 0) { rsrv_mem_committed = prev_rsrv_mem_committed; @@ -282,7 +282,6 @@ int sgx_free_rsrv_mem(void * addr, size_t length) #include "global_data.h" -#include "trts_emodpr.h" static sgx_status_t tprotect_internal(size_t start, size_t size, si_flags_t perms) { @@ -300,37 +299,12 @@ static sgx_status_t tprotect_internal(size_t start, size_t size, si_flags_t perm { return SGX_ERROR_UNEXPECTED; } - - // EMODPE/EACCEPT requires OS level R permission for the page. Therefore, - // If target permission is NONE, we should change the OS level permission to NONE after EACCEPT - // If original permission is NONE, we should change the OS level permission before EMODPE if(pr_needed || pe_needed) { - // Ocall to EMODPR if target perm is not RWX and mprotect() if target perm is not NONE - ret = change_permissions_ocall(start, size, perms, EDMM_MODPR); - if (ret != SGX_SUCCESS) - abort(); - } - si_flags_t sf = perms|SI_FLAG_PR|SI_FLAG_REG; - - if(pe_needed) - { - if(emodpe_pages((void *)start, size / SE_PAGE_SIZE, sf)) + int rc = mm_modify_permissions((void*)start, size, (int)perms); + if (rc != 0) abort(); } - if(pr_needed && ((perms & (SI_FLAG_W|SI_FLAG_X)) != (SI_FLAG_W|SI_FLAG_X))) - { - // If the target permission to set is RWX, no EMODPR, hence no EACCEPT. - if(accept_modified_pages((void *)start, size / SE_PAGE_SIZE, sf)) - abort(); - } - if( pr_needed && perms == SI_FLAG_NONE ) - { - // If the target permission is NONE, ocall to mprotect() to change the OS permission - ret = change_permissions_ocall(start, size, perms, EDMM_MPROTECT); - if (ret != SGX_SUCCESS) - abort(); - } return ret; } diff --git a/sdk/tmm_rsrv/sgx_rsrv_mem_init.cpp b/sdk/tmm_rsrv/sgx_rsrv_mem_init.cpp index cc030c352..ae4f32730 100644 --- a/sdk/tmm_rsrv/sgx_rsrv_mem_init.cpp +++ b/sdk/tmm_rsrv/sgx_rsrv_mem_init.cpp @@ -33,7 +33,6 @@ #include "sgx_error.h" #include "stdint.h" - void *rsrv_mem_base __attribute__((section(RELRO_SECTION_NAME))) = NULL; size_t rsrv_mem_size __attribute__((section(RELRO_SECTION_NAME))) = 0; size_t rsrv_mem_min_size __attribute__((section(RELRO_SECTION_NAME))) = 0; diff --git a/sdk/trts/Makefile b/sdk/trts/Makefile index b5b8453f9..8ff666615 100644 --- a/sdk/trts/Makefile +++ b/sdk/trts/Makefile @@ -48,18 +48,20 @@ OBJS1 := init_enclave.o \ trts.o \ trts_ecall.o \ trts_ocall.o \ + ema_init.o \ trts_util.o \ trts_veh.o \ trts_xsave.o \ init_optimized_lib.o \ trts_version.o \ - trts_trim.o \ - trts_emodpr.o \ + trts_interrupt.o \ trts_add_trim.o OBJS2 := trts_nsp.o -OBJS := $(OBJS1) $(OBJS2) +OBJS3 := ema_rt.o + +OBJS := $(OBJS1) $(OBJS2) $(OBJ3) all: $(OBJS) elf_parser @@ -70,6 +72,11 @@ $(OBJS1): %.o: %.cpp $(OBJS2): %.o: %.cpp $(CXX) -c $(TCXXFLAGS) $(CPPFLAGS) -fPIC $< -o $@ +$(OBJS3): %.o: %.c + $(CC) -c $(TCFLAGS) $(CFLAGS) -fPIC $< -o $@ + +.PHONY: elf_parser + .PHONY: elf_parser elf_parser: $(OBJS) $(MAKE) -C linux diff --git a/sdk/trts/ema_init.cpp b/sdk/trts/ema_init.cpp new file mode 100644 index 000000000..aca05f530 --- /dev/null +++ b/sdk/trts/ema_init.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "emm_private.h" +#include "metadata.h" +//#include "se_trace.h" +#include "util.h" +#include "se_page_attr.h" +#include "trts_internal.h" +#include "trts_util.h" + +#if 0 +void dump_layout_entry(layout_entry_t *entry) +{ + se_trace(SE_TRACE_DEBUG, "\t%s\n", __FUNCTION__); + se_trace(SE_TRACE_DEBUG, "\tEntry Id = %4u, %-16s, ", entry->id, + entry[entry->id & ~(GROUP_FLAG)]); + se_trace(SE_TRACE_DEBUG, "Page Count = %5u, ", entry->page_count); + se_trace(SE_TRACE_DEBUG, "Attributes = 0x%02X, ", entry->attributes); + se_trace(SE_TRACE_DEBUG, "Flags = 0x%016llX, ", entry->si_flags); + se_trace(SE_TRACE_DEBUG, "RVA = 0x%016llX -> ", entry->rva); +} + +void dump_layout_group(layout_t *layout) +{ + se_trace(SE_TRACE_DEBUG, "\tEntry Id(%2u) = %4u, %-16s, ", 0, + layout->entry.id, layout_id_str[layout->entry.id & ~(GROUP_FLAG)]); + se_trace(SE_TRACE_DEBUG, "Entry Count = %4u, ", layout->group.entry_count); + se_trace(SE_TRACE_DEBUG, "Load Times = %u, ", layout->group.load_times); + se_trace(SE_TRACE_DEBUG, "LStep = 0x%016llX\n", layout->group.load_step); +} +#endif + +static int build_rts_context_nodes(layout_entry_t *entry, uint64_t offset) +{ + uint64_t rva = offset + entry->rva; + assert(IS_PAGE_ALIGNED(rva)); + + size_t addr = (size_t)get_enclave_base() + rva; + size_t size = entry->page_count << SE_PAGE_SHIFT; + + // entry is guard page or has EREMOVE, build a reserved ema + if ((entry->si_flags == 0) || + (entry->attributes & PAGE_ATTR_EREMOVE)) { + int ret = mm_init_ema((void*)addr, + size, + SGX_EMA_RESERVE | SGX_EMA_SYSTEM, + SGX_EMA_PROT_NONE, + NULL, NULL); + if (ret) { + return SGX_ERROR_UNEXPECTED; + } + return SGX_SUCCESS; + } + bool post_remove = (entry->attributes & PAGE_ATTR_POST_REMOVE); + bool post_add = (entry->attributes & PAGE_ATTR_POST_ADD); + bool static_min = (entry->attributes & PAGE_ATTR_EADD) && (!post_remove); + + if(post_remove) + { + if( mm_init_ema((void*)addr, size, SGX_EMA_SYSTEM, + SGX_EMA_PROT_READ_WRITE, + NULL, NULL)) + return SGX_ERROR_UNEXPECTED; + if( 0 != mm_dealloc((void*)addr, size)) + return SGX_ERROR_UNEXPECTED; + //fall through for POST_ADD to realloc as COMMIT_ON_DEMAND + } + + if (post_add) { + // build commit-on-demand ema node + uint32_t commit_direction = SGX_EMA_GROWSUP; + uint32_t type = SGX_EMA_PAGE_TYPE_REG; + + if (entry->id == LAYOUT_ID_STACK_MAX || + entry->id == LAYOUT_ID_STACK_DYN_MAX || + entry->id == LAYOUT_ID_STACK_DYN_MIN) { + commit_direction = SGX_EMA_GROWSDOWN; + } + + int ret = mm_alloc((void*)addr, + ((size_t)entry->page_count) << SE_PAGE_SHIFT, + SGX_EMA_COMMIT_ON_DEMAND | commit_direction + | SGX_EMA_SYSTEM | SGX_EMA_FIXED | type, + NULL, NULL, NULL); + if (ret) { + return SGX_ERROR_UNEXPECTED; + } + + } else if (static_min) { + // build static ema node + int type = SGX_EMA_PAGE_TYPE_REG; + int prot = entry->si_flags & (SGX_EMA_PROT_MASK); + + if (entry->id == LAYOUT_ID_TCS) { + type = SGX_EMA_PAGE_TYPE_TCS; + prot = SGX_EMA_PROT_NONE; + } + int ret = mm_init_ema((void*)addr, + size, + SGX_EMA_SYSTEM | type, + prot, + NULL, + NULL); + if (ret) { + return SGX_ERROR_UNEXPECTED; + } + + } + return SGX_SUCCESS; +} + +static int init_rts_contexts_emas(layout_t *start, layout_t *end, uint64_t delta) +{ + int ret = SGX_ERROR_UNEXPECTED; + + for(layout_t *layout = start; layout < end; layout++) { + //se_trace(SE_TRACE_DEBUG, "%s, step = 0x%016llX\n", __FUNCTION__, delta); + + if (!IS_GROUP_ID(layout->group.id)) { + ret = build_rts_context_nodes(&layout->entry, delta); + if (ret != SGX_SUCCESS) { + return ret; + } + } else { + uint64_t step = 0; + for(uint32_t i = 0; i < layout->group.load_times; i++) { + step += layout->group.load_step; + ret = init_rts_contexts_emas(&layout[-layout->group.entry_count], + layout, step); + if (ret != SGX_SUCCESS) { + return ret; + } + } + } + } + return SGX_SUCCESS; +} + +extern "C" int init_segment_emas(void* enclave_base); + +extern "C" int init_rts_emas(size_t rts_base, layout_t *layout_start, layout_t *layout_end) +{ + int ret = SGX_ERROR_UNEXPECTED; + + ret = init_segment_emas((void *)rts_base); + if (SGX_SUCCESS != ret) { + return ret; + } + + ret = init_rts_contexts_emas(layout_start, layout_end, 0); + return ret; +} + diff --git a/sdk/trts/ema_rt.c b/sdk/trts/ema_rt.c new file mode 100644 index 000000000..e232f0947 --- /dev/null +++ b/sdk/trts/ema_rt.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "sethread_spinlock.h" +#include +#include +#include +#include "sgx_trts.h" // for sgx_ocalloc, sgx_is_outside_enclave +#include "arch.h" +#include "sgx_edger8r.h" // for sgx_ocall etc. +#include "internal/rts.h" +#include "sgx_mm_rt_abstraction.h" +#define OCALLOC(val, type, len) do { \ + void* __tmp = sgx_ocalloc(len); \ + if (__tmp == NULL) { \ + sgx_ocfree(); \ + return SGX_ERROR_UNEXPECTED;\ + } \ + (val) = (type)__tmp; \ +} while (0) + +typedef struct ms_emm_alloc_ocall_t { + int retval; + size_t addr; + size_t size; + int page_type; + int alloc_flags; +} ms_emm_alloc_ocall_t; + +int SGXAPI sgx_mm_alloc_ocall(size_t addr, size_t size, int page_type, int alloc_flags) +{ +#ifdef SE_SIM + (void)addr; + (void)size; + (void)page_type; + (void)alloc_flags; + return 0; +#else + int status = SGX_SUCCESS; + int ret = EFAULT; + ms_emm_alloc_ocall_t* ms; + OCALLOC(ms, ms_emm_alloc_ocall_t*, sizeof(*ms)); + + ms->addr = (size_t)addr; + ms->size = size; + ms->page_type = page_type; + ms->alloc_flags = alloc_flags; + + status = sgx_ocall((unsigned int)EDMM_ALLOC, ms); + if(status == SGX_SUCCESS && ms->retval == SGX_SUCCESS) + ret = 0; + + sgx_ocfree(); + return ret; +#endif +} + +typedef struct ms_emm_modify_ocall_t { + int retval; + size_t addr; + size_t size; + int flags_from; + int flags_to; +} ms_emm_modify_ocall_t; + +int SGXAPI sgx_mm_modify_ocall(size_t addr, size_t size, int flags_from, int flags_to) +{ +#ifdef SE_SIM + (void)addr; + (void)size; + (void)flags_from; + (void)flags_to; + return 0; +#else + int status = SGX_SUCCESS; + int ret = EFAULT; + ms_emm_modify_ocall_t* ms; + OCALLOC(ms, ms_emm_modify_ocall_t*, sizeof(*ms)); + + ms->addr = (size_t)addr; + ms->size = size; + ms->flags_from = flags_from; + ms->flags_to = flags_to; + status = sgx_ocall((unsigned int)EDMM_MODIFY, ms); + if(status == SGX_SUCCESS && ms->retval == SGX_SUCCESS) + ret = 0; + + sgx_ocfree(); + return ret; +#endif +} + +extern sgx_mm_pfhandler_t g_mm_pfhandler; + +bool sgx_mm_register_pfhandler(sgx_mm_pfhandler_t pfhandler) +{ + if (g_mm_pfhandler != NULL) + return false; + else + { + g_mm_pfhandler = pfhandler; + return true; + } +} + +bool sgx_mm_unregister_pfhandler(sgx_mm_pfhandler_t pfhandler) +{ + if (g_mm_pfhandler != pfhandler) + return false; + g_mm_pfhandler = NULL; + return true; +} + +typedef struct _sgx_mm_mutex { + sgx_thread_spinlock_t m; +}sgx_mm_mutex; + +static int sgx_mm_mutex_init(sgx_mm_mutex* mutex) +{ + //Recursive locks needed for cases when exception happens in + // mm_x_internal functions while lock being held. For example, + // stack expansion/heap expansion during those calls as we use + // regular enclave stack and heap for internal processing and + // book keeping. + mutex->m = (sgx_thread_spinlock_t)SGX_THREAD_RECURSIVE_SPINLOCK_INITIALIZER; + return 0; +} + +sgx_mm_mutex *sgx_mm_mutex_create() +{ + sgx_mm_mutex *mutex = (sgx_mm_mutex *)malloc(sizeof(sgx_mm_mutex)); + if (!mutex) { + return NULL; + } + sgx_mm_mutex_init(mutex); + return mutex; +} + +int sgx_mm_mutex_lock(sgx_mm_mutex* mutex) +{ + assert(mutex != NULL); + //Intel SDK does not have + // WAKE/WAIT event ocalls as builtins. And TCS + // pages are addred in a "utility" thread which + // does not have those in ocall table for the ecall. + // Additionally, stack expansion is done in 1st phase + // exception handler which does not support ocalls currently. + // Therefore we do not make ocalls for synchronization. + while ( sgx_thread_spin_trylock(&mutex->m)); + return 0; +} + +int sgx_mm_mutex_unlock(sgx_mm_mutex* mutex) +{ + assert(mutex != NULL); + return sgx_thread_spin_unlock(&mutex->m); +} + +int sgx_mm_mutex_destroy(sgx_mm_mutex* mutex) +{ + assert(mutex != NULL); + int ret = sgx_thread_spin_destroy(&mutex->m); + free(mutex); + return ret; +} + +bool sgx_mm_is_within_enclave(const void* addr, size_t size) +{ + return sgx_is_within_enclave(addr, size); +} diff --git a/sdk/trts/init_enclave.cpp b/sdk/trts/init_enclave.cpp index 8d303d483..7c7f4bd21 100644 --- a/sdk/trts/init_enclave.cpp +++ b/sdk/trts/init_enclave.cpp @@ -33,7 +33,7 @@ /** * File: init_enclave.cpp * Description: - * Initialize enclave by rebasing the image to the enclave base + * Initialize enclave by rebasing the image to the enclave base */ #include @@ -51,7 +51,7 @@ #include "se_memcpy.h" #include "se_cpu_feature.h" #include "se_version.h" - +#include "sgx_mm_rt_abstraction.h" // The global cpu feature bits from uRTS uint64_t g_cpu_feature_indicator __attribute__((section(RELRO_SECTION_NAME))) = 0; int EDMM_supported __attribute__((section(RELRO_SECTION_NAME))) = 0; @@ -77,7 +77,10 @@ extern sgx_status_t pcl_entry(void* enclave_base,void* ms) __attribute__((weak)) extern "C" int init_enclave(void *enclave_base, void *ms) __attribute__((section(".nipx"))); extern "C" int rsrv_mem_init(void *_rsrv_mem_base, size_t _rsrv_mem_size, size_t _rsrv_mem_min_size); - +extern "C" int init_rts_emas(size_t rts_base, layout_t *start, layout_t *end); +extern "C" int sgx_mm_init(size_t, size_t); +extern uintptr_t enclave_code_start_address; +extern size_t enclave_code_size; // init_enclave() // Initialize enclave. // Parameters: @@ -161,7 +164,7 @@ extern "C" int init_enclave(void *enclave_base, void *ms) { EDMM_supported = 0; } - else if (g_sdk_version >= SDK_VERSION_2_0) + else if (g_sdk_version >= SDK_VERSION_3_0) { EDMM_supported = feature_supported((const uint64_t *)sys_features.system_feature_set, 0); } @@ -169,7 +172,7 @@ extern "C" int init_enclave(void *enclave_base, void *ms) { return -1; } - + if (heap_init(get_heap_base(), get_heap_size(), get_heap_min_size(), EDMM_supported) != SGX_SUCCESS) return -1; @@ -200,7 +203,7 @@ extern "C" int init_enclave(void *enclave_base, void *ms) return -1; } } - else + else { if (0 != init_optimized_libs(cpu_features, NULL, xfrm)) { @@ -214,20 +217,16 @@ extern "C" int init_enclave(void *enclave_base, void *ms) return -1; } - + if(SGX_SUCCESS != sgx_read_rand((unsigned char*)&__stack_chk_guard, sizeof(__stack_chk_guard))) { return -1; } - return 0; + return get_first_executable_segment_info(enclave_base, &enclave_code_start_address, &enclave_code_size); } -#ifndef SE_SIM -int accept_post_remove(const volatile layout_t *layout_start, const volatile layout_t *layout_end, size_t offset); -#endif - extern size_t rsrv_mem_min_size; sgx_status_t do_init_enclave(void *ms, void *tcs) @@ -254,9 +253,6 @@ sgx_status_t do_init_enclave(void *ms, void *tcs) /* for EDMM, we need to accept the trimming of the POST_REMOVE pages. */ if (EDMM_supported) { - if (0 != accept_post_remove(&g_global_data.layout_table[0], &g_global_data.layout_table[0] + g_global_data.layout_entry_num, 0)) - return SGX_ERROR_UNEXPECTED; - size_t heap_min_size = get_heap_min_size(); memset_s(GET_PTR(void, enclave_base, g_global_data.heap_offset), heap_min_size, 0, heap_min_size); @@ -270,6 +266,39 @@ sgx_status_t do_init_enclave(void *ms, void *tcs) #endif g_enclave_state = ENCLAVE_INIT_DONE; + if (EDMM_supported) + { + size_t rts_base = g_enclave_base; + size_t user_base = 0; + size_t user_end = 0; + + layout_t *layout_start = (layout_t*)g_global_data.layout_table; + layout_t *layout_end = (layout_t*)(g_global_data.layout_table + g_global_data.layout_entry_num); + + // find potential user_region layout + layout_t *layout = layout_start; + for (;layout < layout_end; layout++) + if (layout->entry.id == LAYOUT_ID_USER_REGION) + break; + + // there exists user_region layout + if (layout != layout_end) + { + user_base = g_enclave_base + layout->entry.rva; + user_end = user_base + (((size_t)layout->entry.page_count) << SE_PAGE_SHIFT); + if(user_base > user_end) + return SGX_ERROR_UNEXPECTED; + + } + + if (sgx_mm_init(user_base, user_end)) + return SGX_ERROR_UNEXPECTED; + + int ret = init_rts_emas(rts_base, layout_start, layout); + if (ret != SGX_SUCCESS) { + return SGX_ERROR_UNEXPECTED; + } + } return SGX_SUCCESS; } diff --git a/sdk/trts/linux/Makefile b/sdk/trts/linux/Makefile index 3ce7b24ab..fcb56662d 100644 --- a/sdk/trts/linux/Makefile +++ b/sdk/trts/linux/Makefile @@ -46,10 +46,11 @@ CXXFLAGS += -Werror $(ENCLAVE_CXXFLAGS) \ TCFLAGS += -nostdinc \ -I$(COMMON_DIR)/inc/tlibc/ + LDCFLAGS := -shared -nostdlib -nodefaultlibs -nostartfiles CPP_SRCS := $(wildcard ../*.cpp) -C_SRCS := $(wildcard *.c) +C_SRCS := $(wildcard *.c) $(wildcard ../*.c) ASM_SRCS := $(wildcard *.S) \ $(COMMON_DIR)/src/linux/xsave_gnu.S OBJS := $(CPP_SRCS:.cpp=.o) @@ -58,13 +59,22 @@ OBJS += $(ASM_SRCS:.S=.o) OBJS := $(sort $(OBJS)) LIBTRTS = libsgx_trts.a +LIBSGX_MM_PATH = $(LINUX_EXTERNAL_DIR)/sgx-emm +LIBSGX_MM = libsgx_mm.a .PHONY: all all: $(LIBTRTS) | $(BUILD_DIR) $(CP) $(LIBTRTS) $| -$(LIBTRTS): $(OBJS) +$(LIBSGX_MM): + $(MAKE) -C $(LIBSGX_MM_PATH) + +$(LIBTRTS): $(OBJS) $(LIBSGX_MM) $(AR) rsD $@ $(OBJS) + $(MKDIR) $(BUILD_DIR)/.libsgx_mm + $(RM) $(BUILD_DIR)/.libsgx_mm/* && cd $(BUILD_DIR)/.libsgx_mm && $(AR) x $(LIBSGX_MM_PATH)/libsgx_mm.a + $(AR) rsD $@ $(BUILD_DIR)/.libsgx_mm/*.o + @$(RM) -rf $(BUILD_DIR)/.libsgx_mm %.o: %.S echo $(ASM_SRCS) @@ -82,7 +92,7 @@ $(BUILD_DIR): .PHONY: clean clean: @$(RM) $(OBJS) $(LIBTRTS) $(BUILD_DIR)/$(LIBTRTS) - + @$(MAKE) -C $(LIBSGX_MM_PATH) clean .PHONY: rebuild rebuild: $(MAKE) clean diff --git a/sdk/trts/linux/elf_parser.c b/sdk/trts/linux/elf_parser.c index 52769932d..b91463aab 100644 --- a/sdk/trts/linux/elf_parser.c +++ b/sdk/trts/linux/elf_parser.c @@ -39,9 +39,8 @@ #include "util.h" #include "elf_util.h" #include "global_data.h" -#include "../trts_emodpr.h" #include "trts_inst.h" - +#include "emm_private.h" static int elf_tls_aligned_virtual_size(const void *enclave_base, size_t *aligned_virtual_size); @@ -514,11 +513,11 @@ sgx_status_t change_protection(void *enclave_base) size_t end = (size_t)enclave_base + ((phdr->p_vaddr + phdr->p_memsz + SE_PAGE_SIZE - 1) & (size_t)(~(SE_PAGE_SIZE-1))); if (phdr->p_flags & PF_R) - perms |= SI_FLAG_R; + perms |= SGX_EMA_PROT_READ; if (phdr->p_flags & PF_X) - perms |= SI_FLAG_X; + perms |= SGX_EMA_PROT_EXEC; - if((status = trts_mprotect(start, end - start, perms)) != SGX_SUCCESS) + if(mm_modify_permissions((void*)start, end - start, (int)perms) != 0) return status; } @@ -527,7 +526,7 @@ sgx_status_t change_protection(void *enclave_base) size_t start = (size_t)enclave_base + (phdr->p_vaddr & (size_t)(~(SE_PAGE_SIZE-1))); size_t end = (size_t)enclave_base + ((phdr->p_vaddr + phdr->p_memsz + SE_PAGE_SIZE - 1) & (size_t)(~(SE_PAGE_SIZE-1))); if ((start != end) && - (status = trts_mprotect(start, end - start, SI_FLAG_R)) != SGX_SUCCESS) + mm_modify_permissions((void*)start, end - start, SGX_EMA_PROT_READ) != 0) return status; } } @@ -539,15 +538,74 @@ sgx_status_t change_protection(void *enclave_base) { if (g_global_data.layout_table[i].entry.id == LAYOUT_ID_RSRV_MIN && g_global_data.layout_table[i].entry.si_flags == SI_FLAGS_RWX && g_global_data.layout_table[i].entry.page_count > 0) { - if((status = trts_mprotect((size_t)((size_t)enclave_base + g_global_data.layout_table[i].entry.rva), - (size_t)g_global_data.layout_table[i].entry.page_count << SE_PAGE_SHIFT, - SI_FLAG_R|SI_FLAG_W)) != SGX_SUCCESS) + if(mm_modify_permissions((void*)((size_t)enclave_base + g_global_data.layout_table[i].entry.rva), + (size_t)g_global_data.layout_table[i].entry.page_count << SE_PAGE_SHIFT, + SGX_EMA_PROT_READ|SGX_EMA_PROT_WRITE) != 0) return status; break; } } - return SGX_SUCCESS; } +int init_segment_emas(void* enclave_base) +{ + + ElfW(Half) phnum = 0; + const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr)*)enclave_base; + const ElfW(Phdr) *phdr = get_phdr(ehdr); + uint64_t perms; + if (phdr == NULL) return -1; + int text_relocation = has_text_relo(ehdr, phdr, ehdr->e_phnum); + for (; phnum < ehdr->e_phnum; phnum++, phdr++) + { + if (phdr->p_type == PT_LOAD) + { + perms = SGX_EMA_PROT_READ; + size_t start = (size_t)enclave_base + (phdr->p_vaddr & (size_t)(~(SE_PAGE_SIZE-1))); + size_t end = (size_t)enclave_base + ((phdr->p_vaddr + phdr->p_memsz + SE_PAGE_SIZE - 1) & (size_t)(~(SE_PAGE_SIZE-1))); + + if (phdr->p_flags & PF_W || text_relocation) + perms |= SGX_EMA_PROT_WRITE; + if (phdr->p_flags & PF_X) + perms |= SGX_EMA_PROT_EXEC; + + if (mm_init_ema((void*)start, end - start, SGX_EMA_SYSTEM | SGX_EMA_PAGE_TYPE_REG, (int)perms, NULL, NULL) != 0) + return -1; + } + } + return 0; +} + +int get_first_executable_segment_info(const void *enclave_base, + uintptr_t *segment_start_addr, + size_t *segment_size) +{ + ElfW(Half) phnum = 0; + const ElfW(Ehdr) *ehdr = (const ElfW(Ehdr) *)enclave_base; + ElfW(Phdr) *phdr = get_phdr(ehdr); + int ret = -1; + + if (!segment_start_addr || !segment_size) + return ret; + + *segment_start_addr = 0; + *segment_size = 0; + + if (phdr == NULL) + return ret; /* Invalid image. */ + + for (; phnum < ehdr->e_phnum; phnum++, phdr++) + { + if (phdr->p_type == PT_LOAD && phdr->p_flags & PF_X) + { + *segment_start_addr = (size_t)enclave_base + phdr->p_vaddr; + *segment_size = phdr->p_memsz; + break; + } + } + + return 0; +} + /* vim: set ts=4 sw=4 et cin: */ diff --git a/sdk/trts/linux/elf_parser.h b/sdk/trts/linux/elf_parser.h index ae66935e7..9199f6cb3 100644 --- a/sdk/trts/linux/elf_parser.h +++ b/sdk/trts/linux/elf_parser.h @@ -55,6 +55,11 @@ int elf_get_init_array(const void* enclave_base, int elf_get_uninit_array(const void* enclave_base, uintptr_t *uninit_array_addr, size_t *uninit_array_size); + +int get_first_executable_segment_info(const void *enclave_base, + uintptr_t *segment_start_addr, + size_t *segment_size); + #ifdef __cplusplus } #endif diff --git a/sdk/trts/linux/trts_pic.S b/sdk/trts/linux/trts_pic.S index 92470a492..3236ca2cd 100644 --- a/sdk/trts/linux/trts_pic.S +++ b/sdk/trts/linux/trts_pic.S @@ -547,6 +547,14 @@ DECLARE_GLOBAL_FUNC do_eaccept jnz abort SE_EPILOG +DECLARE_GLOBAL_FUNC do_eacceptcopy + SE_PROLOG + mov $SE_EACCEPTCOPY, %eax + ENCLU + cmp $SGX_SUCCESS, %eax + jnz abort + SE_EPILOG + DECLARE_GLOBAL_FUNC do_emodpe SE_PROLOG mov $SE_EMODPE, %eax diff --git a/sdk/trts/linux/trts_pic.h b/sdk/trts/linux/trts_pic.h index 1f769bedc..550f4eeb0 100644 --- a/sdk/trts/linux/trts_pic.h +++ b/sdk/trts/linux/trts_pic.h @@ -79,34 +79,12 @@ /* OCALL command */ #define OCALL_FLAG 0x04F434944 -#define dtv SE_WORDSIZE -#define tls 0 .macro READ_TD_DATA offset -#ifdef SE_SIM -/* TLS support in simulation mode - * see "sdk/simulation/uinst/linux/set_tls.c" - * and "sdk/simulation/assembly/linux/gnu_tls.h" - * TD address (tcs->ofs_base) is set to tcb_head->dtv->value. - * The offset of tcb_head->dtv->value is SE_WORDSIZE. - */ - -#if defined(LINUX32) - mov %gs:dtv, %xax -#elif defined(LINUX64) - mov %fs:dtv, %xax -#endif - mov tls(%xax), %xax - mov \offset(%xax), %xax - -#else /* SE_SIM */ - #if defined(LINUX32) mov %fs:\offset, %xax #elif defined(LINUX64) mov %gs:\offset, %xax #endif - -#endif /* !SE_SIM */ .endm .macro GET_STACK_BASE tcs diff --git a/sdk/trts/trts_add_trim.cpp b/sdk/trts/trts_add_trim.cpp index 653c6e884..59e1e11a2 100644 --- a/sdk/trts/trts_add_trim.cpp +++ b/sdk/trts/trts_add_trim.cpp @@ -34,12 +34,13 @@ #include "sgx_utils.h" #include "trts_inst.h" #include "util.h" -#include "trts_trim.h" +#include "trts_emm.h" #include "trts_util.h" #include "global_data.h" #include "se_memcpy.h" #include "se_page_attr.h" #include "trts_internal.h" +#include "emm_private.h" #ifndef SE_SIM @@ -49,52 +50,6 @@ struct dynamic_flags_attributes uint16_t attributes; }; -// Low level API to EACCEPT pages on grow-up region. -static int sgx_accept_backward(si_flags_t sfl, size_t lo, size_t hi) -{ - size_t addr = hi; - SE_DECLSPEC_ALIGN(sizeof(sec_info_t)) sec_info_t si; - si.flags = sfl; - for (uint16_t i = 0; i < (sizeof(si.reserved)/sizeof(si.reserved[0])); i++) - si.reserved[i] = 0; - - while (lo < addr) - { - int rc = do_eaccept(&si, addr -= SE_PAGE_SIZE); - if (rc != 0) - abort(); - } - return 0; -} - -// Low level API to EACCEPT pages on grow-up region during exception handling. -static int sgx_accept_forward_within_exception(size_t lo, size_t hi) -{ - size_t addr = lo; - SE_DECLSPEC_ALIGN(sizeof(sec_info_t)) sec_info_t si; - -#ifdef DEBUG - unsigned int sp_value = 0; - asm("mov %%esp, %0;" : "=r" (sp_value) :); - if ((sp_value & (SE_PAGE_SIZE -1)) <= (SE_PAGE_SIZE - (STATIC_STACK_SIZE % SE_PAGE_SIZE))) - return SGX_ERROR_UNEXPECTED; -#endif - - si.flags = SI_FLAGS_RW | SI_FLAG_PENDING; - for (uint16_t i = 0; i < (sizeof(si.reserved)/sizeof(si.reserved[0])); i++) - si.reserved[i] = 0; - - while (addr < hi) - { - int rc = do_eaccept(&si, addr); - if (rc != 0) - abort(); - addr += SE_PAGE_SIZE; - } - - return 0; -} - const volatile layout_t *get_dynamic_layout_by_id(uint16_t id) { for(uint32_t i = 0; i < g_global_data.layout_entry_num; i++) @@ -107,34 +62,6 @@ const volatile layout_t *get_dynamic_layout_by_id(uint16_t id) return NULL; } -// EACCEPT trim requests when the enclave completes initialization. -int accept_post_remove(const volatile layout_t *layout_start, const volatile layout_t *layout_end, size_t offset) -{ - int ret = -1; - for (const volatile layout_t *layout = layout_start; layout < layout_end; layout++) - { - if (!IS_GROUP_ID(layout->group.id) && (layout->entry.attributes & PAGE_ATTR_POST_REMOVE)) - { - size_t start_addr = (size_t)layout->entry.rva + offset + (size_t)get_enclave_base(); - uint32_t page_count = layout->entry.page_count; - - if (0 != (ret = sgx_accept_forward(SI_FLAG_TRIM | SI_FLAG_MODIFIED, start_addr, start_addr + ((size_t)page_count << SE_PAGE_SHIFT)))) - return ret; - } - else if (IS_GROUP_ID(layout->group.id)) - { - size_t step = 0; - for(uint32_t j = 0; j < layout->group.load_times; j++) - { - step += (size_t)layout->group.load_step; - if(0 != (ret = accept_post_remove(&layout[-layout->group.entry_count], layout, step))) - return ret; - } - } - } - return 0; -} - static int check_heap_dyn_range(void *addr, size_t page_count, struct dynamic_flags_attributes *fa) { size_t heap_dyn_start, heap_dyn_size; @@ -303,132 +230,6 @@ uint32_t get_dynamic_stack_max_page() } #endif -int sgx_accept_forward(si_flags_t sfl, size_t lo, size_t hi) -{ -#ifdef SE_SIM - (void)sfl; - (void)lo; - (void)hi; - return 0; -#else - size_t addr = lo; - SE_DECLSPEC_ALIGN(sizeof(sec_info_t)) sec_info_t si; - si.flags = sfl; - for (uint16_t i = 0; i < (sizeof(si.reserved)/sizeof(si.reserved[0])); i++) - si.reserved[i] = 0; - - while (addr < hi) - { - int rc = do_eaccept(&si, addr); - if (rc != 0) - abort(); - addr += SE_PAGE_SIZE; - } - - return 0; -#endif -} - -// High level API to EACCEPT pages, mainly used in exception handling -// to deal with stack expansion. -int apply_pages_within_exception(void *start_address, size_t page_count) -{ -#ifdef SE_SIM - (void)start_address; - (void)page_count; - return 0; -#else - int rc; - - if (start_address == NULL) - return -1; - - if (check_dynamic_range(start_address, page_count, NULL, NULL) != 0) - return -1; - - size_t start = (size_t)start_address; - size_t end = start + (page_count << SE_PAGE_SHIFT); - - rc = sgx_accept_forward_within_exception(start, end); - - return rc; -#endif - -} - -// High level API to EACCEPT pages -int apply_EPC_pages(void *start_address, size_t page_count) -{ -#ifdef SE_SIM - (void)start_address; - (void)page_count; - return 0; -#else - int rc; - struct dynamic_flags_attributes fa; - - if (start_address == NULL) - return -1; - - if (check_dynamic_range(start_address, page_count, NULL, &fa) != 0) - return -1; - - size_t start = (size_t)start_address; - size_t end = start + (page_count << SE_PAGE_SHIFT); - - if (fa.attributes & PAGE_DIR_GROW_DOWN) - { - rc = sgx_accept_forward(SI_FLAGS_RW | SI_FLAG_PENDING, start, end); - } - else - { - rc = sgx_accept_backward(SI_FLAGS_RW | SI_FLAG_PENDING, start, end); - } - - return rc; -#endif -} - -// High level API to trim previously EAUG-ed pages. -int trim_EPC_pages(void *start_address, size_t page_count) -{ -#ifdef SE_SIM - (void)start_address; - (void)page_count; - return 0; -#else - int rc; - - if (start_address == NULL) - return -1; - - // check range - if (check_dynamic_range(start_address, page_count, NULL, NULL) != 0) - return -1; - - size_t start = (size_t)start_address; - size_t end = start + (page_count << SE_PAGE_SHIFT); - - // trim ocall - rc = trim_range_ocall(start, end); - assert(rc == 0); - - rc = sgx_accept_forward(SI_FLAG_TRIM | SI_FLAG_MODIFIED, start, end); - assert(rc == 0); - - // trim commit ocall - size_t i = start; - while (i < end) - { - rc = trim_range_commit_ocall(i); - assert(rc == 0); - i += SE_PAGE_SIZE; - } - - return rc; -#endif -} - // Create a thread dynamically. // It will add necessary pages and transform one of them into type TCS. sgx_status_t do_add_thread(void *ptcs) @@ -460,7 +261,7 @@ sgx_status_t do_add_thread(void *ptcs) const volatile layout_t *layout = get_dynamic_layout_by_id(id); if (layout && (layout->entry.attributes & PAGE_ATTR_DYN_THREAD)) { - ret = apply_EPC_pages((void *)(enclave_base + layout->entry.rva + offset), layout->entry.page_count); + ret = mm_commit((void *)(enclave_base + layout->entry.rva + offset), layout->entry.page_count << SE_PAGE_SHIFT); if (ret != 0) return SGX_ERROR_UNEXPECTED; } @@ -475,13 +276,7 @@ sgx_status_t do_add_thread(void *ptcs) tcs->ofs_base = (size_t)GET_PTR(size_t, (void *)tcs, tcs->ofs_base) - enclave_base; tcs->ogs_base = (size_t)GET_PTR(size_t, (void *)tcs, tcs->ogs_base) - enclave_base; - //OCALL for MKTCS - ret = sgx_ocall(0, tcs); - if (ret != 0) - return SGX_ERROR_UNEXPECTED; - - //EACCEPT for MKTCS - ret = sgx_accept_backward(SI_FLAG_TCS | SI_FLAG_MODIFIED, (size_t)tcs, (size_t)tcs + SE_PAGE_SIZE); + ret = mm_modify_type((void *)tcs, SE_PAGE_SIZE, SGX_EMA_PAGE_TYPE_TCS); if (ret != 0) return SGX_ERROR_UNEXPECTED; diff --git a/sdk/trts/trts_ecall.cpp b/sdk/trts/trts_ecall.cpp index 68f08c618..ff5a4c3dd 100644 --- a/sdk/trts/trts_ecall.cpp +++ b/sdk/trts/trts_ecall.cpp @@ -42,7 +42,8 @@ #include "global_init.h" #include "trts_internal.h" #include "trts_inst.h" -#include "trts_emodpr.h" +#include "trts_emm.h" +#include "sgx_mm.h" #include "trts_util.h" #include "metadata.h" # include "linux/elf_parser.h" @@ -51,6 +52,9 @@ #include "pthread_imp.h" #include "sgx_random_buffers.h" #include "se_page_attr.h" +#include "emm_private.h" + +extern "C" sgx_status_t change_protection(void *enclave_base); __attribute__((weak)) sgx_status_t _pthread_thread_run(void* ms) {UNUSED(ms); return SGX_SUCCESS;} __attribute__((weak)) bool _pthread_enabled() {return false;} @@ -550,7 +554,7 @@ sgx_status_t do_uninit_enclave(void *tcs) size_t start = (size_t)DEC_TCS_POINTER(tcs_node->tcs); size_t end = start + (1 << SE_PAGE_SHIFT); - int rc = sgx_accept_forward(SI_FLAG_TRIM | SI_FLAG_MODIFIED, start, end); + int rc = mm_dealloc((void*)start, end); if(rc != 0) { set_enclave_state(ENCLAVE_CRASHED); @@ -576,39 +580,3 @@ sgx_status_t do_uninit_enclave(void *tcs) return SGX_SUCCESS; } -extern sdk_version_t g_sdk_version; - -extern "C" sgx_status_t trts_mprotect(size_t start, size_t size, uint64_t perms) -{ - int rc = -1; - size_t page; - sgx_status_t ret = SGX_SUCCESS; - SE_DECLSPEC_ALIGN(sizeof(sec_info_t)) sec_info_t si; - - //Error return if start or size is not page-aligned or size is zero. - if (!IS_PAGE_ALIGNED(start) || (size == 0) || !IS_PAGE_ALIGNED(size)) - return SGX_ERROR_INVALID_PARAMETER; - if (g_sdk_version == SDK_VERSION_2_0) - { - ret = change_permissions_ocall(start, size, perms, EDMM_MODPR); - if (ret != SGX_SUCCESS) - return ret; - } - - si.flags = perms|SI_FLAG_REG|SI_FLAG_PR; - memset(&si.reserved, 0, sizeof(si.reserved)); - - for(page = start; page < start + size; page += SE_PAGE_SIZE) - { - do_emodpe(&si, page); - // If the target permission to set is RWX, no EMODPR, hence no EACCEPT. - if ((perms & (SI_FLAG_W|SI_FLAG_X)) != (SI_FLAG_W|SI_FLAG_X)) - { - rc = do_eaccept(&si, page); - if(rc != 0) - return (sgx_status_t)rc; - } - } - - return SGX_SUCCESS; -} diff --git a/sdk/trts/trts_emodpr.h b/sdk/trts/trts_emm.h similarity index 90% rename from sdk/trts/trts_emodpr.h rename to sdk/trts/trts_emm.h index 5cc69fef8..ec32d4e13 100644 --- a/sdk/trts/trts_emodpr.h +++ b/sdk/trts/trts_emm.h @@ -30,8 +30,8 @@ */ -#ifndef MPROTECT_T_H__ -#define MPROTECT_T_H__ +#ifndef TRTS_EMM_H__ +#define TRTS_EMM_H__ #include #include @@ -47,9 +47,9 @@ extern "C" { #endif -sgx_status_t SGXAPI change_permissions_ocall(size_t addr, size_t size, uint64_t epcm_perms, const int proc); +int SGXAPI sgx_mm_alloc_ocall(size_t addr, size_t size, int flags); -sgx_status_t change_protection(void *enclave_base); +int SGXAPI sgx_mm_modify_ocall(size_t addr, size_t size, int flags_from, int flags_to); #ifdef __cplusplus } diff --git a/sdk/trts/trts_internal.h b/sdk/trts/trts_internal.h index 195fc7217..45bb705dc 100644 --- a/sdk/trts/trts_internal.h +++ b/sdk/trts/trts_internal.h @@ -34,6 +34,7 @@ #include "util.h" #include "trts_shared_constants.h" #include "trts_internal_types.h" +#include "sgx_interrupt.h" #define TD2TCS(td) ((const void *)(((thread_data_t*)(td))->stack_base_addr + (size_t)STATIC_STACK_SIZE + (size_t)SE_GUARD_PAGE_SIZE)) #define TCS2CANARY(addr) ((size_t *)((size_t)(addr)-(size_t)SE_GUARD_PAGE_SIZE-(size_t)STATIC_STACK_SIZE+sizeof(size_t))) @@ -59,6 +60,10 @@ sgx_status_t do_uninit_enclave(void *tcs); int check_static_stack_canary(void *tcs); sgx_status_t _pthread_thread_run(void* ms); +sgx_status_t trts_handle_interrupt(void *tcs); +int check_ip_interruptible(size_t ip); +__attribute__((regparm(1))) void internal_handle_interrupt(sgx_interrupt_info_t *info); + #ifdef __cplusplus } #endif diff --git a/sdk/trts/trts_interrupt.cpp b/sdk/trts/trts_interrupt.cpp new file mode 100644 index 000000000..237f0eb5e --- /dev/null +++ b/sdk/trts/trts_interrupt.cpp @@ -0,0 +1,63 @@ +#include "sgx_interrupt.h" +#include "thread_data.h" +#include "trts_internal.h" + +static sgx_interrupt_handler_t registered_handler = NULL; + +static __thread size_t enabled_code_addr = 0; +static __thread size_t enabled_code_size = 0; +static __thread bool is_enabled = false; + +static void set_enabled(bool new_val) { + // Make sure all writes before this store are visible + __atomic_store_n(&is_enabled, new_val, __ATOMIC_RELEASE); +} + + +sgx_status_t sgx_interrupt_init(sgx_interrupt_handler_t handler) { + if (handler == NULL) { + return SGX_ERROR_INVALID_PARAMETER; + } + if (registered_handler != NULL) { + return SGX_ERROR_INVALID_STATE; + } + + registered_handler = handler; + return SGX_SUCCESS; +} + +sgx_status_t sgx_interrupt_enable(size_t code_addr, size_t code_size) { + if (registered_handler == NULL) { + return SGX_ERROR_INVALID_STATE; + } + if (is_enabled) { + return SGX_ERROR_INVALID_STATE; + } + + enabled_code_addr = code_addr; + enabled_code_size = code_size; + set_enabled(true); + return SGX_SUCCESS; +} + +sgx_status_t sgx_interrupt_disable(void) { + if (!is_enabled) { + return SGX_ERROR_INVALID_STATE; + } + set_enabled(false); + return SGX_SUCCESS; +} + +int check_ip_interruptible(size_t ip) { + return is_enabled && + ip >= enabled_code_addr && + (ip - enabled_code_addr) < enabled_code_size; +} + +__attribute__((regparm(1))) void internal_handle_interrupt(sgx_interrupt_info_t *info) { + registered_handler(info); + // Note that the registered handler must be in charge of continueing the execution of + // the interrupted workloads. + // TODO: restore the CPU context info + abort(); +} diff --git a/sdk/trts/trts_nsp.cpp b/sdk/trts/trts_nsp.cpp index 24a0ad5a1..964214917 100644 --- a/sdk/trts/trts_nsp.cpp +++ b/sdk/trts/trts_nsp.cpp @@ -120,6 +120,14 @@ extern "C" int enter_enclave(int index, void *ms, void *tcs, int cssa) error = SGX_ERROR_STACK_OVERRUN; } } + else if((cssa == 1) && (index == ECMD_INTERRUPT)) + { + error = trts_handle_interrupt(tcs); + if (check_static_stack_canary(tcs) != 0) + { + error = SGX_ERROR_STACK_OVERRUN; + } + } if(error == SGX_ERROR_UNEXPECTED) { set_enclave_state(ENCLAVE_CRASHED); diff --git a/sdk/trts/trts_shared_constants.h b/sdk/trts/trts_shared_constants.h index accbb7b54..ca5cc4ef1 100644 --- a/sdk/trts/trts_shared_constants.h +++ b/sdk/trts/trts_shared_constants.h @@ -47,7 +47,7 @@ #endif -#define STATIC_STACK_SIZE 688 +#define STATIC_STACK_SIZE 1024 #endif diff --git a/sdk/trts/trts_veh.cpp b/sdk/trts/trts_veh.cpp index c36c56ed4..9fad06135 100644 --- a/sdk/trts/trts_veh.cpp +++ b/sdk/trts/trts_veh.cpp @@ -50,7 +50,9 @@ #include "trts_util.h" #include "trts_shared_constants.h" #include "se_cdefs.h" - +#include "emm_private.h" +#include "sgx_mm_rt_abstraction.h" +#include "sgx_interrupt.h" typedef struct _handler_node_t { @@ -62,9 +64,12 @@ static handler_node_t *g_first_node = NULL; static sgx_spinlock_t g_handler_lock = SGX_SPINLOCK_INITIALIZER; static uintptr_t g_veh_cookie = 0; +sgx_mm_pfhandler_t g_mm_pfhandler = NULL; #define ENC_VEH_POINTER(x) (uintptr_t)(x) ^ g_veh_cookie #define DEC_VEH_POINTER(x) (sgx_exception_handler_t)((x) ^ g_veh_cookie) +#define XSAVE_PKRU_OFFSET (2688) +#define PKRU_LIBOS (0x0) // sgx_register_exception_handler() // register a custom exception handler @@ -180,6 +185,8 @@ int sgx_unregister_exception_handler(void *handler) return status; } +static bool is_standard_exception(uintptr_t); + // continue_execution(sgx_exception_info_t *info): // try to restore the thread context saved in info to current execution context. extern "C" __attribute__((regparm(1))) void continue_execution(sgx_exception_info_t *info); @@ -197,11 +204,25 @@ extern "C" __attribute__((regparm(1))) void internal_handle_exception(sgx_except uintptr_t *nhead = NULL; uintptr_t *ntmp = NULL; uintptr_t xsp = 0; + bool standard_exception = true; if (thread_data->exception_flag < 0) goto failed_end; thread_data->exception_flag++; + if(info->exception_vector == SGX_EXCEPTION_VECTOR_PF && + (g_mm_pfhandler != NULL)) + { + thread_data->exception_flag--; + sgx_pfinfo* pfinfo = (sgx_pfinfo*)(&info->exinfo); + if(SGX_MM_EXCEPTION_CONTINUE_EXECUTION == g_mm_pfhandler(pfinfo)) + { + //instruction triggering the exception will be executed again. + continue_execution(info); + } + //restore old flag, and fall thru + thread_data->exception_flag++; + } // read lock sgx_spin_lock(&g_handler_lock); @@ -223,7 +244,8 @@ extern "C" __attribute__((regparm(1))) void internal_handle_exception(sgx_except //instruction triggering the exception will be executed again. continue_execution(info); } - // The customer handler may never return, use alloca instead of malloc + + // The customer handler may never return, use alloca instead of malloc if ((nhead = (uintptr_t *)alloca(size)) == NULL) { sgx_spin_unlock(&g_handler_lock); @@ -259,11 +281,13 @@ extern "C" __attribute__((regparm(1))) void internal_handle_exception(sgx_except size -= sizeof(sgx_exception_handler_t); } + standard_exception = is_standard_exception(info->cpu_context.REG(ip)); + // call default handler // ignore invalid return value, treat to EXCEPTION_CONTINUE_SEARCH // check SP to be written on SSA is pointing to the trusted stack xsp = info->cpu_context.REG(sp); - if (!is_valid_sp(xsp)) + if (standard_exception && !is_valid_sp(xsp)) { goto failed_end; } @@ -289,7 +313,7 @@ static int expand_stack_by_pages(void *start_addr, size_t page_count) if ((start_addr == NULL) || (page_count == 0)) return -1; - ret = apply_pages_within_exception(start_addr, page_count); + ret = mm_commit(start_addr, page_count << SE_PAGE_SHIFT); return ret; } @@ -309,7 +333,10 @@ extern "C" sgx_status_t trts_handle_exception(void *tcs) ssa_gpr_t *ssa_gpr = NULL; sgx_exception_info_t *info = NULL; uintptr_t sp_u, sp, *new_sp = NULL; + uintptr_t first_ssa_base = 0, pkru_base = 0; + uint32_t *pkru_ptr = NULL; size_t size = 0; + bool standard_exception = true; if ((thread_data == NULL) || (tcs == NULL)) goto default_handler; if (check_static_stack_canary(tcs) != 0) @@ -324,30 +351,45 @@ extern "C" sgx_status_t trts_handle_exception(void *tcs) if(thread_data->exception_flag == -1) { goto default_handler; } - - if ((TD2TCS(thread_data) != tcs) - || (((thread_data->first_ssa_gpr)&(~0xfff)) - SE_PAGE_SIZE) != (uintptr_t)tcs) { + + if (TD2TCS(thread_data) != tcs || (((thread_data->first_ssa_gpr) & (~0xfff)) - SE_PAGE_SIZE) != (uintptr_t)tcs) + { goto default_handler; } // no need to check the result of ssa_gpr because thread_data is always trusted ssa_gpr = reinterpret_cast(thread_data->first_ssa_gpr); - // The unstrusted RSP should never point inside the enclave - sp_u = ssa_gpr->REG(sp_u); - if (!sgx_is_outside_enclave((void *)sp_u, sizeof(sp_u))) + // The point of differentiating the two types of exceptions is that when handling an exception, we must choose a stack that is suitable for the type of the exception. + // For standard exceptions, we can just use the stacks managed by SGX SDK; + // but, for non-standard exceptions, we cannot make any assumption about how the dynamically-loaded code uses stack--- it may choose an arbitrary memory region as its stack. + // Thus, when handling non-standard exceptions, we use a special, SDK-reserved memory region as the stack. + standard_exception = is_standard_exception(ssa_gpr->REG(ip)); + + if (!standard_exception) { - g_enclave_state = ENCLAVE_CRASHED; - return SGX_ERROR_STACK_OVERRUN; + // The bottom 4 pages are used as stack to handle the non-standard exceptions. + // User should take responsibility to confirm the stack is not corrupted. + sp = thread_data->stack_limit_addr + SE_PAGE_SIZE*4; } - - // The untrusted and trusted RSPs cannot be the same, unless - // an exception happened before the enclave setup the trusted stack - sp = ssa_gpr->REG(sp); - if (sp_u == sp) + else { - g_enclave_state = ENCLAVE_CRASHED; - return SGX_ERROR_STACK_OVERRUN; + // The unstrusted RSP should never point inside the enclave + sp_u = ssa_gpr->REG(sp_u); + if (!sgx_is_outside_enclave((void *)sp_u, sizeof(sp_u))) + { + g_enclave_state = ENCLAVE_CRASHED; + return SGX_ERROR_STACK_OVERRUN; + } + + // The untrusted and trusted RSPs cannot be the same, unless + // an exception happened before the enclave setup the trusted stack + sp = ssa_gpr->REG(sp); + if (sp_u == sp) + { + g_enclave_state = ENCLAVE_CRASHED; + return SGX_ERROR_STACK_OVERRUN; + } } if(!is_stack_addr((void*)sp, 0)) // check stack overrun only, alignment will be checked after exception handled @@ -451,7 +493,14 @@ extern "C" sgx_status_t trts_handle_exception(void *tcs) info->cpu_context.r14 = ssa_gpr->r14; info->cpu_context.r15 = ssa_gpr->r15; #endif - + if (info->exception_vector == SGX_EXCEPTION_VECTOR_PF) + // FUTURE: info->exception_vector == SGX_EXCEPTION_VECTOR_GP) + { + misc_exinfo_t* exinfo = + (misc_exinfo_t*)((uint64_t)ssa_gpr - (uint64_t)MISC_BYTE_SIZE); + info->exinfo.faulting_address = exinfo->maddr; + info->exinfo.error_code = exinfo->errcd; + } new_sp = (uintptr_t *)sp; ssa_gpr->REG(ip) = (size_t)internal_handle_exception; // prepare the ip for 2nd phrase handling ssa_gpr->REG(sp) = (size_t)new_sp; // new stack for internal_handle_exception @@ -462,9 +511,168 @@ extern "C" sgx_status_t trts_handle_exception(void *tcs) //mark valid to 0 to prevent eenter again ssa_gpr->exit_info.valid = 0; + if (!standard_exception && is_pkru_enabled()) + { + // When handling non-standard exceptions, the PKRU saved in SSA XSAVE area can be PKRU_USER. + // We need to update PKRU to PKRU_LIBOS, ensuring LibOS has enough access rights at `internal_handle_exception()`. + first_ssa_base = (uintptr_t)tcs + SE_PAGE_SIZE; + pkru_base = (uintptr_t)first_ssa_base + XSAVE_PKRU_OFFSET; + pkru_ptr = (uint32_t *)pkru_base; + *pkru_ptr = PKRU_LIBOS; + } + return SGX_SUCCESS; default_handler: g_enclave_state = ENCLAVE_CRASHED; return SGX_ERROR_ENCLAVE_CRASHED; } + +uintptr_t enclave_code_start_address = 0; +size_t enclave_code_size = 0; + +// Exceptions, according to their sources, can be categorized into two types: standard exceptions and non-standard exceptions. +// Standard exceptions are those triggered by the code of SGX SDK itself or the app code that statically linked to SGX SDK. +// Non-standard exceptions are those triggered by dynamically-loaded code. +static bool is_standard_exception(uintptr_t xip) +{ + assert(enclave_code_start_address != 0); + assert(enclave_code_size != 0); + + if (xip >= enclave_code_start_address && + xip < (enclave_code_start_address + enclave_code_size)) + { + return true; + } + + return false; +} + +extern "C" sgx_status_t trts_handle_interrupt(void *tcs) +{ + thread_data_t *thread_data = get_thread_data(); + ssa_gpr_t *ssa_gpr = NULL; + sgx_interrupt_info_t *info = NULL; + uintptr_t sp, *new_sp = NULL; + uintptr_t first_ssa_base = 0, pkru_base = 0; + uint32_t *pkru_ptr = NULL; + size_t size = 0; + + if ((thread_data == NULL) || (tcs == NULL)) goto default_handler; + if (check_static_stack_canary(tcs) != 0) + goto default_handler; + + if(get_enclave_state() != ENCLAVE_INIT_DONE) + { + goto default_handler; + } + + if (TD2TCS(thread_data) != tcs || (((thread_data->first_ssa_gpr) & (~0xfff)) - SE_PAGE_SIZE) != (uintptr_t)tcs) + { + goto default_handler; + } + + // no need to check the result of ssa_gpr because thread_data is always trusted + ssa_gpr = reinterpret_cast(thread_data->first_ssa_gpr); + + if(ssa_gpr->exit_info.valid == 1) + { // exceptions cannot be treated as interrupts + goto default_handler; + } + + if (is_standard_exception(ssa_gpr->REG(ip))) { + goto default_handler; + } + + if (!check_ip_interruptible(ssa_gpr->REG(ip))) { + goto default_handler; + } + + // Confirm enclave is execting the user code + if (ssa_gpr->fs == ssa_gpr->gs) { + return SGX_SUCCESS; + } + + // The bottom 4 pages are used as stack to handle the non-standard exceptions. + // User should take responsibility to confirm the stack is not corrupted. + sp = thread_data->stack_limit_addr + SE_PAGE_SIZE*4; + + if(!is_stack_addr((void*)sp, 0)) // check stack overrun only, alignment will be checked after exception handled + { + g_enclave_state = ENCLAVE_CRASHED; + return SGX_ERROR_STACK_OVERRUN; + } + + size = 0; + // x86_64 requires a 128-bytes red zone, which begins directly + // after the return addr and includes func's arguments + size += RED_ZONE_SIZE; + + // decrease the stack to give space for info + size += sizeof(sgx_exception_info_t); + sp -= size; + sp = sp & ~0xF; + + // check the decreased sp to make sure it is in the trusted stack range + if(!is_stack_addr((void *)sp, size)) + { + g_enclave_state = ENCLAVE_CRASHED; + return SGX_ERROR_STACK_OVERRUN; + } + + info = (sgx_interrupt_info_t *)sp; + // decrease the stack to save the SSA[0]->ip + size = sizeof(uintptr_t); + sp -= size; + if(!is_stack_addr((void *)sp, size)) + { + g_enclave_state = ENCLAVE_CRASHED; + return SGX_ERROR_STACK_OVERRUN; + } + + // restore the fs + ssa_gpr->fs = ssa_gpr->gs; + + // initialize the info with SSA[0] + info->cpu_context.REG(ax) = ssa_gpr->REG(ax); + info->cpu_context.REG(cx) = ssa_gpr->REG(cx); + info->cpu_context.REG(dx) = ssa_gpr->REG(dx); + info->cpu_context.REG(bx) = ssa_gpr->REG(bx); + info->cpu_context.REG(sp) = ssa_gpr->REG(sp); + info->cpu_context.REG(bp) = ssa_gpr->REG(bp); + info->cpu_context.REG(si) = ssa_gpr->REG(si); + info->cpu_context.REG(di) = ssa_gpr->REG(di); + info->cpu_context.REG(flags) = ssa_gpr->REG(flags); + info->cpu_context.REG(ip) = ssa_gpr->REG(ip); +#ifdef SE_64 + info->cpu_context.r8 = ssa_gpr->r8; + info->cpu_context.r9 = ssa_gpr->r9; + info->cpu_context.r10 = ssa_gpr->r10; + info->cpu_context.r11 = ssa_gpr->r11; + info->cpu_context.r12 = ssa_gpr->r12; + info->cpu_context.r13 = ssa_gpr->r13; + info->cpu_context.r14 = ssa_gpr->r14; + info->cpu_context.r15 = ssa_gpr->r15; +#endif + + new_sp = (uintptr_t *)sp; + ssa_gpr->REG(ip) = (size_t)internal_handle_interrupt; // prepare the ip for 2nd phrase handling + ssa_gpr->REG(sp) = (size_t)new_sp; // new stack for internal_handle_exception + ssa_gpr->REG(ax) = (size_t)info; // 1st parameter (info) for LINUX32 + ssa_gpr->REG(di) = (size_t)info; // 1st parameter (info) for LINUX64, LINUX32 also uses it while restoring the context + *new_sp = info->cpu_context.REG(ip); // for debugger to get call trace + + if (is_pkru_enabled()) + { + // Update PKRU to PKRU_LIBOS, ensuring LibOS has enough access rights at `internal_handle_exception()`. + first_ssa_base = (uintptr_t)tcs + SE_PAGE_SIZE; + pkru_base = (uintptr_t)first_ssa_base + XSAVE_PKRU_OFFSET; + pkru_ptr = (uint32_t *)pkru_base; + *pkru_ptr = PKRU_LIBOS; + } + + return SGX_SUCCESS; + +default_handler: + return SGX_SUCCESS; +}