1994 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2016-20 Intel Corporation. */3 4#include <cpuid.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 <sys/auxv.h>20#include "defines.h"21#include "../kselftest_harness.h"22#include "main.h"23 24static const uint64_t MAGIC = 0x1122334455667788ULL;25static const uint64_t MAGIC2 = 0x8877665544332211ULL;26vdso_sgx_enter_enclave_t vdso_sgx_enter_enclave;27 28/*29 * Security Information (SECINFO) data structure needed by a few SGX30 * instructions (eg. ENCLU[EACCEPT] and ENCLU[EMODPE]) holds meta-data31 * about an enclave page. &enum sgx_secinfo_page_state specifies the32 * secinfo flags used for page state.33 */34enum sgx_secinfo_page_state {35 SGX_SECINFO_PENDING = (1 << 3),36 SGX_SECINFO_MODIFIED = (1 << 4),37 SGX_SECINFO_PR = (1 << 5),38};39 40struct vdso_symtab {41 Elf64_Sym *elf_symtab;42 const char *elf_symstrtab;43 Elf64_Word *elf_hashtab;44};45 46static Elf64_Dyn *vdso_get_dyntab(void *addr)47{48 Elf64_Ehdr *ehdr = addr;49 Elf64_Phdr *phdrtab = addr + ehdr->e_phoff;50 int i;51 52 for (i = 0; i < ehdr->e_phnum; i++)53 if (phdrtab[i].p_type == PT_DYNAMIC)54 return addr + phdrtab[i].p_offset;55 56 return NULL;57}58 59static void *vdso_get_dyn(void *addr, Elf64_Dyn *dyntab, Elf64_Sxword tag)60{61 int i;62 63 for (i = 0; dyntab[i].d_tag != DT_NULL; i++)64 if (dyntab[i].d_tag == tag)65 return addr + dyntab[i].d_un.d_ptr;66 67 return NULL;68}69 70static bool vdso_get_symtab(void *addr, struct vdso_symtab *symtab)71{72 Elf64_Dyn *dyntab = vdso_get_dyntab(addr);73 74 symtab->elf_symtab = vdso_get_dyn(addr, dyntab, DT_SYMTAB);75 if (!symtab->elf_symtab)76 return false;77 78 symtab->elf_symstrtab = vdso_get_dyn(addr, dyntab, DT_STRTAB);79 if (!symtab->elf_symstrtab)80 return false;81 82 symtab->elf_hashtab = vdso_get_dyn(addr, dyntab, DT_HASH);83 if (!symtab->elf_hashtab)84 return false;85 86 return true;87}88 89static inline int sgx2_supported(void)90{91 unsigned int eax, ebx, ecx, edx;92 93 __cpuid_count(SGX_CPUID, 0x0, eax, ebx, ecx, edx);94 95 return eax & 0x2;96}97 98static unsigned long elf_sym_hash(const char *name)99{100 unsigned long h = 0, high;101 102 while (*name) {103 h = (h << 4) + *name++;104 high = h & 0xf0000000;105 106 if (high)107 h ^= high >> 24;108 109 h &= ~high;110 }111 112 return h;113}114 115static Elf64_Sym *vdso_symtab_get(struct vdso_symtab *symtab, const char *name)116{117 Elf64_Word bucketnum = symtab->elf_hashtab[0];118 Elf64_Word *buckettab = &symtab->elf_hashtab[2];119 Elf64_Word *chaintab = &symtab->elf_hashtab[2 + bucketnum];120 Elf64_Sym *sym;121 Elf64_Word i;122 123 for (i = buckettab[elf_sym_hash(name) % bucketnum]; i != STN_UNDEF;124 i = chaintab[i]) {125 sym = &symtab->elf_symtab[i];126 if (!strcmp(name, &symtab->elf_symstrtab[sym->st_name]))127 return sym;128 }129 130 return NULL;131}132 133/*134 * Return the offset in the enclave where the TCS segment can be found.135 * The first RW segment loaded is the TCS.136 */137static off_t encl_get_tcs_offset(struct encl *encl)138{139 int i;140 141 for (i = 0; i < encl->nr_segments; i++) {142 struct encl_segment *seg = &encl->segment_tbl[i];143 144 if (i == 0 && seg->prot == (PROT_READ | PROT_WRITE))145 return seg->offset;146 }147 148 return -1;149}150 151/*152 * Return the offset in the enclave where the data segment can be found.153 * The first RW segment loaded is the TCS, skip that to get info on the154 * data segment.155 */156static off_t encl_get_data_offset(struct encl *encl)157{158 int i;159 160 for (i = 1; i < encl->nr_segments; i++) {161 struct encl_segment *seg = &encl->segment_tbl[i];162 163 if (seg->prot == (PROT_READ | PROT_WRITE))164 return seg->offset;165 }166 167 return -1;168}169 170FIXTURE(enclave) {171 struct encl encl;172 struct sgx_enclave_run run;173};174 175static bool setup_test_encl(unsigned long heap_size, struct encl *encl,176 struct __test_metadata *_metadata)177{178 Elf64_Sym *sgx_enter_enclave_sym = NULL;179 struct vdso_symtab symtab;180 struct encl_segment *seg;181 char maps_line[256];182 FILE *maps_file;183 unsigned int i;184 void *addr;185 186 if (!encl_load("test_encl.elf", encl, heap_size)) {187 encl_delete(encl);188 TH_LOG("Failed to load the test enclave.");189 return false;190 }191 192 if (!encl_measure(encl))193 goto err;194 195 if (!encl_build(encl))196 goto err;197 198 /*199 * An enclave consumer only must do this.200 */201 for (i = 0; i < encl->nr_segments; i++) {202 struct encl_segment *seg = &encl->segment_tbl[i];203 204 addr = mmap((void *)encl->encl_base + seg->offset, seg->size,205 seg->prot, MAP_SHARED | MAP_FIXED, encl->fd, 0);206 EXPECT_NE(addr, MAP_FAILED);207 if (addr == MAP_FAILED)208 goto err;209 }210 211 /* Get vDSO base address */212 addr = (void *)getauxval(AT_SYSINFO_EHDR);213 if (!addr)214 goto err;215 216 if (!vdso_get_symtab(addr, &symtab))217 goto err;218 219 sgx_enter_enclave_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave");220 if (!sgx_enter_enclave_sym)221 goto err;222 223 vdso_sgx_enter_enclave = addr + sgx_enter_enclave_sym->st_value;224 225 return true;226 227err:228 for (i = 0; i < encl->nr_segments; i++) {229 seg = &encl->segment_tbl[i];230 231 TH_LOG("0x%016lx 0x%016lx 0x%02x", seg->offset, seg->size, seg->prot);232 }233 234 maps_file = fopen("/proc/self/maps", "r");235 if (maps_file != NULL) {236 while (fgets(maps_line, sizeof(maps_line), maps_file) != NULL) {237 maps_line[strlen(maps_line) - 1] = '\0';238 239 if (strstr(maps_line, "/dev/sgx_enclave"))240 TH_LOG("%s", maps_line);241 }242 243 fclose(maps_file);244 }245 246 TH_LOG("Failed to initialize the test enclave.");247 248 encl_delete(encl);249 250 return false;251}252 253FIXTURE_SETUP(enclave)254{255}256 257FIXTURE_TEARDOWN(enclave)258{259 encl_delete(&self->encl);260}261 262#define ENCL_CALL(op, run, clobbered) \263 ({ \264 int ret; \265 if ((clobbered)) \266 ret = vdso_sgx_enter_enclave((unsigned long)(op), 0, 0, \267 EENTER, 0, 0, (run)); \268 else \269 ret = sgx_enter_enclave((void *)(op), NULL, 0, EENTER, NULL, NULL, \270 (run)); \271 ret; \272 })273 274#define EXPECT_EEXIT(run) \275 do { \276 EXPECT_EQ((run)->function, EEXIT); \277 if ((run)->function != EEXIT) \278 TH_LOG("0x%02x 0x%02x 0x%016llx", (run)->exception_vector, \279 (run)->exception_error_code, (run)->exception_addr); \280 } while (0)281 282TEST_F(enclave, unclobbered_vdso)283{284 struct encl_op_get_from_buf get_op;285 struct encl_op_put_to_buf put_op;286 287 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));288 289 memset(&self->run, 0, sizeof(self->run));290 self->run.tcs = self->encl.encl_base;291 292 put_op.header.type = ENCL_OP_PUT_TO_BUFFER;293 put_op.value = MAGIC;294 295 EXPECT_EQ(ENCL_CALL(&put_op, &self->run, false), 0);296 297 EXPECT_EEXIT(&self->run);298 EXPECT_EQ(self->run.user_data, 0);299 300 get_op.header.type = ENCL_OP_GET_FROM_BUFFER;301 get_op.value = 0;302 303 EXPECT_EQ(ENCL_CALL(&get_op, &self->run, false), 0);304 305 EXPECT_EQ(get_op.value, MAGIC);306 EXPECT_EEXIT(&self->run);307 EXPECT_EQ(self->run.user_data, 0);308}309 310/*311 * A section metric is concatenated in a way that @low bits 12-31 define the312 * bits 12-31 of the metric and @high bits 0-19 define the bits 32-51 of the313 * metric.314 */315static unsigned long sgx_calc_section_metric(unsigned int low,316 unsigned int high)317{318 return (low & GENMASK_ULL(31, 12)) +319 ((high & GENMASK_ULL(19, 0)) << 32);320}321 322/*323 * Sum total available physical SGX memory across all EPC sections324 *325 * Return: total available physical SGX memory available on system326 */327static unsigned long get_total_epc_mem(void)328{329 unsigned int eax, ebx, ecx, edx;330 unsigned long total_size = 0;331 unsigned int type;332 int section = 0;333 334 while (true) {335 __cpuid_count(SGX_CPUID, section + SGX_CPUID_EPC, eax, ebx, ecx, edx);336 337 type = eax & SGX_CPUID_EPC_MASK;338 if (type == SGX_CPUID_EPC_INVALID)339 break;340 341 if (type != SGX_CPUID_EPC_SECTION)342 break;343 344 total_size += sgx_calc_section_metric(ecx, edx);345 346 section++;347 }348 349 return total_size;350}351 352TEST_F(enclave, unclobbered_vdso_oversubscribed)353{354 struct encl_op_get_from_buf get_op;355 struct encl_op_put_to_buf put_op;356 unsigned long total_mem;357 358 total_mem = get_total_epc_mem();359 ASSERT_NE(total_mem, 0);360 ASSERT_TRUE(setup_test_encl(total_mem, &self->encl, _metadata));361 362 memset(&self->run, 0, sizeof(self->run));363 self->run.tcs = self->encl.encl_base;364 365 put_op.header.type = ENCL_OP_PUT_TO_BUFFER;366 put_op.value = MAGIC;367 368 EXPECT_EQ(ENCL_CALL(&put_op, &self->run, false), 0);369 370 EXPECT_EEXIT(&self->run);371 EXPECT_EQ(self->run.user_data, 0);372 373 get_op.header.type = ENCL_OP_GET_FROM_BUFFER;374 get_op.value = 0;375 376 EXPECT_EQ(ENCL_CALL(&get_op, &self->run, false), 0);377 378 EXPECT_EQ(get_op.value, MAGIC);379 EXPECT_EEXIT(&self->run);380 EXPECT_EQ(self->run.user_data, 0);381}382 383TEST_F_TIMEOUT(enclave, unclobbered_vdso_oversubscribed_remove, 900)384{385 struct sgx_enclave_remove_pages remove_ioc;386 struct sgx_enclave_modify_types modt_ioc;387 struct encl_op_get_from_buf get_op;388 struct encl_op_eaccept eaccept_op;389 struct encl_op_put_to_buf put_op;390 struct encl_segment *heap;391 unsigned long total_mem;392 int ret, errno_save;393 unsigned long addr;394 unsigned long i;395 396 /*397 * Create enclave with additional heap that is as big as all398 * available physical SGX memory.399 */400 total_mem = get_total_epc_mem();401 ASSERT_NE(total_mem, 0);402 TH_LOG("Creating an enclave with %lu bytes heap may take a while ...",403 total_mem);404 ASSERT_TRUE(setup_test_encl(total_mem, &self->encl, _metadata));405 406 /*407 * Hardware (SGX2) and kernel support is needed for this test. Start408 * with check that test has a chance of succeeding.409 */410 memset(&modt_ioc, 0, sizeof(modt_ioc));411 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);412 413 if (ret == -1) {414 if (errno == ENOTTY)415 SKIP(return,416 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");417 else if (errno == ENODEV)418 SKIP(return, "System does not support SGX2");419 }420 421 /*422 * Invalid parameters were provided during sanity check,423 * expect command to fail.424 */425 EXPECT_EQ(ret, -1);426 427 /* SGX2 is supported by kernel and hardware, test can proceed. */428 memset(&self->run, 0, sizeof(self->run));429 self->run.tcs = self->encl.encl_base;430 431 heap = &self->encl.segment_tbl[self->encl.nr_segments - 1];432 433 put_op.header.type = ENCL_OP_PUT_TO_BUFFER;434 put_op.value = MAGIC;435 436 EXPECT_EQ(ENCL_CALL(&put_op, &self->run, false), 0);437 438 EXPECT_EEXIT(&self->run);439 EXPECT_EQ(self->run.user_data, 0);440 441 get_op.header.type = ENCL_OP_GET_FROM_BUFFER;442 get_op.value = 0;443 444 EXPECT_EQ(ENCL_CALL(&get_op, &self->run, false), 0);445 446 EXPECT_EQ(get_op.value, MAGIC);447 EXPECT_EEXIT(&self->run);448 EXPECT_EQ(self->run.user_data, 0);449 450 /* Trim entire heap. */451 memset(&modt_ioc, 0, sizeof(modt_ioc));452 453 modt_ioc.offset = heap->offset;454 modt_ioc.length = heap->size;455 modt_ioc.page_type = SGX_PAGE_TYPE_TRIM;456 457 TH_LOG("Changing type of %zd bytes to trimmed may take a while ...",458 heap->size);459 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);460 errno_save = ret == -1 ? errno : 0;461 462 EXPECT_EQ(ret, 0);463 EXPECT_EQ(errno_save, 0);464 EXPECT_EQ(modt_ioc.result, 0);465 EXPECT_EQ(modt_ioc.count, heap->size);466 467 /* EACCEPT all removed pages. */468 addr = self->encl.encl_base + heap->offset;469 470 eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED;471 eaccept_op.header.type = ENCL_OP_EACCEPT;472 473 TH_LOG("Entering enclave to run EACCEPT for each page of %zd bytes may take a while ...",474 heap->size);475 for (i = 0; i < heap->size; i += 4096) {476 eaccept_op.epc_addr = addr + i;477 eaccept_op.ret = 0;478 479 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);480 481 EXPECT_EQ(self->run.exception_vector, 0);482 EXPECT_EQ(self->run.exception_error_code, 0);483 EXPECT_EQ(self->run.exception_addr, 0);484 ASSERT_EQ(eaccept_op.ret, 0);485 ASSERT_EQ(self->run.function, EEXIT);486 }487 488 /* Complete page removal. */489 memset(&remove_ioc, 0, sizeof(remove_ioc));490 491 remove_ioc.offset = heap->offset;492 remove_ioc.length = heap->size;493 494 TH_LOG("Removing %zd bytes from enclave may take a while ...",495 heap->size);496 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc);497 errno_save = ret == -1 ? errno : 0;498 499 EXPECT_EQ(ret, 0);500 EXPECT_EQ(errno_save, 0);501 EXPECT_EQ(remove_ioc.count, heap->size);502}503 504TEST_F(enclave, clobbered_vdso)505{506 struct encl_op_get_from_buf get_op;507 struct encl_op_put_to_buf put_op;508 509 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));510 511 memset(&self->run, 0, sizeof(self->run));512 self->run.tcs = self->encl.encl_base;513 514 put_op.header.type = ENCL_OP_PUT_TO_BUFFER;515 put_op.value = MAGIC;516 517 EXPECT_EQ(ENCL_CALL(&put_op, &self->run, true), 0);518 519 EXPECT_EEXIT(&self->run);520 EXPECT_EQ(self->run.user_data, 0);521 522 get_op.header.type = ENCL_OP_GET_FROM_BUFFER;523 get_op.value = 0;524 525 EXPECT_EQ(ENCL_CALL(&get_op, &self->run, true), 0);526 527 EXPECT_EQ(get_op.value, MAGIC);528 EXPECT_EEXIT(&self->run);529 EXPECT_EQ(self->run.user_data, 0);530}531 532static int test_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9,533 struct sgx_enclave_run *run)534{535 run->user_data = 0;536 537 return 0;538}539 540TEST_F(enclave, clobbered_vdso_and_user_function)541{542 struct encl_op_get_from_buf get_op;543 struct encl_op_put_to_buf put_op;544 545 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));546 547 memset(&self->run, 0, sizeof(self->run));548 self->run.tcs = self->encl.encl_base;549 550 self->run.user_handler = (__u64)test_handler;551 self->run.user_data = 0xdeadbeef;552 553 put_op.header.type = ENCL_OP_PUT_TO_BUFFER;554 put_op.value = MAGIC;555 556 EXPECT_EQ(ENCL_CALL(&put_op, &self->run, true), 0);557 558 EXPECT_EEXIT(&self->run);559 EXPECT_EQ(self->run.user_data, 0);560 561 get_op.header.type = ENCL_OP_GET_FROM_BUFFER;562 get_op.value = 0;563 564 EXPECT_EQ(ENCL_CALL(&get_op, &self->run, true), 0);565 566 EXPECT_EQ(get_op.value, MAGIC);567 EXPECT_EEXIT(&self->run);568 EXPECT_EQ(self->run.user_data, 0);569}570 571/*572 * Sanity check that it is possible to enter either of the two hardcoded TCS573 */574TEST_F(enclave, tcs_entry)575{576 struct encl_op_header op;577 578 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));579 580 memset(&self->run, 0, sizeof(self->run));581 self->run.tcs = self->encl.encl_base;582 583 op.type = ENCL_OP_NOP;584 585 EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);586 587 EXPECT_EEXIT(&self->run);588 EXPECT_EQ(self->run.exception_vector, 0);589 EXPECT_EQ(self->run.exception_error_code, 0);590 EXPECT_EQ(self->run.exception_addr, 0);591 592 /* Move to the next TCS. */593 self->run.tcs = self->encl.encl_base + PAGE_SIZE;594 595 EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);596 597 EXPECT_EEXIT(&self->run);598 EXPECT_EQ(self->run.exception_vector, 0);599 EXPECT_EQ(self->run.exception_error_code, 0);600 EXPECT_EQ(self->run.exception_addr, 0);601}602 603/*604 * Second page of .data segment is used to test changing PTE permissions.605 * This spans the local encl_buffer within the test enclave.606 *607 * 1) Start with a sanity check: a value is written to the target page within608 * the enclave and read back to ensure target page can be written to.609 * 2) Change PTE permissions (RW -> RO) of target page within enclave.610 * 3) Repeat (1) - this time expecting a regular #PF communicated via the611 * vDSO.612 * 4) Change PTE permissions of target page within enclave back to be RW.613 * 5) Repeat (1) by resuming enclave, now expected to be possible to write to614 * and read from target page within enclave.615 */616TEST_F(enclave, pte_permissions)617{618 struct encl_op_get_from_addr get_addr_op;619 struct encl_op_put_to_addr put_addr_op;620 unsigned long data_start;621 int ret;622 623 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));624 625 memset(&self->run, 0, sizeof(self->run));626 self->run.tcs = self->encl.encl_base;627 628 data_start = self->encl.encl_base +629 encl_get_data_offset(&self->encl) +630 PAGE_SIZE;631 632 /*633 * Sanity check to ensure it is possible to write to page that will634 * have its permissions manipulated.635 */636 637 /* Write MAGIC to page */638 put_addr_op.value = MAGIC;639 put_addr_op.addr = data_start;640 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;641 642 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);643 644 EXPECT_EEXIT(&self->run);645 EXPECT_EQ(self->run.exception_vector, 0);646 EXPECT_EQ(self->run.exception_error_code, 0);647 EXPECT_EQ(self->run.exception_addr, 0);648 649 /*650 * Read memory that was just written to, confirming that it is the651 * value previously written (MAGIC).652 */653 get_addr_op.value = 0;654 get_addr_op.addr = data_start;655 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;656 657 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);658 659 EXPECT_EQ(get_addr_op.value, MAGIC);660 EXPECT_EEXIT(&self->run);661 EXPECT_EQ(self->run.exception_vector, 0);662 EXPECT_EQ(self->run.exception_error_code, 0);663 EXPECT_EQ(self->run.exception_addr, 0);664 665 /* Change PTE permissions of target page within the enclave */666 ret = mprotect((void *)data_start, PAGE_SIZE, PROT_READ);667 if (ret)668 perror("mprotect");669 670 /*671 * PTE permissions of target page changed to read-only, EPCM672 * permissions unchanged (EPCM permissions are RW), attempt to673 * write to the page, expecting a regular #PF.674 */675 676 put_addr_op.value = MAGIC2;677 678 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);679 680 EXPECT_EQ(self->run.exception_vector, 14);681 EXPECT_EQ(self->run.exception_error_code, 0x7);682 EXPECT_EQ(self->run.exception_addr, data_start);683 684 self->run.exception_vector = 0;685 self->run.exception_error_code = 0;686 self->run.exception_addr = 0;687 688 /*689 * Change PTE permissions back to enable enclave to write to the690 * target page and resume enclave - do not expect any exceptions this691 * time.692 */693 ret = mprotect((void *)data_start, PAGE_SIZE, PROT_READ | PROT_WRITE);694 if (ret)695 perror("mprotect");696 697 EXPECT_EQ(vdso_sgx_enter_enclave((unsigned long)&put_addr_op, 0,698 0, ERESUME, 0, 0, &self->run),699 0);700 701 EXPECT_EEXIT(&self->run);702 EXPECT_EQ(self->run.exception_vector, 0);703 EXPECT_EQ(self->run.exception_error_code, 0);704 EXPECT_EQ(self->run.exception_addr, 0);705 706 get_addr_op.value = 0;707 708 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);709 710 EXPECT_EQ(get_addr_op.value, MAGIC2);711 EXPECT_EEXIT(&self->run);712 EXPECT_EQ(self->run.exception_vector, 0);713 EXPECT_EQ(self->run.exception_error_code, 0);714 EXPECT_EQ(self->run.exception_addr, 0);715}716 717/*718 * Modifying permissions of TCS page should not be possible.719 */720TEST_F(enclave, tcs_permissions)721{722 struct sgx_enclave_restrict_permissions ioc;723 int ret, errno_save;724 725 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));726 727 memset(&self->run, 0, sizeof(self->run));728 self->run.tcs = self->encl.encl_base;729 730 memset(&ioc, 0, sizeof(ioc));731 732 /*733 * Ensure kernel supports needed ioctl() and system supports needed734 * commands.735 */736 737 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, &ioc);738 errno_save = ret == -1 ? errno : 0;739 740 /*741 * Invalid parameters were provided during sanity check,742 * expect command to fail.743 */744 ASSERT_EQ(ret, -1);745 746 /* ret == -1 */747 if (errno_save == ENOTTY)748 SKIP(return,749 "Kernel does not support SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS ioctl()");750 else if (errno_save == ENODEV)751 SKIP(return, "System does not support SGX2");752 753 /*754 * Attempt to make TCS page read-only. This is not allowed and755 * should be prevented by the kernel.756 */757 ioc.offset = encl_get_tcs_offset(&self->encl);758 ioc.length = PAGE_SIZE;759 ioc.permissions = SGX_SECINFO_R;760 761 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, &ioc);762 errno_save = ret == -1 ? errno : 0;763 764 EXPECT_EQ(ret, -1);765 EXPECT_EQ(errno_save, EINVAL);766 EXPECT_EQ(ioc.result, 0);767 EXPECT_EQ(ioc.count, 0);768}769 770/*771 * Enclave page permission test.772 *773 * Modify and restore enclave page's EPCM (enclave) permissions from774 * outside enclave (ENCLS[EMODPR] via kernel) as well as from within775 * enclave (via ENCLU[EMODPE]). Check for page fault if776 * VMA allows access but EPCM permissions do not.777 */778TEST_F(enclave, epcm_permissions)779{780 struct sgx_enclave_restrict_permissions restrict_ioc;781 struct encl_op_get_from_addr get_addr_op;782 struct encl_op_put_to_addr put_addr_op;783 struct encl_op_eaccept eaccept_op;784 struct encl_op_emodpe emodpe_op;785 unsigned long data_start;786 int ret, errno_save;787 788 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));789 790 memset(&self->run, 0, sizeof(self->run));791 self->run.tcs = self->encl.encl_base;792 793 /*794 * Ensure kernel supports needed ioctl() and system supports needed795 * commands.796 */797 memset(&restrict_ioc, 0, sizeof(restrict_ioc));798 799 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS,800 &restrict_ioc);801 errno_save = ret == -1 ? errno : 0;802 803 /*804 * Invalid parameters were provided during sanity check,805 * expect command to fail.806 */807 ASSERT_EQ(ret, -1);808 809 /* ret == -1 */810 if (errno_save == ENOTTY)811 SKIP(return,812 "Kernel does not support SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS ioctl()");813 else if (errno_save == ENODEV)814 SKIP(return, "System does not support SGX2");815 816 /*817 * Page that will have its permissions changed is the second data818 * page in the .data segment. This forms part of the local encl_buffer819 * within the enclave.820 *821 * At start of test @data_start should have EPCM as well as PTE and822 * VMA permissions of RW.823 */824 825 data_start = self->encl.encl_base +826 encl_get_data_offset(&self->encl) + PAGE_SIZE;827 828 /*829 * Sanity check that page at @data_start is writable before making830 * any changes to page permissions.831 *832 * Start by writing MAGIC to test page.833 */834 put_addr_op.value = MAGIC;835 put_addr_op.addr = data_start;836 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;837 838 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);839 840 EXPECT_EEXIT(&self->run);841 EXPECT_EQ(self->run.exception_vector, 0);842 EXPECT_EQ(self->run.exception_error_code, 0);843 EXPECT_EQ(self->run.exception_addr, 0);844 845 /*846 * Read memory that was just written to, confirming that847 * page is writable.848 */849 get_addr_op.value = 0;850 get_addr_op.addr = data_start;851 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;852 853 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);854 855 EXPECT_EQ(get_addr_op.value, MAGIC);856 EXPECT_EEXIT(&self->run);857 EXPECT_EQ(self->run.exception_vector, 0);858 EXPECT_EQ(self->run.exception_error_code, 0);859 EXPECT_EQ(self->run.exception_addr, 0);860 861 /*862 * Change EPCM permissions to read-only. Kernel still considers863 * the page writable.864 */865 memset(&restrict_ioc, 0, sizeof(restrict_ioc));866 867 restrict_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;868 restrict_ioc.length = PAGE_SIZE;869 restrict_ioc.permissions = SGX_SECINFO_R;870 871 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS,872 &restrict_ioc);873 errno_save = ret == -1 ? errno : 0;874 875 EXPECT_EQ(ret, 0);876 EXPECT_EQ(errno_save, 0);877 EXPECT_EQ(restrict_ioc.result, 0);878 EXPECT_EQ(restrict_ioc.count, 4096);879 880 /*881 * EPCM permissions changed from kernel, need to EACCEPT from enclave.882 */883 eaccept_op.epc_addr = data_start;884 eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_REG | SGX_SECINFO_PR;885 eaccept_op.ret = 0;886 eaccept_op.header.type = ENCL_OP_EACCEPT;887 888 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);889 890 EXPECT_EEXIT(&self->run);891 EXPECT_EQ(self->run.exception_vector, 0);892 EXPECT_EQ(self->run.exception_error_code, 0);893 EXPECT_EQ(self->run.exception_addr, 0);894 EXPECT_EQ(eaccept_op.ret, 0);895 896 /*897 * EPCM permissions of page is now read-only, expect #PF898 * on EPCM when attempting to write to page from within enclave.899 */900 put_addr_op.value = MAGIC2;901 902 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);903 904 EXPECT_EQ(self->run.function, ERESUME);905 EXPECT_EQ(self->run.exception_vector, 14);906 EXPECT_EQ(self->run.exception_error_code, 0x8007);907 EXPECT_EQ(self->run.exception_addr, data_start);908 909 self->run.exception_vector = 0;910 self->run.exception_error_code = 0;911 self->run.exception_addr = 0;912 913 /*914 * Received AEX but cannot return to enclave at same entrypoint,915 * need different TCS from where EPCM permission can be made writable916 * again.917 */918 self->run.tcs = self->encl.encl_base + PAGE_SIZE;919 920 /*921 * Enter enclave at new TCS to change EPCM permissions to be922 * writable again and thus fix the page fault that triggered the923 * AEX.924 */925 926 emodpe_op.epc_addr = data_start;927 emodpe_op.flags = SGX_SECINFO_R | SGX_SECINFO_W;928 emodpe_op.header.type = ENCL_OP_EMODPE;929 930 EXPECT_EQ(ENCL_CALL(&emodpe_op, &self->run, true), 0);931 932 EXPECT_EEXIT(&self->run);933 EXPECT_EQ(self->run.exception_vector, 0);934 EXPECT_EQ(self->run.exception_error_code, 0);935 EXPECT_EQ(self->run.exception_addr, 0);936 937 /*938 * Attempt to return to main TCS to resume execution at faulting939 * instruction, PTE should continue to allow writing to the page.940 */941 self->run.tcs = self->encl.encl_base;942 943 /*944 * Wrong page permissions that caused original fault has945 * now been fixed via EPCM permissions.946 * Resume execution in main TCS to re-attempt the memory access.947 */948 self->run.tcs = self->encl.encl_base;949 950 EXPECT_EQ(vdso_sgx_enter_enclave((unsigned long)&put_addr_op, 0, 0,951 ERESUME, 0, 0,952 &self->run),953 0);954 955 EXPECT_EEXIT(&self->run);956 EXPECT_EQ(self->run.exception_vector, 0);957 EXPECT_EQ(self->run.exception_error_code, 0);958 EXPECT_EQ(self->run.exception_addr, 0);959 960 get_addr_op.value = 0;961 962 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);963 964 EXPECT_EQ(get_addr_op.value, MAGIC2);965 EXPECT_EEXIT(&self->run);966 EXPECT_EQ(self->run.user_data, 0);967 EXPECT_EQ(self->run.exception_vector, 0);968 EXPECT_EQ(self->run.exception_error_code, 0);969 EXPECT_EQ(self->run.exception_addr, 0);970}971 972/*973 * Test the addition of pages to an initialized enclave via writing to974 * a page belonging to the enclave's address space but was not added975 * during enclave creation.976 */977TEST_F(enclave, augment)978{979 struct encl_op_get_from_addr get_addr_op;980 struct encl_op_put_to_addr put_addr_op;981 struct encl_op_eaccept eaccept_op;982 size_t total_size = 0;983 void *addr;984 int i;985 986 if (!sgx2_supported())987 SKIP(return, "SGX2 not supported");988 989 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));990 991 memset(&self->run, 0, sizeof(self->run));992 self->run.tcs = self->encl.encl_base;993 994 for (i = 0; i < self->encl.nr_segments; i++) {995 struct encl_segment *seg = &self->encl.segment_tbl[i];996 997 total_size += seg->size;998 }999 1000 /*1001 * Actual enclave size is expected to be larger than the loaded1002 * test enclave since enclave size must be a power of 2 in bytes1003 * and test_encl does not consume it all.1004 */1005 EXPECT_LT(total_size + PAGE_SIZE, self->encl.encl_size);1006 1007 /*1008 * Create memory mapping for the page that will be added. New1009 * memory mapping is for one page right after all existing1010 * mappings.1011 * Kernel will allow new mapping using any permissions if it1012 * falls into the enclave's address range but not backed1013 * by existing enclave pages.1014 */1015 addr = mmap((void *)self->encl.encl_base + total_size, PAGE_SIZE,1016 PROT_READ | PROT_WRITE | PROT_EXEC,1017 MAP_SHARED | MAP_FIXED, self->encl.fd, 0);1018 EXPECT_NE(addr, MAP_FAILED);1019 1020 self->run.exception_vector = 0;1021 self->run.exception_error_code = 0;1022 self->run.exception_addr = 0;1023 1024 /*1025 * Attempt to write to the new page from within enclave.1026 * Expected to fail since page is not (yet) part of the enclave.1027 * The first #PF will trigger the addition of the page to the1028 * enclave, but since the new page needs an EACCEPT from within the1029 * enclave before it can be used it would not be possible1030 * to successfully return to the failing instruction. This is the1031 * cause of the second #PF captured here having the SGX bit set,1032 * it is from hardware preventing the page from being used.1033 */1034 put_addr_op.value = MAGIC;1035 put_addr_op.addr = (unsigned long)addr;1036 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;1037 1038 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);1039 1040 EXPECT_EQ(self->run.function, ERESUME);1041 EXPECT_EQ(self->run.exception_vector, 14);1042 EXPECT_EQ(self->run.exception_addr, (unsigned long)addr);1043 1044 if (self->run.exception_error_code == 0x6) {1045 munmap(addr, PAGE_SIZE);1046 SKIP(return, "Kernel does not support adding pages to initialized enclave");1047 }1048 1049 EXPECT_EQ(self->run.exception_error_code, 0x8007);1050 1051 self->run.exception_vector = 0;1052 self->run.exception_error_code = 0;1053 self->run.exception_addr = 0;1054 1055 /* Handle AEX by running EACCEPT from new entry point. */1056 self->run.tcs = self->encl.encl_base + PAGE_SIZE;1057 1058 eaccept_op.epc_addr = self->encl.encl_base + total_size;1059 eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING;1060 eaccept_op.ret = 0;1061 eaccept_op.header.type = ENCL_OP_EACCEPT;1062 1063 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1064 1065 EXPECT_EEXIT(&self->run);1066 EXPECT_EQ(self->run.exception_vector, 0);1067 EXPECT_EQ(self->run.exception_error_code, 0);1068 EXPECT_EQ(self->run.exception_addr, 0);1069 EXPECT_EQ(eaccept_op.ret, 0);1070 1071 /* Can now return to main TCS to resume execution. */1072 self->run.tcs = self->encl.encl_base;1073 1074 EXPECT_EQ(vdso_sgx_enter_enclave((unsigned long)&put_addr_op, 0, 0,1075 ERESUME, 0, 0,1076 &self->run),1077 0);1078 1079 EXPECT_EEXIT(&self->run);1080 EXPECT_EQ(self->run.exception_vector, 0);1081 EXPECT_EQ(self->run.exception_error_code, 0);1082 EXPECT_EQ(self->run.exception_addr, 0);1083 1084 /*1085 * Read memory from newly added page that was just written to,1086 * confirming that data previously written (MAGIC) is present.1087 */1088 get_addr_op.value = 0;1089 get_addr_op.addr = (unsigned long)addr;1090 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;1091 1092 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);1093 1094 EXPECT_EQ(get_addr_op.value, MAGIC);1095 EXPECT_EEXIT(&self->run);1096 EXPECT_EQ(self->run.exception_vector, 0);1097 EXPECT_EQ(self->run.exception_error_code, 0);1098 EXPECT_EQ(self->run.exception_addr, 0);1099 1100 munmap(addr, PAGE_SIZE);1101}1102 1103/*1104 * Test for the addition of pages to an initialized enclave via a1105 * pre-emptive run of EACCEPT on page to be added.1106 */1107TEST_F(enclave, augment_via_eaccept)1108{1109 struct encl_op_get_from_addr get_addr_op;1110 struct encl_op_put_to_addr put_addr_op;1111 struct encl_op_eaccept eaccept_op;1112 size_t total_size = 0;1113 void *addr;1114 int i;1115 1116 if (!sgx2_supported())1117 SKIP(return, "SGX2 not supported");1118 1119 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));1120 1121 memset(&self->run, 0, sizeof(self->run));1122 self->run.tcs = self->encl.encl_base;1123 1124 for (i = 0; i < self->encl.nr_segments; i++) {1125 struct encl_segment *seg = &self->encl.segment_tbl[i];1126 1127 total_size += seg->size;1128 }1129 1130 /*1131 * Actual enclave size is expected to be larger than the loaded1132 * test enclave since enclave size must be a power of 2 in bytes while1133 * test_encl does not consume it all.1134 */1135 EXPECT_LT(total_size + PAGE_SIZE, self->encl.encl_size);1136 1137 /*1138 * mmap() a page at end of existing enclave to be used for dynamic1139 * EPC page.1140 *1141 * Kernel will allow new mapping using any permissions if it1142 * falls into the enclave's address range but not backed1143 * by existing enclave pages.1144 */1145 1146 addr = mmap((void *)self->encl.encl_base + total_size, PAGE_SIZE,1147 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED,1148 self->encl.fd, 0);1149 EXPECT_NE(addr, MAP_FAILED);1150 1151 self->run.exception_vector = 0;1152 self->run.exception_error_code = 0;1153 self->run.exception_addr = 0;1154 1155 /*1156 * Run EACCEPT on new page to trigger the #PF->EAUG->EACCEPT(again1157 * without a #PF). All should be transparent to userspace.1158 */1159 eaccept_op.epc_addr = self->encl.encl_base + total_size;1160 eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING;1161 eaccept_op.ret = 0;1162 eaccept_op.header.type = ENCL_OP_EACCEPT;1163 1164 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1165 1166 if (self->run.exception_vector == 14 &&1167 self->run.exception_error_code == 4 &&1168 self->run.exception_addr == self->encl.encl_base + total_size) {1169 munmap(addr, PAGE_SIZE);1170 SKIP(return, "Kernel does not support adding pages to initialized enclave");1171 }1172 1173 EXPECT_EEXIT(&self->run);1174 EXPECT_EQ(self->run.exception_vector, 0);1175 EXPECT_EQ(self->run.exception_error_code, 0);1176 EXPECT_EQ(self->run.exception_addr, 0);1177 EXPECT_EQ(eaccept_op.ret, 0);1178 1179 /*1180 * New page should be accessible from within enclave - attempt to1181 * write to it.1182 */1183 put_addr_op.value = MAGIC;1184 put_addr_op.addr = (unsigned long)addr;1185 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;1186 1187 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);1188 1189 EXPECT_EEXIT(&self->run);1190 EXPECT_EQ(self->run.exception_vector, 0);1191 EXPECT_EQ(self->run.exception_error_code, 0);1192 EXPECT_EQ(self->run.exception_addr, 0);1193 1194 /*1195 * Read memory from newly added page that was just written to,1196 * confirming that data previously written (MAGIC) is present.1197 */1198 get_addr_op.value = 0;1199 get_addr_op.addr = (unsigned long)addr;1200 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;1201 1202 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);1203 1204 EXPECT_EQ(get_addr_op.value, MAGIC);1205 EXPECT_EEXIT(&self->run);1206 EXPECT_EQ(self->run.exception_vector, 0);1207 EXPECT_EQ(self->run.exception_error_code, 0);1208 EXPECT_EQ(self->run.exception_addr, 0);1209 1210 munmap(addr, PAGE_SIZE);1211}1212 1213/*1214 * SGX2 page type modification test in two phases:1215 * Phase 1:1216 * Create a new TCS, consisting out of three new pages (stack page with regular1217 * page type, SSA page with regular page type, and TCS page with TCS page1218 * type) in an initialized enclave and run a simple workload within it.1219 * Phase 2:1220 * Remove the three pages added in phase 1, add a new regular page at the1221 * same address that previously hosted the TCS page and verify that it can1222 * be modified.1223 */1224TEST_F(enclave, tcs_create)1225{1226 struct encl_op_init_tcs_page init_tcs_page_op;1227 struct sgx_enclave_remove_pages remove_ioc;1228 struct encl_op_get_from_addr get_addr_op;1229 struct sgx_enclave_modify_types modt_ioc;1230 struct encl_op_put_to_addr put_addr_op;1231 struct encl_op_get_from_buf get_buf_op;1232 struct encl_op_put_to_buf put_buf_op;1233 void *addr, *tcs, *stack_end, *ssa;1234 struct encl_op_eaccept eaccept_op;1235 size_t total_size = 0;1236 uint64_t val_64;1237 int errno_save;1238 int ret, i;1239 1240 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl,1241 _metadata));1242 1243 memset(&self->run, 0, sizeof(self->run));1244 self->run.tcs = self->encl.encl_base;1245 1246 /*1247 * Hardware (SGX2) and kernel support is needed for this test. Start1248 * with check that test has a chance of succeeding.1249 */1250 memset(&modt_ioc, 0, sizeof(modt_ioc));1251 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);1252 1253 if (ret == -1) {1254 if (errno == ENOTTY)1255 SKIP(return,1256 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");1257 else if (errno == ENODEV)1258 SKIP(return, "System does not support SGX2");1259 }1260 1261 /*1262 * Invalid parameters were provided during sanity check,1263 * expect command to fail.1264 */1265 EXPECT_EQ(ret, -1);1266 1267 /*1268 * Add three regular pages via EAUG: one will be the TCS stack, one1269 * will be the TCS SSA, and one will be the new TCS. The stack and1270 * SSA will remain as regular pages, the TCS page will need its1271 * type changed after populated with needed data.1272 */1273 for (i = 0; i < self->encl.nr_segments; i++) {1274 struct encl_segment *seg = &self->encl.segment_tbl[i];1275 1276 total_size += seg->size;1277 }1278 1279 /*1280 * Actual enclave size is expected to be larger than the loaded1281 * test enclave since enclave size must be a power of 2 in bytes while1282 * test_encl does not consume it all.1283 */1284 EXPECT_LT(total_size + 3 * PAGE_SIZE, self->encl.encl_size);1285 1286 /*1287 * mmap() three pages at end of existing enclave to be used for the1288 * three new pages.1289 */1290 addr = mmap((void *)self->encl.encl_base + total_size, 3 * PAGE_SIZE,1291 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,1292 self->encl.fd, 0);1293 EXPECT_NE(addr, MAP_FAILED);1294 1295 self->run.exception_vector = 0;1296 self->run.exception_error_code = 0;1297 self->run.exception_addr = 0;1298 1299 stack_end = (void *)self->encl.encl_base + total_size;1300 tcs = (void *)self->encl.encl_base + total_size + PAGE_SIZE;1301 ssa = (void *)self->encl.encl_base + total_size + 2 * PAGE_SIZE;1302 1303 /*1304 * Run EACCEPT on each new page to trigger the1305 * EACCEPT->(#PF)->EAUG->EACCEPT(again without a #PF) flow.1306 */1307 1308 eaccept_op.epc_addr = (unsigned long)stack_end;1309 eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING;1310 eaccept_op.ret = 0;1311 eaccept_op.header.type = ENCL_OP_EACCEPT;1312 1313 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1314 1315 if (self->run.exception_vector == 14 &&1316 self->run.exception_error_code == 4 &&1317 self->run.exception_addr == (unsigned long)stack_end) {1318 munmap(addr, 3 * PAGE_SIZE);1319 SKIP(return, "Kernel does not support adding pages to initialized enclave");1320 }1321 1322 EXPECT_EEXIT(&self->run);1323 EXPECT_EQ(self->run.exception_vector, 0);1324 EXPECT_EQ(self->run.exception_error_code, 0);1325 EXPECT_EQ(self->run.exception_addr, 0);1326 EXPECT_EQ(eaccept_op.ret, 0);1327 1328 eaccept_op.epc_addr = (unsigned long)ssa;1329 1330 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1331 1332 EXPECT_EEXIT(&self->run);1333 EXPECT_EQ(self->run.exception_vector, 0);1334 EXPECT_EQ(self->run.exception_error_code, 0);1335 EXPECT_EQ(self->run.exception_addr, 0);1336 EXPECT_EQ(eaccept_op.ret, 0);1337 1338 eaccept_op.epc_addr = (unsigned long)tcs;1339 1340 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1341 1342 EXPECT_EEXIT(&self->run);1343 EXPECT_EQ(self->run.exception_vector, 0);1344 EXPECT_EQ(self->run.exception_error_code, 0);1345 EXPECT_EQ(self->run.exception_addr, 0);1346 EXPECT_EQ(eaccept_op.ret, 0);1347 1348 /*1349 * Three new pages added to enclave. Now populate the TCS page with1350 * needed data. This should be done from within enclave. Provide1351 * the function that will do the actual data population with needed1352 * data.1353 */1354 1355 /*1356 * New TCS will use the "encl_dyn_entry" entrypoint that expects1357 * stack to begin in page before TCS page.1358 */1359 val_64 = encl_get_entry(&self->encl, "encl_dyn_entry");1360 EXPECT_NE(val_64, 0);1361 1362 init_tcs_page_op.tcs_page = (unsigned long)tcs;1363 init_tcs_page_op.ssa = (unsigned long)total_size + 2 * PAGE_SIZE;1364 init_tcs_page_op.entry = val_64;1365 init_tcs_page_op.header.type = ENCL_OP_INIT_TCS_PAGE;1366 1367 EXPECT_EQ(ENCL_CALL(&init_tcs_page_op, &self->run, true), 0);1368 1369 EXPECT_EEXIT(&self->run);1370 EXPECT_EQ(self->run.exception_vector, 0);1371 EXPECT_EQ(self->run.exception_error_code, 0);1372 EXPECT_EQ(self->run.exception_addr, 0);1373 1374 /* Change TCS page type to TCS. */1375 memset(&modt_ioc, 0, sizeof(modt_ioc));1376 1377 modt_ioc.offset = total_size + PAGE_SIZE;1378 modt_ioc.length = PAGE_SIZE;1379 modt_ioc.page_type = SGX_PAGE_TYPE_TCS;1380 1381 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);1382 errno_save = ret == -1 ? errno : 0;1383 1384 EXPECT_EQ(ret, 0);1385 EXPECT_EQ(errno_save, 0);1386 EXPECT_EQ(modt_ioc.result, 0);1387 EXPECT_EQ(modt_ioc.count, 4096);1388 1389 /* EACCEPT new TCS page from enclave. */1390 eaccept_op.epc_addr = (unsigned long)tcs;1391 eaccept_op.flags = SGX_SECINFO_TCS | SGX_SECINFO_MODIFIED;1392 eaccept_op.ret = 0;1393 eaccept_op.header.type = ENCL_OP_EACCEPT;1394 1395 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1396 1397 EXPECT_EEXIT(&self->run);1398 EXPECT_EQ(self->run.exception_vector, 0);1399 EXPECT_EQ(self->run.exception_error_code, 0);1400 EXPECT_EQ(self->run.exception_addr, 0);1401 EXPECT_EQ(eaccept_op.ret, 0);1402 1403 /* Run workload from new TCS. */1404 self->run.tcs = (unsigned long)tcs;1405 1406 /*1407 * Simple workload to write to data buffer and read value back.1408 */1409 put_buf_op.header.type = ENCL_OP_PUT_TO_BUFFER;1410 put_buf_op.value = MAGIC;1411 1412 EXPECT_EQ(ENCL_CALL(&put_buf_op, &self->run, true), 0);1413 1414 EXPECT_EEXIT(&self->run);1415 EXPECT_EQ(self->run.exception_vector, 0);1416 EXPECT_EQ(self->run.exception_error_code, 0);1417 EXPECT_EQ(self->run.exception_addr, 0);1418 1419 get_buf_op.header.type = ENCL_OP_GET_FROM_BUFFER;1420 get_buf_op.value = 0;1421 1422 EXPECT_EQ(ENCL_CALL(&get_buf_op, &self->run, true), 0);1423 1424 EXPECT_EQ(get_buf_op.value, MAGIC);1425 EXPECT_EEXIT(&self->run);1426 EXPECT_EQ(self->run.exception_vector, 0);1427 EXPECT_EQ(self->run.exception_error_code, 0);1428 EXPECT_EQ(self->run.exception_addr, 0);1429 1430 /*1431 * Phase 2 of test:1432 * Remove pages associated with new TCS, create a regular page1433 * where TCS page used to be and verify it can be used as a regular1434 * page.1435 */1436 1437 /* Start page removal by requesting change of page type to PT_TRIM. */1438 memset(&modt_ioc, 0, sizeof(modt_ioc));1439 1440 modt_ioc.offset = total_size;1441 modt_ioc.length = 3 * PAGE_SIZE;1442 modt_ioc.page_type = SGX_PAGE_TYPE_TRIM;1443 1444 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);1445 errno_save = ret == -1 ? errno : 0;1446 1447 EXPECT_EQ(ret, 0);1448 EXPECT_EQ(errno_save, 0);1449 EXPECT_EQ(modt_ioc.result, 0);1450 EXPECT_EQ(modt_ioc.count, 3 * PAGE_SIZE);1451 1452 /*1453 * Enter enclave via TCS #1 and approve page removal by sending1454 * EACCEPT for each of three removed pages.1455 */1456 self->run.tcs = self->encl.encl_base;1457 1458 eaccept_op.epc_addr = (unsigned long)stack_end;1459 eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED;1460 eaccept_op.ret = 0;1461 eaccept_op.header.type = ENCL_OP_EACCEPT;1462 1463 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1464 1465 EXPECT_EEXIT(&self->run);1466 EXPECT_EQ(self->run.exception_vector, 0);1467 EXPECT_EQ(self->run.exception_error_code, 0);1468 EXPECT_EQ(self->run.exception_addr, 0);1469 EXPECT_EQ(eaccept_op.ret, 0);1470 1471 eaccept_op.epc_addr = (unsigned long)tcs;1472 eaccept_op.ret = 0;1473 1474 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1475 1476 EXPECT_EEXIT(&self->run);1477 EXPECT_EQ(self->run.exception_vector, 0);1478 EXPECT_EQ(self->run.exception_error_code, 0);1479 EXPECT_EQ(self->run.exception_addr, 0);1480 EXPECT_EQ(eaccept_op.ret, 0);1481 1482 eaccept_op.epc_addr = (unsigned long)ssa;1483 eaccept_op.ret = 0;1484 1485 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1486 1487 EXPECT_EEXIT(&self->run);1488 EXPECT_EQ(self->run.exception_vector, 0);1489 EXPECT_EQ(self->run.exception_error_code, 0);1490 EXPECT_EQ(self->run.exception_addr, 0);1491 EXPECT_EQ(eaccept_op.ret, 0);1492 1493 /* Send final ioctl() to complete page removal. */1494 memset(&remove_ioc, 0, sizeof(remove_ioc));1495 1496 remove_ioc.offset = total_size;1497 remove_ioc.length = 3 * PAGE_SIZE;1498 1499 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc);1500 errno_save = ret == -1 ? errno : 0;1501 1502 EXPECT_EQ(ret, 0);1503 EXPECT_EQ(errno_save, 0);1504 EXPECT_EQ(remove_ioc.count, 3 * PAGE_SIZE);1505 1506 /*1507 * Enter enclave via TCS #1 and access location where TCS #3 was to1508 * trigger dynamic add of regular page at that location.1509 */1510 eaccept_op.epc_addr = (unsigned long)tcs;1511 eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING;1512 eaccept_op.ret = 0;1513 eaccept_op.header.type = ENCL_OP_EACCEPT;1514 1515 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1516 1517 EXPECT_EEXIT(&self->run);1518 EXPECT_EQ(self->run.exception_vector, 0);1519 EXPECT_EQ(self->run.exception_error_code, 0);1520 EXPECT_EQ(self->run.exception_addr, 0);1521 EXPECT_EQ(eaccept_op.ret, 0);1522 1523 /*1524 * New page should be accessible from within enclave - write to it.1525 */1526 put_addr_op.value = MAGIC;1527 put_addr_op.addr = (unsigned long)tcs;1528 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;1529 1530 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);1531 1532 EXPECT_EEXIT(&self->run);1533 EXPECT_EQ(self->run.exception_vector, 0);1534 EXPECT_EQ(self->run.exception_error_code, 0);1535 EXPECT_EQ(self->run.exception_addr, 0);1536 1537 /*1538 * Read memory from newly added page that was just written to,1539 * confirming that data previously written (MAGIC) is present.1540 */1541 get_addr_op.value = 0;1542 get_addr_op.addr = (unsigned long)tcs;1543 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;1544 1545 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);1546 1547 EXPECT_EQ(get_addr_op.value, MAGIC);1548 EXPECT_EEXIT(&self->run);1549 EXPECT_EQ(self->run.exception_vector, 0);1550 EXPECT_EQ(self->run.exception_error_code, 0);1551 EXPECT_EQ(self->run.exception_addr, 0);1552 1553 munmap(addr, 3 * PAGE_SIZE);1554}1555 1556/*1557 * Ensure sane behavior if user requests page removal, does not run1558 * EACCEPT from within enclave but still attempts to finalize page removal1559 * with the SGX_IOC_ENCLAVE_REMOVE_PAGES ioctl(). The latter should fail1560 * because the removal was not EACCEPTed from within the enclave.1561 */1562TEST_F(enclave, remove_added_page_no_eaccept)1563{1564 struct sgx_enclave_remove_pages remove_ioc;1565 struct encl_op_get_from_addr get_addr_op;1566 struct sgx_enclave_modify_types modt_ioc;1567 struct encl_op_put_to_addr put_addr_op;1568 unsigned long data_start;1569 int ret, errno_save;1570 1571 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));1572 1573 memset(&self->run, 0, sizeof(self->run));1574 self->run.tcs = self->encl.encl_base;1575 1576 /*1577 * Hardware (SGX2) and kernel support is needed for this test. Start1578 * with check that test has a chance of succeeding.1579 */1580 memset(&modt_ioc, 0, sizeof(modt_ioc));1581 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);1582 1583 if (ret == -1) {1584 if (errno == ENOTTY)1585 SKIP(return,1586 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");1587 else if (errno == ENODEV)1588 SKIP(return, "System does not support SGX2");1589 }1590 1591 /*1592 * Invalid parameters were provided during sanity check,1593 * expect command to fail.1594 */1595 EXPECT_EQ(ret, -1);1596 1597 /*1598 * Page that will be removed is the second data page in the .data1599 * segment. This forms part of the local encl_buffer within the1600 * enclave.1601 */1602 data_start = self->encl.encl_base +1603 encl_get_data_offset(&self->encl) + PAGE_SIZE;1604 1605 /*1606 * Sanity check that page at @data_start is writable before1607 * removing it.1608 *1609 * Start by writing MAGIC to test page.1610 */1611 put_addr_op.value = MAGIC;1612 put_addr_op.addr = data_start;1613 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;1614 1615 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);1616 1617 EXPECT_EEXIT(&self->run);1618 EXPECT_EQ(self->run.exception_vector, 0);1619 EXPECT_EQ(self->run.exception_error_code, 0);1620 EXPECT_EQ(self->run.exception_addr, 0);1621 1622 /*1623 * Read memory that was just written to, confirming that data1624 * previously written (MAGIC) is present.1625 */1626 get_addr_op.value = 0;1627 get_addr_op.addr = data_start;1628 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;1629 1630 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);1631 1632 EXPECT_EQ(get_addr_op.value, MAGIC);1633 EXPECT_EEXIT(&self->run);1634 EXPECT_EQ(self->run.exception_vector, 0);1635 EXPECT_EQ(self->run.exception_error_code, 0);1636 EXPECT_EQ(self->run.exception_addr, 0);1637 1638 /* Start page removal by requesting change of page type to PT_TRIM */1639 memset(&modt_ioc, 0, sizeof(modt_ioc));1640 1641 modt_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;1642 modt_ioc.length = PAGE_SIZE;1643 modt_ioc.page_type = SGX_PAGE_TYPE_TRIM;1644 1645 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);1646 errno_save = ret == -1 ? errno : 0;1647 1648 EXPECT_EQ(ret, 0);1649 EXPECT_EQ(errno_save, 0);1650 EXPECT_EQ(modt_ioc.result, 0);1651 EXPECT_EQ(modt_ioc.count, 4096);1652 1653 /* Skip EACCEPT */1654 1655 /* Send final ioctl() to complete page removal */1656 memset(&remove_ioc, 0, sizeof(remove_ioc));1657 1658 remove_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;1659 remove_ioc.length = PAGE_SIZE;1660 1661 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc);1662 errno_save = ret == -1 ? errno : 0;1663 1664 /* Operation not permitted since EACCEPT was omitted. */1665 EXPECT_EQ(ret, -1);1666 EXPECT_EQ(errno_save, EPERM);1667 EXPECT_EQ(remove_ioc.count, 0);1668}1669 1670/*1671 * Request enclave page removal but instead of correctly following with1672 * EACCEPT a read attempt to page is made from within the enclave.1673 */1674TEST_F(enclave, remove_added_page_invalid_access)1675{1676 struct encl_op_get_from_addr get_addr_op;1677 struct encl_op_put_to_addr put_addr_op;1678 struct sgx_enclave_modify_types ioc;1679 unsigned long data_start;1680 int ret, errno_save;1681 1682 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));1683 1684 memset(&self->run, 0, sizeof(self->run));1685 self->run.tcs = self->encl.encl_base;1686 1687 /*1688 * Hardware (SGX2) and kernel support is needed for this test. Start1689 * with check that test has a chance of succeeding.1690 */1691 memset(&ioc, 0, sizeof(ioc));1692 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);1693 1694 if (ret == -1) {1695 if (errno == ENOTTY)1696 SKIP(return,1697 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");1698 else if (errno == ENODEV)1699 SKIP(return, "System does not support SGX2");1700 }1701 1702 /*1703 * Invalid parameters were provided during sanity check,1704 * expect command to fail.1705 */1706 EXPECT_EQ(ret, -1);1707 1708 /*1709 * Page that will be removed is the second data page in the .data1710 * segment. This forms part of the local encl_buffer within the1711 * enclave.1712 */1713 data_start = self->encl.encl_base +1714 encl_get_data_offset(&self->encl) + PAGE_SIZE;1715 1716 /*1717 * Sanity check that page at @data_start is writable before1718 * removing it.1719 *1720 * Start by writing MAGIC to test page.1721 */1722 put_addr_op.value = MAGIC;1723 put_addr_op.addr = data_start;1724 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;1725 1726 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);1727 1728 EXPECT_EEXIT(&self->run);1729 EXPECT_EQ(self->run.exception_vector, 0);1730 EXPECT_EQ(self->run.exception_error_code, 0);1731 EXPECT_EQ(self->run.exception_addr, 0);1732 1733 /*1734 * Read memory that was just written to, confirming that data1735 * previously written (MAGIC) is present.1736 */1737 get_addr_op.value = 0;1738 get_addr_op.addr = data_start;1739 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;1740 1741 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);1742 1743 EXPECT_EQ(get_addr_op.value, MAGIC);1744 EXPECT_EEXIT(&self->run);1745 EXPECT_EQ(self->run.exception_vector, 0);1746 EXPECT_EQ(self->run.exception_error_code, 0);1747 EXPECT_EQ(self->run.exception_addr, 0);1748 1749 /* Start page removal by requesting change of page type to PT_TRIM. */1750 memset(&ioc, 0, sizeof(ioc));1751 1752 ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;1753 ioc.length = PAGE_SIZE;1754 ioc.page_type = SGX_PAGE_TYPE_TRIM;1755 1756 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);1757 errno_save = ret == -1 ? errno : 0;1758 1759 EXPECT_EQ(ret, 0);1760 EXPECT_EQ(errno_save, 0);1761 EXPECT_EQ(ioc.result, 0);1762 EXPECT_EQ(ioc.count, 4096);1763 1764 /*1765 * Read from page that was just removed.1766 */1767 get_addr_op.value = 0;1768 1769 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);1770 1771 /*1772 * From kernel perspective the page is present but according to SGX the1773 * page should not be accessible so a #PF with SGX bit set is1774 * expected.1775 */1776 1777 EXPECT_EQ(self->run.function, ERESUME);1778 EXPECT_EQ(self->run.exception_vector, 14);1779 EXPECT_EQ(self->run.exception_error_code, 0x8005);1780 EXPECT_EQ(self->run.exception_addr, data_start);1781}1782 1783/*1784 * Request enclave page removal and correctly follow with1785 * EACCEPT but do not follow with removal ioctl() but instead a read attempt1786 * to removed page is made from within the enclave.1787 */1788TEST_F(enclave, remove_added_page_invalid_access_after_eaccept)1789{1790 struct encl_op_get_from_addr get_addr_op;1791 struct encl_op_put_to_addr put_addr_op;1792 struct sgx_enclave_modify_types ioc;1793 struct encl_op_eaccept eaccept_op;1794 unsigned long data_start;1795 int ret, errno_save;1796 1797 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));1798 1799 memset(&self->run, 0, sizeof(self->run));1800 self->run.tcs = self->encl.encl_base;1801 1802 /*1803 * Hardware (SGX2) and kernel support is needed for this test. Start1804 * with check that test has a chance of succeeding.1805 */1806 memset(&ioc, 0, sizeof(ioc));1807 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);1808 1809 if (ret == -1) {1810 if (errno == ENOTTY)1811 SKIP(return,1812 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");1813 else if (errno == ENODEV)1814 SKIP(return, "System does not support SGX2");1815 }1816 1817 /*1818 * Invalid parameters were provided during sanity check,1819 * expect command to fail.1820 */1821 EXPECT_EQ(ret, -1);1822 1823 /*1824 * Page that will be removed is the second data page in the .data1825 * segment. This forms part of the local encl_buffer within the1826 * enclave.1827 */1828 data_start = self->encl.encl_base +1829 encl_get_data_offset(&self->encl) + PAGE_SIZE;1830 1831 /*1832 * Sanity check that page at @data_start is writable before1833 * removing it.1834 *1835 * Start by writing MAGIC to test page.1836 */1837 put_addr_op.value = MAGIC;1838 put_addr_op.addr = data_start;1839 put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;1840 1841 EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);1842 1843 EXPECT_EEXIT(&self->run);1844 EXPECT_EQ(self->run.exception_vector, 0);1845 EXPECT_EQ(self->run.exception_error_code, 0);1846 EXPECT_EQ(self->run.exception_addr, 0);1847 1848 /*1849 * Read memory that was just written to, confirming that data1850 * previously written (MAGIC) is present.1851 */1852 get_addr_op.value = 0;1853 get_addr_op.addr = data_start;1854 get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;1855 1856 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);1857 1858 EXPECT_EQ(get_addr_op.value, MAGIC);1859 EXPECT_EEXIT(&self->run);1860 EXPECT_EQ(self->run.exception_vector, 0);1861 EXPECT_EQ(self->run.exception_error_code, 0);1862 EXPECT_EQ(self->run.exception_addr, 0);1863 1864 /* Start page removal by requesting change of page type to PT_TRIM. */1865 memset(&ioc, 0, sizeof(ioc));1866 1867 ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;1868 ioc.length = PAGE_SIZE;1869 ioc.page_type = SGX_PAGE_TYPE_TRIM;1870 1871 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);1872 errno_save = ret == -1 ? errno : 0;1873 1874 EXPECT_EQ(ret, 0);1875 EXPECT_EQ(errno_save, 0);1876 EXPECT_EQ(ioc.result, 0);1877 EXPECT_EQ(ioc.count, 4096);1878 1879 eaccept_op.epc_addr = (unsigned long)data_start;1880 eaccept_op.ret = 0;1881 eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED;1882 eaccept_op.header.type = ENCL_OP_EACCEPT;1883 1884 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1885 1886 EXPECT_EEXIT(&self->run);1887 EXPECT_EQ(self->run.exception_vector, 0);1888 EXPECT_EQ(self->run.exception_error_code, 0);1889 EXPECT_EQ(self->run.exception_addr, 0);1890 EXPECT_EQ(eaccept_op.ret, 0);1891 1892 /* Skip ioctl() to remove page. */1893 1894 /*1895 * Read from page that was just removed.1896 */1897 get_addr_op.value = 0;1898 1899 EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);1900 1901 /*1902 * From kernel perspective the page is present but according to SGX the1903 * page should not be accessible so a #PF with SGX bit set is1904 * expected.1905 */1906 1907 EXPECT_EQ(self->run.function, ERESUME);1908 EXPECT_EQ(self->run.exception_vector, 14);1909 EXPECT_EQ(self->run.exception_error_code, 0x8005);1910 EXPECT_EQ(self->run.exception_addr, data_start);1911}1912 1913TEST_F(enclave, remove_untouched_page)1914{1915 struct sgx_enclave_remove_pages remove_ioc;1916 struct sgx_enclave_modify_types modt_ioc;1917 struct encl_op_eaccept eaccept_op;1918 unsigned long data_start;1919 int ret, errno_save;1920 1921 ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));1922 1923 /*1924 * Hardware (SGX2) and kernel support is needed for this test. Start1925 * with check that test has a chance of succeeding.1926 */1927 memset(&modt_ioc, 0, sizeof(modt_ioc));1928 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);1929 1930 if (ret == -1) {1931 if (errno == ENOTTY)1932 SKIP(return,1933 "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");1934 else if (errno == ENODEV)1935 SKIP(return, "System does not support SGX2");1936 }1937 1938 /*1939 * Invalid parameters were provided during sanity check,1940 * expect command to fail.1941 */1942 EXPECT_EQ(ret, -1);1943 1944 /* SGX2 is supported by kernel and hardware, test can proceed. */1945 memset(&self->run, 0, sizeof(self->run));1946 self->run.tcs = self->encl.encl_base;1947 1948 data_start = self->encl.encl_base +1949 encl_get_data_offset(&self->encl) + PAGE_SIZE;1950 1951 memset(&modt_ioc, 0, sizeof(modt_ioc));1952 1953 modt_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;1954 modt_ioc.length = PAGE_SIZE;1955 modt_ioc.page_type = SGX_PAGE_TYPE_TRIM;1956 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);1957 errno_save = ret == -1 ? errno : 0;1958 1959 EXPECT_EQ(ret, 0);1960 EXPECT_EQ(errno_save, 0);1961 EXPECT_EQ(modt_ioc.result, 0);1962 EXPECT_EQ(modt_ioc.count, 4096);1963 1964 /*1965 * Enter enclave via TCS #1 and approve page removal by sending1966 * EACCEPT for removed page.1967 */1968 1969 eaccept_op.epc_addr = data_start;1970 eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED;1971 eaccept_op.ret = 0;1972 eaccept_op.header.type = ENCL_OP_EACCEPT;1973 1974 EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);1975 EXPECT_EEXIT(&self->run);1976 EXPECT_EQ(self->run.exception_vector, 0);1977 EXPECT_EQ(self->run.exception_error_code, 0);1978 EXPECT_EQ(self->run.exception_addr, 0);1979 EXPECT_EQ(eaccept_op.ret, 0);1980 1981 memset(&remove_ioc, 0, sizeof(remove_ioc));1982 1983 remove_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;1984 remove_ioc.length = PAGE_SIZE;1985 ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc);1986 errno_save = ret == -1 ? errno : 0;1987 1988 EXPECT_EQ(ret, 0);1989 EXPECT_EQ(errno_save, 0);1990 EXPECT_EQ(remove_ioc.count, 4096);1991}1992 1993TEST_HARNESS_MAIN1994