// SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2016-20 Intel Corporation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "main.h" #include "../kselftest.h" static const uint64_t MAGIC = 0x1122334455667788ULL; vdso_sgx_enter_enclave_t eenter; struct vdso_symtab { Elf64_Sym *elf_symtab; const char *elf_symstrtab; Elf64_Word *elf_hashtab; }; static void *vdso_get_base_addr(char *envp[]) { Elf64_auxv_t *auxv; int i; for (i = 0; envp[i]; i++) ; auxv = (Elf64_auxv_t *)&envp[i + 1]; for (i = 0; auxv[i].a_type != AT_NULL; i++) { if (auxv[i].a_type == AT_SYSINFO_EHDR) return (void *)auxv[i].a_un.a_val; } return NULL; } static Elf64_Dyn *vdso_get_dyntab(void *addr) { Elf64_Ehdr *ehdr = addr; Elf64_Phdr *phdrtab = addr + ehdr->e_phoff; int i; for (i = 0; i < ehdr->e_phnum; i++) if (phdrtab[i].p_type == PT_DYNAMIC) return addr + phdrtab[i].p_offset; return NULL; } static void *vdso_get_dyn(void *addr, Elf64_Dyn *dyntab, Elf64_Sxword tag) { int i; for (i = 0; dyntab[i].d_tag != DT_NULL; i++) if (dyntab[i].d_tag == tag) return addr + dyntab[i].d_un.d_ptr; return NULL; } static bool vdso_get_symtab(void *addr, struct vdso_symtab *symtab) { Elf64_Dyn *dyntab = vdso_get_dyntab(addr); symtab->elf_symtab = vdso_get_dyn(addr, dyntab, DT_SYMTAB); if (!symtab->elf_symtab) return false; symtab->elf_symstrtab = vdso_get_dyn(addr, dyntab, DT_STRTAB); if (!symtab->elf_symstrtab) return false; symtab->elf_hashtab = vdso_get_dyn(addr, dyntab, DT_HASH); if (!symtab->elf_hashtab) return false; return true; } static unsigned long elf_sym_hash(const char *name) { unsigned long h = 0, high; while (*name) { h = (h << 4) + *name++; high = h & 0xf0000000; if (high) h ^= high >> 24; h &= ~high; } return h; } static Elf64_Sym *vdso_symtab_get(struct vdso_symtab *symtab, const char *name) { Elf64_Word bucketnum = symtab->elf_hashtab[0]; Elf64_Word *buckettab = &symtab->elf_hashtab[2]; Elf64_Word *chaintab = &symtab->elf_hashtab[2 + bucketnum]; Elf64_Sym *sym; Elf64_Word i; for (i = buckettab[elf_sym_hash(name) % bucketnum]; i != STN_UNDEF; i = chaintab[i]) { sym = &symtab->elf_symtab[i]; if (!strcmp(name, &symtab->elf_symstrtab[sym->st_name])) return sym; } return NULL; } bool report_results(struct sgx_enclave_run *run, int ret, uint64_t result, const char *test) { bool valid = true; if (ret) { printf("FAIL: %s() returned: %d\n", test, ret); valid = false; } if (run->function != EEXIT) { printf("FAIL: %s() function, expected: %u, got: %u\n", test, EEXIT, run->function); valid = false; } if (result != MAGIC) { printf("FAIL: %s(), expected: 0x%lx, got: 0x%lx\n", test, MAGIC, result); valid = false; } if (run->user_data) { printf("FAIL: %s() user data, expected: 0x0, got: 0x%llx\n", test, run->user_data); valid = false; } return valid; } static int user_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9, struct sgx_enclave_run *run) { run->user_data = 0; return 0; } int main(int argc, char *argv[], char *envp[]) { struct sgx_enclave_run run; struct vdso_symtab symtab; Elf64_Sym *eenter_sym; uint64_t result = 0; struct encl encl; unsigned int i; void *addr; int ret; memset(&run, 0, sizeof(run)); if (!encl_load("test_encl.elf", &encl)) { encl_delete(&encl); ksft_exit_skip("cannot load enclaves\n"); } if (!encl_measure(&encl)) goto err; if (!encl_build(&encl)) goto err; /* * An enclave consumer only must do this. */ for (i = 0; i < encl.nr_segments; i++) { struct encl_segment *seg = &encl.segment_tbl[i]; addr = mmap((void *)encl.encl_base + seg->offset, seg->size, seg->prot, MAP_SHARED | MAP_FIXED, encl.fd, 0); if (addr == MAP_FAILED) { fprintf(stderr, "mmap() failed, errno=%d.\n", errno); exit(KSFT_FAIL); } } memset(&run, 0, sizeof(run)); run.tcs = encl.encl_base; addr = vdso_get_base_addr(envp); if (!addr) goto err; if (!vdso_get_symtab(addr, &symtab)) goto err; eenter_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave"); if (!eenter_sym) goto err; eenter = addr + eenter_sym->st_value; ret = sgx_call_vdso((void *)&MAGIC, &result, 0, EENTER, NULL, NULL, &run); if (!report_results(&run, ret, result, "sgx_call_vdso")) goto err; /* Invoke the vDSO directly. */ result = 0; ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER, 0, 0, &run); if (!report_results(&run, ret, result, "eenter")) goto err; /* And with an exit handler. */ run.user_handler = (__u64)user_handler; run.user_data = 0xdeadbeef; ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER, 0, 0, &run); if (!report_results(&run, ret, result, "user_handler")) goto err; printf("SUCCESS\n"); encl_delete(&encl); exit(KSFT_PASS); err: encl_delete(&encl); exit(KSFT_FAIL); }