linux/tools/testing/selftests/sgx/main.c
<<
>>
Prefs
   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
  23static const uint64_t MAGIC = 0x1122334455667788ULL;
  24vdso_sgx_enter_enclave_t eenter;
  25
  26struct vdso_symtab {
  27        Elf64_Sym *elf_symtab;
  28        const char *elf_symstrtab;
  29        Elf64_Word *elf_hashtab;
  30};
  31
  32static 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
  45static 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
  56static 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
  75static 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
  92static 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
 110bool 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
 141static 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
 148int 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
 227err:
 228        encl_delete(&encl);
 229        exit(KSFT_FAIL);
 230}
 231