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