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 "../kselftest_harness.h" 21 #include "main.h" 22 23 static const uint64_t MAGIC = 0x1122334455667788ULL; 24 vdso_sgx_enter_enclave_t vdso_sgx_enter_enclave; 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 FIXTURE(enclave) { 111 struct encl encl; 112 struct sgx_enclave_run run; 113 }; 114 115 FIXTURE_SETUP(enclave) 116 { 117 Elf64_Sym *sgx_enter_enclave_sym = NULL; 118 struct vdso_symtab symtab; 119 struct encl_segment *seg; 120 char maps_line[256]; 121 FILE *maps_file; 122 unsigned int i; 123 void *addr; 124 125 if (!encl_load("test_encl.elf", &self->encl)) { 126 encl_delete(&self->encl); 127 ksft_exit_skip("cannot load enclaves\n"); 128 } 129 130 for (i = 0; i < self->encl.nr_segments; i++) { 131 seg = &self->encl.segment_tbl[i]; 132 133 TH_LOG("0x%016lx 0x%016lx 0x%02x", seg->offset, seg->size, seg->prot); 134 } 135 136 if (!encl_measure(&self->encl)) 137 goto err; 138 139 if (!encl_build(&self->encl)) 140 goto err; 141 142 /* 143 * An enclave consumer only must do this. 144 */ 145 for (i = 0; i < self->encl.nr_segments; i++) { 146 struct encl_segment *seg = &self->encl.segment_tbl[i]; 147 148 addr = mmap((void *)self->encl.encl_base + seg->offset, seg->size, 149 seg->prot, MAP_SHARED | MAP_FIXED, self->encl.fd, 0); 150 EXPECT_NE(addr, MAP_FAILED); 151 if (addr == MAP_FAILED) 152 goto err; 153 } 154 155 /* Get vDSO base address */ 156 addr = (void *)getauxval(AT_SYSINFO_EHDR); 157 if (!addr) 158 goto err; 159 160 if (!vdso_get_symtab(addr, &symtab)) 161 goto err; 162 163 sgx_enter_enclave_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave"); 164 if (!sgx_enter_enclave_sym) 165 goto err; 166 167 vdso_sgx_enter_enclave = addr + sgx_enter_enclave_sym->st_value; 168 169 memset(&self->run, 0, sizeof(self->run)); 170 self->run.tcs = self->encl.encl_base; 171 172 maps_file = fopen("/proc/self/maps", "r"); 173 if (maps_file != NULL) { 174 while (fgets(maps_line, sizeof(maps_line), maps_file) != NULL) { 175 maps_line[strlen(maps_line) - 1] = '\0'; 176 177 if (strstr(maps_line, "/dev/sgx_enclave")) 178 TH_LOG("%s", maps_line); 179 } 180 181 fclose(maps_file); 182 } 183 184 err: 185 if (!sgx_enter_enclave_sym) 186 encl_delete(&self->encl); 187 188 ASSERT_NE(sgx_enter_enclave_sym, NULL); 189 } 190 191 FIXTURE_TEARDOWN(enclave) 192 { 193 encl_delete(&self->encl); 194 } 195 196 #define ENCL_CALL(op, run, clobbered) \ 197 ({ \ 198 int ret; \ 199 if ((clobbered)) \ 200 ret = vdso_sgx_enter_enclave((unsigned long)(op), 0, 0, \ 201 EENTER, 0, 0, (run)); \ 202 else \ 203 ret = sgx_enter_enclave((void *)(op), NULL, 0, EENTER, NULL, NULL, \ 204 (run)); \ 205 ret; \ 206 }) 207 208 #define EXPECT_EEXIT(run) \ 209 do { \ 210 EXPECT_EQ((run)->function, EEXIT); \ 211 if ((run)->function != EEXIT) \ 212 TH_LOG("0x%02x 0x%02x 0x%016llx", (run)->exception_vector, \ 213 (run)->exception_error_code, (run)->exception_addr); \ 214 } while (0) 215 216 TEST_F(enclave, unclobbered_vdso) 217 { 218 struct encl_op op; 219 220 op.type = ENCL_OP_PUT; 221 op.buffer = MAGIC; 222 223 EXPECT_EQ(ENCL_CALL(&op, &self->run, false), 0); 224 225 EXPECT_EEXIT(&self->run); 226 EXPECT_EQ(self->run.user_data, 0); 227 228 op.type = ENCL_OP_GET; 229 op.buffer = 0; 230 231 EXPECT_EQ(ENCL_CALL(&op, &self->run, false), 0); 232 233 EXPECT_EQ(op.buffer, MAGIC); 234 EXPECT_EEXIT(&self->run); 235 EXPECT_EQ(self->run.user_data, 0); 236 } 237 238 TEST_F(enclave, clobbered_vdso) 239 { 240 struct encl_op op; 241 242 op.type = ENCL_OP_PUT; 243 op.buffer = MAGIC; 244 245 EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0); 246 247 EXPECT_EEXIT(&self->run); 248 EXPECT_EQ(self->run.user_data, 0); 249 250 op.type = ENCL_OP_GET; 251 op.buffer = 0; 252 253 EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0); 254 255 EXPECT_EQ(op.buffer, MAGIC); 256 EXPECT_EEXIT(&self->run); 257 EXPECT_EQ(self->run.user_data, 0); 258 } 259 260 static int test_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9, 261 struct sgx_enclave_run *run) 262 { 263 run->user_data = 0; 264 265 return 0; 266 } 267 268 TEST_F(enclave, clobbered_vdso_and_user_function) 269 { 270 struct encl_op op; 271 272 self->run.user_handler = (__u64)test_handler; 273 self->run.user_data = 0xdeadbeef; 274 275 op.type = ENCL_OP_PUT; 276 op.buffer = MAGIC; 277 278 EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0); 279 280 EXPECT_EEXIT(&self->run); 281 EXPECT_EQ(self->run.user_data, 0); 282 283 op.type = ENCL_OP_GET; 284 op.buffer = 0; 285 286 EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0); 287 288 EXPECT_EQ(op.buffer, MAGIC); 289 EXPECT_EEXIT(&self->run); 290 EXPECT_EQ(self->run.user_data, 0); 291 } 292 293 TEST_HARNESS_MAIN 294