1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright(c) 2016-20 Intel Corporation. */ 3 4 #include <elf.h> 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <stdbool.h> 8 #include <stdio.h> 9 #include <stdint.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <unistd.h> 13 #include <sys/ioctl.h> 14 #include <sys/mman.h> 15 #include <sys/stat.h> 16 #include <sys/time.h> 17 #include <sys/types.h> 18 #include <sys/auxv.h> 19 #include "defines.h" 20 #include "main.h" 21 #include "../kselftest.h" 22 23 static const uint64_t MAGIC = 0x1122334455667788ULL; 24 vdso_sgx_enter_enclave_t eenter; 25 26 struct vdso_symtab { 27 Elf64_Sym *elf_symtab; 28 const char *elf_symstrtab; 29 Elf64_Word *elf_hashtab; 30 }; 31 32 static Elf64_Dyn *vdso_get_dyntab(void *addr) 33 { 34 Elf64_Ehdr *ehdr = addr; 35 Elf64_Phdr *phdrtab = addr + ehdr->e_phoff; 36 int i; 37 38 for (i = 0; i < ehdr->e_phnum; i++) 39 if (phdrtab[i].p_type == PT_DYNAMIC) 40 return addr + phdrtab[i].p_offset; 41 42 return NULL; 43 } 44 45 static void *vdso_get_dyn(void *addr, Elf64_Dyn *dyntab, Elf64_Sxword tag) 46 { 47 int i; 48 49 for (i = 0; dyntab[i].d_tag != DT_NULL; i++) 50 if (dyntab[i].d_tag == tag) 51 return addr + dyntab[i].d_un.d_ptr; 52 53 return NULL; 54 } 55 56 static bool vdso_get_symtab(void *addr, struct vdso_symtab *symtab) 57 { 58 Elf64_Dyn *dyntab = vdso_get_dyntab(addr); 59 60 symtab->elf_symtab = vdso_get_dyn(addr, dyntab, DT_SYMTAB); 61 if (!symtab->elf_symtab) 62 return false; 63 64 symtab->elf_symstrtab = vdso_get_dyn(addr, dyntab, DT_STRTAB); 65 if (!symtab->elf_symstrtab) 66 return false; 67 68 symtab->elf_hashtab = vdso_get_dyn(addr, dyntab, DT_HASH); 69 if (!symtab->elf_hashtab) 70 return false; 71 72 return true; 73 } 74 75 static unsigned long elf_sym_hash(const char *name) 76 { 77 unsigned long h = 0, high; 78 79 while (*name) { 80 h = (h << 4) + *name++; 81 high = h & 0xf0000000; 82 83 if (high) 84 h ^= high >> 24; 85 86 h &= ~high; 87 } 88 89 return h; 90 } 91 92 static Elf64_Sym *vdso_symtab_get(struct vdso_symtab *symtab, const char *name) 93 { 94 Elf64_Word bucketnum = symtab->elf_hashtab[0]; 95 Elf64_Word *buckettab = &symtab->elf_hashtab[2]; 96 Elf64_Word *chaintab = &symtab->elf_hashtab[2 + bucketnum]; 97 Elf64_Sym *sym; 98 Elf64_Word i; 99 100 for (i = buckettab[elf_sym_hash(name) % bucketnum]; i != STN_UNDEF; 101 i = chaintab[i]) { 102 sym = &symtab->elf_symtab[i]; 103 if (!strcmp(name, &symtab->elf_symstrtab[sym->st_name])) 104 return sym; 105 } 106 107 return NULL; 108 } 109 110 bool report_results(struct sgx_enclave_run *run, int ret, uint64_t result, 111 const char *test) 112 { 113 bool valid = true; 114 115 if (ret) { 116 printf("FAIL: %s() returned: %d\n", test, ret); 117 valid = false; 118 } 119 120 if (run->function != EEXIT) { 121 printf("FAIL: %s() function, expected: %u, got: %u\n", test, EEXIT, 122 run->function); 123 valid = false; 124 } 125 126 if (result != MAGIC) { 127 printf("FAIL: %s(), expected: 0x%lx, got: 0x%lx\n", test, MAGIC, 128 result); 129 valid = false; 130 } 131 132 if (run->user_data) { 133 printf("FAIL: %s() user data, expected: 0x0, got: 0x%llx\n", 134 test, run->user_data); 135 valid = false; 136 } 137 138 return valid; 139 } 140 141 static int user_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9, 142 struct sgx_enclave_run *run) 143 { 144 run->user_data = 0; 145 return 0; 146 } 147 148 int main(int argc, char *argv[]) 149 { 150 struct sgx_enclave_run run; 151 struct vdso_symtab symtab; 152 Elf64_Sym *eenter_sym; 153 uint64_t result = 0; 154 struct encl encl; 155 unsigned int i; 156 void *addr; 157 int ret; 158 159 memset(&run, 0, sizeof(run)); 160 161 if (!encl_load("test_encl.elf", &encl)) { 162 encl_delete(&encl); 163 ksft_exit_skip("cannot load enclaves\n"); 164 } 165 166 if (!encl_measure(&encl)) 167 goto err; 168 169 if (!encl_build(&encl)) 170 goto err; 171 172 /* 173 * An enclave consumer only must do this. 174 */ 175 for (i = 0; i < encl.nr_segments; i++) { 176 struct encl_segment *seg = &encl.segment_tbl[i]; 177 178 addr = mmap((void *)encl.encl_base + seg->offset, seg->size, 179 seg->prot, MAP_SHARED | MAP_FIXED, encl.fd, 0); 180 if (addr == MAP_FAILED) { 181 perror("mmap() segment failed"); 182 exit(KSFT_FAIL); 183 } 184 } 185 186 memset(&run, 0, sizeof(run)); 187 run.tcs = encl.encl_base; 188 189 /* Get vDSO base address */ 190 addr = (void *)getauxval(AT_SYSINFO_EHDR); 191 if (!addr) 192 goto err; 193 194 if (!vdso_get_symtab(addr, &symtab)) 195 goto err; 196 197 eenter_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave"); 198 if (!eenter_sym) 199 goto err; 200 201 eenter = addr + eenter_sym->st_value; 202 203 ret = sgx_call_vdso((void *)&MAGIC, &result, 0, EENTER, NULL, NULL, &run); 204 if (!report_results(&run, ret, result, "sgx_call_vdso")) 205 goto err; 206 207 208 /* Invoke the vDSO directly. */ 209 result = 0; 210 ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER, 211 0, 0, &run); 212 if (!report_results(&run, ret, result, "eenter")) 213 goto err; 214 215 /* And with an exit handler. */ 216 run.user_handler = (__u64)user_handler; 217 run.user_data = 0xdeadbeef; 218 ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER, 219 0, 0, &run); 220 if (!report_results(&run, ret, result, "user_handler")) 221 goto err; 222 223 printf("SUCCESS\n"); 224 encl_delete(&encl); 225 exit(KSFT_PASS); 226 227 err: 228 encl_delete(&encl); 229 exit(KSFT_FAIL); 230 } 231