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