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 "../kselftest_harness.h"
  21#include "main.h"
  22
  23static const uint64_t MAGIC = 0x1122334455667788ULL;
  24vdso_sgx_enter_enclave_t vdso_sgx_enter_enclave;
  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
 110FIXTURE(enclave) {
 111        struct encl encl;
 112        struct sgx_enclave_run run;
 113};
 114
 115FIXTURE_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
 184err:
 185        if (!sgx_enter_enclave_sym)
 186                encl_delete(&self->encl);
 187
 188        ASSERT_NE(sgx_enter_enclave_sym, NULL);
 189}
 190
 191FIXTURE_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
 216TEST_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
 238TEST_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
 260static 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
 268TEST_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
 293TEST_HARNESS_MAIN
 294