linux/tools/testing/selftests/sgx/load.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*  Copyright(c) 2016-20 Intel Corporation. */
   3
   4#include <assert.h>
   5#include <elf.h>
   6#include <errno.h>
   7#include <fcntl.h>
   8#include <stdbool.h>
   9#include <stdio.h>
  10#include <stdint.h>
  11#include <stdlib.h>
  12#include <string.h>
  13#include <unistd.h>
  14#include <sys/ioctl.h>
  15#include <sys/mman.h>
  16#include <sys/stat.h>
  17#include <sys/time.h>
  18#include <sys/types.h>
  19#include "defines.h"
  20#include "main.h"
  21
  22void encl_delete(struct encl *encl)
  23{
  24        if (encl->encl_base)
  25                munmap((void *)encl->encl_base, encl->encl_size);
  26
  27        if (encl->bin)
  28                munmap(encl->bin, encl->bin_size);
  29
  30        if (encl->fd)
  31                close(encl->fd);
  32
  33        if (encl->segment_tbl)
  34                free(encl->segment_tbl);
  35
  36        memset(encl, 0, sizeof(*encl));
  37}
  38
  39static bool encl_map_bin(const char *path, struct encl *encl)
  40{
  41        struct stat sb;
  42        void *bin;
  43        int ret;
  44        int fd;
  45
  46        fd = open(path, O_RDONLY);
  47        if (fd == -1)  {
  48                perror("enclave executable open()");
  49                return false;
  50        }
  51
  52        ret = stat(path, &sb);
  53        if (ret) {
  54                perror("enclave executable stat()");
  55                goto err;
  56        }
  57
  58        bin = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  59        if (bin == MAP_FAILED) {
  60                perror("enclave executable mmap()");
  61                goto err;
  62        }
  63
  64        encl->bin = bin;
  65        encl->bin_size = sb.st_size;
  66
  67        close(fd);
  68        return true;
  69
  70err:
  71        close(fd);
  72        return false;
  73}
  74
  75static bool encl_ioc_create(struct encl *encl)
  76{
  77        struct sgx_secs *secs = &encl->secs;
  78        struct sgx_enclave_create ioc;
  79        int rc;
  80
  81        assert(encl->encl_base != 0);
  82
  83        memset(secs, 0, sizeof(*secs));
  84        secs->ssa_frame_size = 1;
  85        secs->attributes = SGX_ATTR_MODE64BIT;
  86        secs->xfrm = 3;
  87        secs->base = encl->encl_base;
  88        secs->size = encl->encl_size;
  89
  90        ioc.src = (unsigned long)secs;
  91        rc = ioctl(encl->fd, SGX_IOC_ENCLAVE_CREATE, &ioc);
  92        if (rc) {
  93                perror("SGX_IOC_ENCLAVE_CREATE failed");
  94                munmap((void *)secs->base, encl->encl_size);
  95                return false;
  96        }
  97
  98        return true;
  99}
 100
 101static bool encl_ioc_add_pages(struct encl *encl, struct encl_segment *seg)
 102{
 103        struct sgx_enclave_add_pages ioc;
 104        struct sgx_secinfo secinfo;
 105        int rc;
 106
 107        memset(&secinfo, 0, sizeof(secinfo));
 108        secinfo.flags = seg->flags;
 109
 110        ioc.src = (uint64_t)encl->src + seg->offset;
 111        ioc.offset = seg->offset;
 112        ioc.length = seg->size;
 113        ioc.secinfo = (unsigned long)&secinfo;
 114        ioc.flags = SGX_PAGE_MEASURE;
 115
 116        rc = ioctl(encl->fd, SGX_IOC_ENCLAVE_ADD_PAGES, &ioc);
 117        if (rc < 0) {
 118                perror("SGX_IOC_ENCLAVE_ADD_PAGES failed");
 119                return false;
 120        }
 121
 122        return true;
 123}
 124
 125
 126
 127bool encl_load(const char *path, struct encl *encl)
 128{
 129        const char device_path[] = "/dev/sgx_enclave";
 130        Elf64_Phdr *phdr_tbl;
 131        off_t src_offset;
 132        Elf64_Ehdr *ehdr;
 133        struct stat sb;
 134        void *ptr;
 135        int i, j;
 136        int ret;
 137        int fd = -1;
 138
 139        memset(encl, 0, sizeof(*encl));
 140
 141        fd = open(device_path, O_RDWR);
 142        if (fd < 0) {
 143                perror("Unable to open /dev/sgx_enclave");
 144                goto err;
 145        }
 146
 147        ret = stat(device_path, &sb);
 148        if (ret) {
 149                perror("device file stat()");
 150                goto err;
 151        }
 152
 153        ptr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
 154        if (ptr == (void *)-1) {
 155                perror("mmap for read");
 156                goto err;
 157        }
 158        munmap(ptr, PAGE_SIZE);
 159
 160#define ERR_MSG \
 161"mmap() succeeded for PROT_READ, but failed for PROT_EXEC.\n" \
 162" Check that /dev does not have noexec set:\n" \
 163" \tmount | grep \"/dev .*noexec\"\n" \
 164" If so, remount it executable: mount -o remount,exec /dev\n\n"
 165
 166        ptr = mmap(NULL, PAGE_SIZE, PROT_EXEC, MAP_SHARED, fd, 0);
 167        if (ptr == (void *)-1) {
 168                fprintf(stderr, ERR_MSG);
 169                goto err;
 170        }
 171        munmap(ptr, PAGE_SIZE);
 172
 173        encl->fd = fd;
 174
 175        if (!encl_map_bin(path, encl))
 176                goto err;
 177
 178        ehdr = encl->bin;
 179        phdr_tbl = encl->bin + ehdr->e_phoff;
 180
 181        for (i = 0; i < ehdr->e_phnum; i++) {
 182                Elf64_Phdr *phdr = &phdr_tbl[i];
 183
 184                if (phdr->p_type == PT_LOAD)
 185                        encl->nr_segments++;
 186        }
 187
 188        encl->segment_tbl = calloc(encl->nr_segments,
 189                                   sizeof(struct encl_segment));
 190        if (!encl->segment_tbl)
 191                goto err;
 192
 193        for (i = 0, j = 0; i < ehdr->e_phnum; i++) {
 194                Elf64_Phdr *phdr = &phdr_tbl[i];
 195                unsigned int flags = phdr->p_flags;
 196                struct encl_segment *seg;
 197
 198                if (phdr->p_type != PT_LOAD)
 199                        continue;
 200
 201                seg = &encl->segment_tbl[j];
 202
 203                if (!!(flags & ~(PF_R | PF_W | PF_X))) {
 204                        fprintf(stderr,
 205                                "%d has invalid segment flags 0x%02x.\n", i,
 206                                phdr->p_flags);
 207                        goto err;
 208                }
 209
 210                if (j == 0 && flags != (PF_R | PF_W)) {
 211                        fprintf(stderr,
 212                                "TCS has invalid segment flags 0x%02x.\n",
 213                                phdr->p_flags);
 214                        goto err;
 215                }
 216
 217                if (j == 0) {
 218                        src_offset = phdr->p_offset & PAGE_MASK;
 219
 220                        seg->prot = PROT_READ | PROT_WRITE;
 221                        seg->flags = SGX_PAGE_TYPE_TCS << 8;
 222                } else  {
 223                        seg->prot = (phdr->p_flags & PF_R) ? PROT_READ : 0;
 224                        seg->prot |= (phdr->p_flags & PF_W) ? PROT_WRITE : 0;
 225                        seg->prot |= (phdr->p_flags & PF_X) ? PROT_EXEC : 0;
 226                        seg->flags = (SGX_PAGE_TYPE_REG << 8) | seg->prot;
 227                }
 228
 229                seg->offset = (phdr->p_offset & PAGE_MASK) - src_offset;
 230                seg->size = (phdr->p_filesz + PAGE_SIZE - 1) & PAGE_MASK;
 231
 232                j++;
 233        }
 234
 235        assert(j == encl->nr_segments);
 236
 237        encl->src = encl->bin + src_offset;
 238        encl->src_size = encl->segment_tbl[j - 1].offset +
 239                         encl->segment_tbl[j - 1].size;
 240
 241        for (encl->encl_size = 4096; encl->encl_size < encl->src_size; )
 242                encl->encl_size <<= 1;
 243
 244        return true;
 245
 246err:
 247        if (fd != -1)
 248                close(fd);
 249        encl_delete(encl);
 250        return false;
 251}
 252
 253static bool encl_map_area(struct encl *encl)
 254{
 255        size_t encl_size = encl->encl_size;
 256        void *area;
 257
 258        area = mmap(NULL, encl_size * 2, PROT_NONE,
 259                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 260        if (area == MAP_FAILED) {
 261                perror("reservation mmap()");
 262                return false;
 263        }
 264
 265        encl->encl_base = ((uint64_t)area + encl_size - 1) & ~(encl_size - 1);
 266
 267        munmap(area, encl->encl_base - (uint64_t)area);
 268        munmap((void *)(encl->encl_base + encl_size),
 269               (uint64_t)area + encl_size - encl->encl_base);
 270
 271        return true;
 272}
 273
 274bool encl_build(struct encl *encl)
 275{
 276        struct sgx_enclave_init ioc;
 277        int ret;
 278        int i;
 279
 280        if (!encl_map_area(encl))
 281                return false;
 282
 283        if (!encl_ioc_create(encl))
 284                return false;
 285
 286        /*
 287         * Pages must be added before mapping VMAs because their permissions
 288         * cap the VMA permissions.
 289         */
 290        for (i = 0; i < encl->nr_segments; i++) {
 291                struct encl_segment *seg = &encl->segment_tbl[i];
 292
 293                if (!encl_ioc_add_pages(encl, seg))
 294                        return false;
 295        }
 296
 297        ioc.sigstruct = (uint64_t)&encl->sigstruct;
 298        ret = ioctl(encl->fd, SGX_IOC_ENCLAVE_INIT, &ioc);
 299        if (ret) {
 300                perror("SGX_IOC_ENCLAVE_INIT failed");
 301                return false;
 302        }
 303
 304        return true;
 305}
 306