162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2016-20 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <cpuid.h> 562306a36Sopenharmony_ci#include <elf.h> 662306a36Sopenharmony_ci#include <errno.h> 762306a36Sopenharmony_ci#include <fcntl.h> 862306a36Sopenharmony_ci#include <stdbool.h> 962306a36Sopenharmony_ci#include <stdio.h> 1062306a36Sopenharmony_ci#include <stdint.h> 1162306a36Sopenharmony_ci#include <stdlib.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <unistd.h> 1462306a36Sopenharmony_ci#include <sys/ioctl.h> 1562306a36Sopenharmony_ci#include <sys/mman.h> 1662306a36Sopenharmony_ci#include <sys/stat.h> 1762306a36Sopenharmony_ci#include <sys/time.h> 1862306a36Sopenharmony_ci#include <sys/types.h> 1962306a36Sopenharmony_ci#include <sys/auxv.h> 2062306a36Sopenharmony_ci#include "defines.h" 2162306a36Sopenharmony_ci#include "../kselftest_harness.h" 2262306a36Sopenharmony_ci#include "main.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic const uint64_t MAGIC = 0x1122334455667788ULL; 2562306a36Sopenharmony_cistatic const uint64_t MAGIC2 = 0x8877665544332211ULL; 2662306a36Sopenharmony_civdso_sgx_enter_enclave_t vdso_sgx_enter_enclave; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * Security Information (SECINFO) data structure needed by a few SGX 3062306a36Sopenharmony_ci * instructions (eg. ENCLU[EACCEPT] and ENCLU[EMODPE]) holds meta-data 3162306a36Sopenharmony_ci * about an enclave page. &enum sgx_secinfo_page_state specifies the 3262306a36Sopenharmony_ci * secinfo flags used for page state. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cienum sgx_secinfo_page_state { 3562306a36Sopenharmony_ci SGX_SECINFO_PENDING = (1 << 3), 3662306a36Sopenharmony_ci SGX_SECINFO_MODIFIED = (1 << 4), 3762306a36Sopenharmony_ci SGX_SECINFO_PR = (1 << 5), 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct vdso_symtab { 4162306a36Sopenharmony_ci Elf64_Sym *elf_symtab; 4262306a36Sopenharmony_ci const char *elf_symstrtab; 4362306a36Sopenharmony_ci Elf64_Word *elf_hashtab; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic Elf64_Dyn *vdso_get_dyntab(void *addr) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci Elf64_Ehdr *ehdr = addr; 4962306a36Sopenharmony_ci Elf64_Phdr *phdrtab = addr + ehdr->e_phoff; 5062306a36Sopenharmony_ci int i; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci for (i = 0; i < ehdr->e_phnum; i++) 5362306a36Sopenharmony_ci if (phdrtab[i].p_type == PT_DYNAMIC) 5462306a36Sopenharmony_ci return addr + phdrtab[i].p_offset; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return NULL; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void *vdso_get_dyn(void *addr, Elf64_Dyn *dyntab, Elf64_Sxword tag) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci int i; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci for (i = 0; dyntab[i].d_tag != DT_NULL; i++) 6462306a36Sopenharmony_ci if (dyntab[i].d_tag == tag) 6562306a36Sopenharmony_ci return addr + dyntab[i].d_un.d_ptr; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return NULL; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic bool vdso_get_symtab(void *addr, struct vdso_symtab *symtab) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci Elf64_Dyn *dyntab = vdso_get_dyntab(addr); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci symtab->elf_symtab = vdso_get_dyn(addr, dyntab, DT_SYMTAB); 7562306a36Sopenharmony_ci if (!symtab->elf_symtab) 7662306a36Sopenharmony_ci return false; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci symtab->elf_symstrtab = vdso_get_dyn(addr, dyntab, DT_STRTAB); 7962306a36Sopenharmony_ci if (!symtab->elf_symstrtab) 8062306a36Sopenharmony_ci return false; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci symtab->elf_hashtab = vdso_get_dyn(addr, dyntab, DT_HASH); 8362306a36Sopenharmony_ci if (!symtab->elf_hashtab) 8462306a36Sopenharmony_ci return false; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return true; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic inline int sgx2_supported(void) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci unsigned int eax, ebx, ecx, edx; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci __cpuid_count(SGX_CPUID, 0x0, eax, ebx, ecx, edx); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return eax & 0x2; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic unsigned long elf_sym_hash(const char *name) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci unsigned long h = 0, high; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci while (*name) { 10362306a36Sopenharmony_ci h = (h << 4) + *name++; 10462306a36Sopenharmony_ci high = h & 0xf0000000; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (high) 10762306a36Sopenharmony_ci h ^= high >> 24; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci h &= ~high; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return h; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic Elf64_Sym *vdso_symtab_get(struct vdso_symtab *symtab, const char *name) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci Elf64_Word bucketnum = symtab->elf_hashtab[0]; 11862306a36Sopenharmony_ci Elf64_Word *buckettab = &symtab->elf_hashtab[2]; 11962306a36Sopenharmony_ci Elf64_Word *chaintab = &symtab->elf_hashtab[2 + bucketnum]; 12062306a36Sopenharmony_ci Elf64_Sym *sym; 12162306a36Sopenharmony_ci Elf64_Word i; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci for (i = buckettab[elf_sym_hash(name) % bucketnum]; i != STN_UNDEF; 12462306a36Sopenharmony_ci i = chaintab[i]) { 12562306a36Sopenharmony_ci sym = &symtab->elf_symtab[i]; 12662306a36Sopenharmony_ci if (!strcmp(name, &symtab->elf_symstrtab[sym->st_name])) 12762306a36Sopenharmony_ci return sym; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return NULL; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * Return the offset in the enclave where the TCS segment can be found. 13562306a36Sopenharmony_ci * The first RW segment loaded is the TCS. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_cistatic off_t encl_get_tcs_offset(struct encl *encl) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci int i; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci for (i = 0; i < encl->nr_segments; i++) { 14262306a36Sopenharmony_ci struct encl_segment *seg = &encl->segment_tbl[i]; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (i == 0 && seg->prot == (PROT_READ | PROT_WRITE)) 14562306a36Sopenharmony_ci return seg->offset; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return -1; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* 15262306a36Sopenharmony_ci * Return the offset in the enclave where the data segment can be found. 15362306a36Sopenharmony_ci * The first RW segment loaded is the TCS, skip that to get info on the 15462306a36Sopenharmony_ci * data segment. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_cistatic off_t encl_get_data_offset(struct encl *encl) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci int i; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci for (i = 1; i < encl->nr_segments; i++) { 16162306a36Sopenharmony_ci struct encl_segment *seg = &encl->segment_tbl[i]; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (seg->prot == (PROT_READ | PROT_WRITE)) 16462306a36Sopenharmony_ci return seg->offset; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return -1; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciFIXTURE(enclave) { 17162306a36Sopenharmony_ci struct encl encl; 17262306a36Sopenharmony_ci struct sgx_enclave_run run; 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic bool setup_test_encl(unsigned long heap_size, struct encl *encl, 17662306a36Sopenharmony_ci struct __test_metadata *_metadata) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci Elf64_Sym *sgx_enter_enclave_sym = NULL; 17962306a36Sopenharmony_ci struct vdso_symtab symtab; 18062306a36Sopenharmony_ci struct encl_segment *seg; 18162306a36Sopenharmony_ci char maps_line[256]; 18262306a36Sopenharmony_ci FILE *maps_file; 18362306a36Sopenharmony_ci unsigned int i; 18462306a36Sopenharmony_ci void *addr; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (!encl_load("test_encl.elf", encl, heap_size)) { 18762306a36Sopenharmony_ci encl_delete(encl); 18862306a36Sopenharmony_ci TH_LOG("Failed to load the test enclave."); 18962306a36Sopenharmony_ci return false; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (!encl_measure(encl)) 19362306a36Sopenharmony_ci goto err; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (!encl_build(encl)) 19662306a36Sopenharmony_ci goto err; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* 19962306a36Sopenharmony_ci * An enclave consumer only must do this. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci for (i = 0; i < encl->nr_segments; i++) { 20262306a36Sopenharmony_ci struct encl_segment *seg = &encl->segment_tbl[i]; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci addr = mmap((void *)encl->encl_base + seg->offset, seg->size, 20562306a36Sopenharmony_ci seg->prot, MAP_SHARED | MAP_FIXED, encl->fd, 0); 20662306a36Sopenharmony_ci EXPECT_NE(addr, MAP_FAILED); 20762306a36Sopenharmony_ci if (addr == MAP_FAILED) 20862306a36Sopenharmony_ci goto err; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* Get vDSO base address */ 21262306a36Sopenharmony_ci addr = (void *)getauxval(AT_SYSINFO_EHDR); 21362306a36Sopenharmony_ci if (!addr) 21462306a36Sopenharmony_ci goto err; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (!vdso_get_symtab(addr, &symtab)) 21762306a36Sopenharmony_ci goto err; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci sgx_enter_enclave_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave"); 22062306a36Sopenharmony_ci if (!sgx_enter_enclave_sym) 22162306a36Sopenharmony_ci goto err; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci vdso_sgx_enter_enclave = addr + sgx_enter_enclave_sym->st_value; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return true; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cierr: 22862306a36Sopenharmony_ci for (i = 0; i < encl->nr_segments; i++) { 22962306a36Sopenharmony_ci seg = &encl->segment_tbl[i]; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci TH_LOG("0x%016lx 0x%016lx 0x%02x", seg->offset, seg->size, seg->prot); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci maps_file = fopen("/proc/self/maps", "r"); 23562306a36Sopenharmony_ci if (maps_file != NULL) { 23662306a36Sopenharmony_ci while (fgets(maps_line, sizeof(maps_line), maps_file) != NULL) { 23762306a36Sopenharmony_ci maps_line[strlen(maps_line) - 1] = '\0'; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (strstr(maps_line, "/dev/sgx_enclave")) 24062306a36Sopenharmony_ci TH_LOG("%s", maps_line); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci fclose(maps_file); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci TH_LOG("Failed to initialize the test enclave."); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci encl_delete(encl); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return false; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ciFIXTURE_SETUP(enclave) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ciFIXTURE_TEARDOWN(enclave) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci encl_delete(&self->encl); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci#define ENCL_CALL(op, run, clobbered) \ 26362306a36Sopenharmony_ci ({ \ 26462306a36Sopenharmony_ci int ret; \ 26562306a36Sopenharmony_ci if ((clobbered)) \ 26662306a36Sopenharmony_ci ret = vdso_sgx_enter_enclave((unsigned long)(op), 0, 0, \ 26762306a36Sopenharmony_ci EENTER, 0, 0, (run)); \ 26862306a36Sopenharmony_ci else \ 26962306a36Sopenharmony_ci ret = sgx_enter_enclave((void *)(op), NULL, 0, EENTER, NULL, NULL, \ 27062306a36Sopenharmony_ci (run)); \ 27162306a36Sopenharmony_ci ret; \ 27262306a36Sopenharmony_ci }) 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci#define EXPECT_EEXIT(run) \ 27562306a36Sopenharmony_ci do { \ 27662306a36Sopenharmony_ci EXPECT_EQ((run)->function, EEXIT); \ 27762306a36Sopenharmony_ci if ((run)->function != EEXIT) \ 27862306a36Sopenharmony_ci TH_LOG("0x%02x 0x%02x 0x%016llx", (run)->exception_vector, \ 27962306a36Sopenharmony_ci (run)->exception_error_code, (run)->exception_addr); \ 28062306a36Sopenharmony_ci } while (0) 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciTEST_F(enclave, unclobbered_vdso) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct encl_op_get_from_buf get_op; 28562306a36Sopenharmony_ci struct encl_op_put_to_buf put_op; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 29062306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci put_op.header.type = ENCL_OP_PUT_TO_BUFFER; 29362306a36Sopenharmony_ci put_op.value = MAGIC; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_op, &self->run, false), 0); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 29862306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci get_op.header.type = ENCL_OP_GET_FROM_BUFFER; 30162306a36Sopenharmony_ci get_op.value = 0; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_op, &self->run, false), 0); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci EXPECT_EQ(get_op.value, MAGIC); 30662306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 30762306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/* 31162306a36Sopenharmony_ci * A section metric is concatenated in a way that @low bits 12-31 define the 31262306a36Sopenharmony_ci * bits 12-31 of the metric and @high bits 0-19 define the bits 32-51 of the 31362306a36Sopenharmony_ci * metric. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_cistatic unsigned long sgx_calc_section_metric(unsigned int low, 31662306a36Sopenharmony_ci unsigned int high) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci return (low & GENMASK_ULL(31, 12)) + 31962306a36Sopenharmony_ci ((high & GENMASK_ULL(19, 0)) << 32); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/* 32362306a36Sopenharmony_ci * Sum total available physical SGX memory across all EPC sections 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci * Return: total available physical SGX memory available on system 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_cistatic unsigned long get_total_epc_mem(void) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci unsigned int eax, ebx, ecx, edx; 33062306a36Sopenharmony_ci unsigned long total_size = 0; 33162306a36Sopenharmony_ci unsigned int type; 33262306a36Sopenharmony_ci int section = 0; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci while (true) { 33562306a36Sopenharmony_ci __cpuid_count(SGX_CPUID, section + SGX_CPUID_EPC, eax, ebx, ecx, edx); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci type = eax & SGX_CPUID_EPC_MASK; 33862306a36Sopenharmony_ci if (type == SGX_CPUID_EPC_INVALID) 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (type != SGX_CPUID_EPC_SECTION) 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci total_size += sgx_calc_section_metric(ecx, edx); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci section++; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return total_size; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ciTEST_F(enclave, unclobbered_vdso_oversubscribed) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct encl_op_get_from_buf get_op; 35562306a36Sopenharmony_ci struct encl_op_put_to_buf put_op; 35662306a36Sopenharmony_ci unsigned long total_mem; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci total_mem = get_total_epc_mem(); 35962306a36Sopenharmony_ci ASSERT_NE(total_mem, 0); 36062306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(total_mem, &self->encl, _metadata)); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 36362306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci put_op.header.type = ENCL_OP_PUT_TO_BUFFER; 36662306a36Sopenharmony_ci put_op.value = MAGIC; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_op, &self->run, false), 0); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 37162306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci get_op.header.type = ENCL_OP_GET_FROM_BUFFER; 37462306a36Sopenharmony_ci get_op.value = 0; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_op, &self->run, false), 0); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci EXPECT_EQ(get_op.value, MAGIC); 37962306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 38062306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ciTEST_F_TIMEOUT(enclave, unclobbered_vdso_oversubscribed_remove, 900) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct sgx_enclave_remove_pages remove_ioc; 38662306a36Sopenharmony_ci struct sgx_enclave_modify_types modt_ioc; 38762306a36Sopenharmony_ci struct encl_op_get_from_buf get_op; 38862306a36Sopenharmony_ci struct encl_op_eaccept eaccept_op; 38962306a36Sopenharmony_ci struct encl_op_put_to_buf put_op; 39062306a36Sopenharmony_ci struct encl_segment *heap; 39162306a36Sopenharmony_ci unsigned long total_mem; 39262306a36Sopenharmony_ci int ret, errno_save; 39362306a36Sopenharmony_ci unsigned long addr; 39462306a36Sopenharmony_ci unsigned long i; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * Create enclave with additional heap that is as big as all 39862306a36Sopenharmony_ci * available physical SGX memory. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci total_mem = get_total_epc_mem(); 40162306a36Sopenharmony_ci ASSERT_NE(total_mem, 0); 40262306a36Sopenharmony_ci TH_LOG("Creating an enclave with %lu bytes heap may take a while ...", 40362306a36Sopenharmony_ci total_mem); 40462306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(total_mem, &self->encl, _metadata)); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* 40762306a36Sopenharmony_ci * Hardware (SGX2) and kernel support is needed for this test. Start 40862306a36Sopenharmony_ci * with check that test has a chance of succeeding. 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ci memset(&modt_ioc, 0, sizeof(modt_ioc)); 41162306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (ret == -1) { 41462306a36Sopenharmony_ci if (errno == ENOTTY) 41562306a36Sopenharmony_ci SKIP(return, 41662306a36Sopenharmony_ci "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); 41762306a36Sopenharmony_ci else if (errno == ENODEV) 41862306a36Sopenharmony_ci SKIP(return, "System does not support SGX2"); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* 42262306a36Sopenharmony_ci * Invalid parameters were provided during sanity check, 42362306a36Sopenharmony_ci * expect command to fail. 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ci EXPECT_EQ(ret, -1); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* SGX2 is supported by kernel and hardware, test can proceed. */ 42862306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 42962306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci heap = &self->encl.segment_tbl[self->encl.nr_segments - 1]; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci put_op.header.type = ENCL_OP_PUT_TO_BUFFER; 43462306a36Sopenharmony_ci put_op.value = MAGIC; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_op, &self->run, false), 0); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 43962306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci get_op.header.type = ENCL_OP_GET_FROM_BUFFER; 44262306a36Sopenharmony_ci get_op.value = 0; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_op, &self->run, false), 0); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci EXPECT_EQ(get_op.value, MAGIC); 44762306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 44862306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* Trim entire heap. */ 45162306a36Sopenharmony_ci memset(&modt_ioc, 0, sizeof(modt_ioc)); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci modt_ioc.offset = heap->offset; 45462306a36Sopenharmony_ci modt_ioc.length = heap->size; 45562306a36Sopenharmony_ci modt_ioc.page_type = SGX_PAGE_TYPE_TRIM; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci TH_LOG("Changing type of %zd bytes to trimmed may take a while ...", 45862306a36Sopenharmony_ci heap->size); 45962306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); 46062306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 46362306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 46462306a36Sopenharmony_ci EXPECT_EQ(modt_ioc.result, 0); 46562306a36Sopenharmony_ci EXPECT_EQ(modt_ioc.count, heap->size); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* EACCEPT all removed pages. */ 46862306a36Sopenharmony_ci addr = self->encl.encl_base + heap->offset; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED; 47162306a36Sopenharmony_ci eaccept_op.header.type = ENCL_OP_EACCEPT; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci TH_LOG("Entering enclave to run EACCEPT for each page of %zd bytes may take a while ...", 47462306a36Sopenharmony_ci heap->size); 47562306a36Sopenharmony_ci for (i = 0; i < heap->size; i += 4096) { 47662306a36Sopenharmony_ci eaccept_op.epc_addr = addr + i; 47762306a36Sopenharmony_ci eaccept_op.ret = 0; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 48262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 48362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 48462306a36Sopenharmony_ci ASSERT_EQ(eaccept_op.ret, 0); 48562306a36Sopenharmony_ci ASSERT_EQ(self->run.function, EEXIT); 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Complete page removal. */ 48962306a36Sopenharmony_ci memset(&remove_ioc, 0, sizeof(remove_ioc)); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci remove_ioc.offset = heap->offset; 49262306a36Sopenharmony_ci remove_ioc.length = heap->size; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci TH_LOG("Removing %zd bytes from enclave may take a while ...", 49562306a36Sopenharmony_ci heap->size); 49662306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc); 49762306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 50062306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 50162306a36Sopenharmony_ci EXPECT_EQ(remove_ioc.count, heap->size); 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ciTEST_F(enclave, clobbered_vdso) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct encl_op_get_from_buf get_op; 50762306a36Sopenharmony_ci struct encl_op_put_to_buf put_op; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 51262306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci put_op.header.type = ENCL_OP_PUT_TO_BUFFER; 51562306a36Sopenharmony_ci put_op.value = MAGIC; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_op, &self->run, true), 0); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 52062306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci get_op.header.type = ENCL_OP_GET_FROM_BUFFER; 52362306a36Sopenharmony_ci get_op.value = 0; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_op, &self->run, true), 0); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci EXPECT_EQ(get_op.value, MAGIC); 52862306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 52962306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int test_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9, 53362306a36Sopenharmony_ci struct sgx_enclave_run *run) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci run->user_data = 0; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return 0; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ciTEST_F(enclave, clobbered_vdso_and_user_function) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct encl_op_get_from_buf get_op; 54362306a36Sopenharmony_ci struct encl_op_put_to_buf put_op; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 54862306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci self->run.user_handler = (__u64)test_handler; 55162306a36Sopenharmony_ci self->run.user_data = 0xdeadbeef; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci put_op.header.type = ENCL_OP_PUT_TO_BUFFER; 55462306a36Sopenharmony_ci put_op.value = MAGIC; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_op, &self->run, true), 0); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 55962306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci get_op.header.type = ENCL_OP_GET_FROM_BUFFER; 56262306a36Sopenharmony_ci get_op.value = 0; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_op, &self->run, true), 0); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci EXPECT_EQ(get_op.value, MAGIC); 56762306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 56862306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci/* 57262306a36Sopenharmony_ci * Sanity check that it is possible to enter either of the two hardcoded TCS 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_ciTEST_F(enclave, tcs_entry) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct encl_op_header op; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 58162306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci op.type = ENCL_OP_NOP; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 58862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 58962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 59062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* Move to the next TCS. */ 59362306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base + PAGE_SIZE; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 59862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 59962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 60062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci/* 60462306a36Sopenharmony_ci * Second page of .data segment is used to test changing PTE permissions. 60562306a36Sopenharmony_ci * This spans the local encl_buffer within the test enclave. 60662306a36Sopenharmony_ci * 60762306a36Sopenharmony_ci * 1) Start with a sanity check: a value is written to the target page within 60862306a36Sopenharmony_ci * the enclave and read back to ensure target page can be written to. 60962306a36Sopenharmony_ci * 2) Change PTE permissions (RW -> RO) of target page within enclave. 61062306a36Sopenharmony_ci * 3) Repeat (1) - this time expecting a regular #PF communicated via the 61162306a36Sopenharmony_ci * vDSO. 61262306a36Sopenharmony_ci * 4) Change PTE permissions of target page within enclave back to be RW. 61362306a36Sopenharmony_ci * 5) Repeat (1) by resuming enclave, now expected to be possible to write to 61462306a36Sopenharmony_ci * and read from target page within enclave. 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ciTEST_F(enclave, pte_permissions) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct encl_op_get_from_addr get_addr_op; 61962306a36Sopenharmony_ci struct encl_op_put_to_addr put_addr_op; 62062306a36Sopenharmony_ci unsigned long data_start; 62162306a36Sopenharmony_ci int ret; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 62662306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci data_start = self->encl.encl_base + 62962306a36Sopenharmony_ci encl_get_data_offset(&self->encl) + 63062306a36Sopenharmony_ci PAGE_SIZE; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* 63362306a36Sopenharmony_ci * Sanity check to ensure it is possible to write to page that will 63462306a36Sopenharmony_ci * have its permissions manipulated. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* Write MAGIC to page */ 63862306a36Sopenharmony_ci put_addr_op.value = MAGIC; 63962306a36Sopenharmony_ci put_addr_op.addr = data_start; 64062306a36Sopenharmony_ci put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 64562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 64662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 64762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* 65062306a36Sopenharmony_ci * Read memory that was just written to, confirming that it is the 65162306a36Sopenharmony_ci * value previously written (MAGIC). 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_ci get_addr_op.value = 0; 65462306a36Sopenharmony_ci get_addr_op.addr = data_start; 65562306a36Sopenharmony_ci get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci EXPECT_EQ(get_addr_op.value, MAGIC); 66062306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 66162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 66262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 66362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* Change PTE permissions of target page within the enclave */ 66662306a36Sopenharmony_ci ret = mprotect((void *)data_start, PAGE_SIZE, PROT_READ); 66762306a36Sopenharmony_ci if (ret) 66862306a36Sopenharmony_ci perror("mprotect"); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* 67162306a36Sopenharmony_ci * PTE permissions of target page changed to read-only, EPCM 67262306a36Sopenharmony_ci * permissions unchanged (EPCM permissions are RW), attempt to 67362306a36Sopenharmony_ci * write to the page, expecting a regular #PF. 67462306a36Sopenharmony_ci */ 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci put_addr_op.value = MAGIC2; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 14); 68162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0x7); 68262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, data_start); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci self->run.exception_vector = 0; 68562306a36Sopenharmony_ci self->run.exception_error_code = 0; 68662306a36Sopenharmony_ci self->run.exception_addr = 0; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* 68962306a36Sopenharmony_ci * Change PTE permissions back to enable enclave to write to the 69062306a36Sopenharmony_ci * target page and resume enclave - do not expect any exceptions this 69162306a36Sopenharmony_ci * time. 69262306a36Sopenharmony_ci */ 69362306a36Sopenharmony_ci ret = mprotect((void *)data_start, PAGE_SIZE, PROT_READ | PROT_WRITE); 69462306a36Sopenharmony_ci if (ret) 69562306a36Sopenharmony_ci perror("mprotect"); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci EXPECT_EQ(vdso_sgx_enter_enclave((unsigned long)&put_addr_op, 0, 69862306a36Sopenharmony_ci 0, ERESUME, 0, 0, &self->run), 69962306a36Sopenharmony_ci 0); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 70262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 70362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 70462306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci get_addr_op.value = 0; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci EXPECT_EQ(get_addr_op.value, MAGIC2); 71162306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 71262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 71362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 71462306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci/* 71862306a36Sopenharmony_ci * Modifying permissions of TCS page should not be possible. 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_ciTEST_F(enclave, tcs_permissions) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci struct sgx_enclave_restrict_permissions ioc; 72362306a36Sopenharmony_ci int ret, errno_save; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 72862306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci memset(&ioc, 0, sizeof(ioc)); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* 73362306a36Sopenharmony_ci * Ensure kernel supports needed ioctl() and system supports needed 73462306a36Sopenharmony_ci * commands. 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, &ioc); 73862306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* 74162306a36Sopenharmony_ci * Invalid parameters were provided during sanity check, 74262306a36Sopenharmony_ci * expect command to fail. 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ci ASSERT_EQ(ret, -1); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* ret == -1 */ 74762306a36Sopenharmony_ci if (errno_save == ENOTTY) 74862306a36Sopenharmony_ci SKIP(return, 74962306a36Sopenharmony_ci "Kernel does not support SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS ioctl()"); 75062306a36Sopenharmony_ci else if (errno_save == ENODEV) 75162306a36Sopenharmony_ci SKIP(return, "System does not support SGX2"); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* 75462306a36Sopenharmony_ci * Attempt to make TCS page read-only. This is not allowed and 75562306a36Sopenharmony_ci * should be prevented by the kernel. 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_ci ioc.offset = encl_get_tcs_offset(&self->encl); 75862306a36Sopenharmony_ci ioc.length = PAGE_SIZE; 75962306a36Sopenharmony_ci ioc.permissions = SGX_SECINFO_R; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, &ioc); 76262306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci EXPECT_EQ(ret, -1); 76562306a36Sopenharmony_ci EXPECT_EQ(errno_save, EINVAL); 76662306a36Sopenharmony_ci EXPECT_EQ(ioc.result, 0); 76762306a36Sopenharmony_ci EXPECT_EQ(ioc.count, 0); 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci/* 77162306a36Sopenharmony_ci * Enclave page permission test. 77262306a36Sopenharmony_ci * 77362306a36Sopenharmony_ci * Modify and restore enclave page's EPCM (enclave) permissions from 77462306a36Sopenharmony_ci * outside enclave (ENCLS[EMODPR] via kernel) as well as from within 77562306a36Sopenharmony_ci * enclave (via ENCLU[EMODPE]). Check for page fault if 77662306a36Sopenharmony_ci * VMA allows access but EPCM permissions do not. 77762306a36Sopenharmony_ci */ 77862306a36Sopenharmony_ciTEST_F(enclave, epcm_permissions) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct sgx_enclave_restrict_permissions restrict_ioc; 78162306a36Sopenharmony_ci struct encl_op_get_from_addr get_addr_op; 78262306a36Sopenharmony_ci struct encl_op_put_to_addr put_addr_op; 78362306a36Sopenharmony_ci struct encl_op_eaccept eaccept_op; 78462306a36Sopenharmony_ci struct encl_op_emodpe emodpe_op; 78562306a36Sopenharmony_ci unsigned long data_start; 78662306a36Sopenharmony_ci int ret, errno_save; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 79162306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* 79462306a36Sopenharmony_ci * Ensure kernel supports needed ioctl() and system supports needed 79562306a36Sopenharmony_ci * commands. 79662306a36Sopenharmony_ci */ 79762306a36Sopenharmony_ci memset(&restrict_ioc, 0, sizeof(restrict_ioc)); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, 80062306a36Sopenharmony_ci &restrict_ioc); 80162306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci /* 80462306a36Sopenharmony_ci * Invalid parameters were provided during sanity check, 80562306a36Sopenharmony_ci * expect command to fail. 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_ci ASSERT_EQ(ret, -1); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* ret == -1 */ 81062306a36Sopenharmony_ci if (errno_save == ENOTTY) 81162306a36Sopenharmony_ci SKIP(return, 81262306a36Sopenharmony_ci "Kernel does not support SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS ioctl()"); 81362306a36Sopenharmony_ci else if (errno_save == ENODEV) 81462306a36Sopenharmony_ci SKIP(return, "System does not support SGX2"); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* 81762306a36Sopenharmony_ci * Page that will have its permissions changed is the second data 81862306a36Sopenharmony_ci * page in the .data segment. This forms part of the local encl_buffer 81962306a36Sopenharmony_ci * within the enclave. 82062306a36Sopenharmony_ci * 82162306a36Sopenharmony_ci * At start of test @data_start should have EPCM as well as PTE and 82262306a36Sopenharmony_ci * VMA permissions of RW. 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci data_start = self->encl.encl_base + 82662306a36Sopenharmony_ci encl_get_data_offset(&self->encl) + PAGE_SIZE; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* 82962306a36Sopenharmony_ci * Sanity check that page at @data_start is writable before making 83062306a36Sopenharmony_ci * any changes to page permissions. 83162306a36Sopenharmony_ci * 83262306a36Sopenharmony_ci * Start by writing MAGIC to test page. 83362306a36Sopenharmony_ci */ 83462306a36Sopenharmony_ci put_addr_op.value = MAGIC; 83562306a36Sopenharmony_ci put_addr_op.addr = data_start; 83662306a36Sopenharmony_ci put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 84162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 84262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 84362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* 84662306a36Sopenharmony_ci * Read memory that was just written to, confirming that 84762306a36Sopenharmony_ci * page is writable. 84862306a36Sopenharmony_ci */ 84962306a36Sopenharmony_ci get_addr_op.value = 0; 85062306a36Sopenharmony_ci get_addr_op.addr = data_start; 85162306a36Sopenharmony_ci get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci EXPECT_EQ(get_addr_op.value, MAGIC); 85662306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 85762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 85862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 85962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* 86262306a36Sopenharmony_ci * Change EPCM permissions to read-only. Kernel still considers 86362306a36Sopenharmony_ci * the page writable. 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_ci memset(&restrict_ioc, 0, sizeof(restrict_ioc)); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci restrict_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; 86862306a36Sopenharmony_ci restrict_ioc.length = PAGE_SIZE; 86962306a36Sopenharmony_ci restrict_ioc.permissions = SGX_SECINFO_R; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, 87262306a36Sopenharmony_ci &restrict_ioc); 87362306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 87662306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 87762306a36Sopenharmony_ci EXPECT_EQ(restrict_ioc.result, 0); 87862306a36Sopenharmony_ci EXPECT_EQ(restrict_ioc.count, 4096); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* 88162306a36Sopenharmony_ci * EPCM permissions changed from kernel, need to EACCEPT from enclave. 88262306a36Sopenharmony_ci */ 88362306a36Sopenharmony_ci eaccept_op.epc_addr = data_start; 88462306a36Sopenharmony_ci eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_REG | SGX_SECINFO_PR; 88562306a36Sopenharmony_ci eaccept_op.ret = 0; 88662306a36Sopenharmony_ci eaccept_op.header.type = ENCL_OP_EACCEPT; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 89162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 89262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 89362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 89462306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* 89762306a36Sopenharmony_ci * EPCM permissions of page is now read-only, expect #PF 89862306a36Sopenharmony_ci * on EPCM when attempting to write to page from within enclave. 89962306a36Sopenharmony_ci */ 90062306a36Sopenharmony_ci put_addr_op.value = MAGIC2; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci EXPECT_EQ(self->run.function, ERESUME); 90562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 14); 90662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0x8007); 90762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, data_start); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci self->run.exception_vector = 0; 91062306a36Sopenharmony_ci self->run.exception_error_code = 0; 91162306a36Sopenharmony_ci self->run.exception_addr = 0; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* 91462306a36Sopenharmony_ci * Received AEX but cannot return to enclave at same entrypoint, 91562306a36Sopenharmony_ci * need different TCS from where EPCM permission can be made writable 91662306a36Sopenharmony_ci * again. 91762306a36Sopenharmony_ci */ 91862306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base + PAGE_SIZE; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* 92162306a36Sopenharmony_ci * Enter enclave at new TCS to change EPCM permissions to be 92262306a36Sopenharmony_ci * writable again and thus fix the page fault that triggered the 92362306a36Sopenharmony_ci * AEX. 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci emodpe_op.epc_addr = data_start; 92762306a36Sopenharmony_ci emodpe_op.flags = SGX_SECINFO_R | SGX_SECINFO_W; 92862306a36Sopenharmony_ci emodpe_op.header.type = ENCL_OP_EMODPE; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&emodpe_op, &self->run, true), 0); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 93362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 93462306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 93562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* 93862306a36Sopenharmony_ci * Attempt to return to main TCS to resume execution at faulting 93962306a36Sopenharmony_ci * instruction, PTE should continue to allow writing to the page. 94062306a36Sopenharmony_ci */ 94162306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* 94462306a36Sopenharmony_ci * Wrong page permissions that caused original fault has 94562306a36Sopenharmony_ci * now been fixed via EPCM permissions. 94662306a36Sopenharmony_ci * Resume execution in main TCS to re-attempt the memory access. 94762306a36Sopenharmony_ci */ 94862306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci EXPECT_EQ(vdso_sgx_enter_enclave((unsigned long)&put_addr_op, 0, 0, 95162306a36Sopenharmony_ci ERESUME, 0, 0, 95262306a36Sopenharmony_ci &self->run), 95362306a36Sopenharmony_ci 0); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 95662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 95762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 95862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci get_addr_op.value = 0; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci EXPECT_EQ(get_addr_op.value, MAGIC2); 96562306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 96662306a36Sopenharmony_ci EXPECT_EQ(self->run.user_data, 0); 96762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 96862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 96962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci/* 97362306a36Sopenharmony_ci * Test the addition of pages to an initialized enclave via writing to 97462306a36Sopenharmony_ci * a page belonging to the enclave's address space but was not added 97562306a36Sopenharmony_ci * during enclave creation. 97662306a36Sopenharmony_ci */ 97762306a36Sopenharmony_ciTEST_F(enclave, augment) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci struct encl_op_get_from_addr get_addr_op; 98062306a36Sopenharmony_ci struct encl_op_put_to_addr put_addr_op; 98162306a36Sopenharmony_ci struct encl_op_eaccept eaccept_op; 98262306a36Sopenharmony_ci size_t total_size = 0; 98362306a36Sopenharmony_ci void *addr; 98462306a36Sopenharmony_ci int i; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (!sgx2_supported()) 98762306a36Sopenharmony_ci SKIP(return, "SGX2 not supported"); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 99262306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci for (i = 0; i < self->encl.nr_segments; i++) { 99562306a36Sopenharmony_ci struct encl_segment *seg = &self->encl.segment_tbl[i]; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci total_size += seg->size; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* 100162306a36Sopenharmony_ci * Actual enclave size is expected to be larger than the loaded 100262306a36Sopenharmony_ci * test enclave since enclave size must be a power of 2 in bytes 100362306a36Sopenharmony_ci * and test_encl does not consume it all. 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_ci EXPECT_LT(total_size + PAGE_SIZE, self->encl.encl_size); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci /* 100862306a36Sopenharmony_ci * Create memory mapping for the page that will be added. New 100962306a36Sopenharmony_ci * memory mapping is for one page right after all existing 101062306a36Sopenharmony_ci * mappings. 101162306a36Sopenharmony_ci * Kernel will allow new mapping using any permissions if it 101262306a36Sopenharmony_ci * falls into the enclave's address range but not backed 101362306a36Sopenharmony_ci * by existing enclave pages. 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_ci addr = mmap((void *)self->encl.encl_base + total_size, PAGE_SIZE, 101662306a36Sopenharmony_ci PROT_READ | PROT_WRITE | PROT_EXEC, 101762306a36Sopenharmony_ci MAP_SHARED | MAP_FIXED, self->encl.fd, 0); 101862306a36Sopenharmony_ci EXPECT_NE(addr, MAP_FAILED); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci self->run.exception_vector = 0; 102162306a36Sopenharmony_ci self->run.exception_error_code = 0; 102262306a36Sopenharmony_ci self->run.exception_addr = 0; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* 102562306a36Sopenharmony_ci * Attempt to write to the new page from within enclave. 102662306a36Sopenharmony_ci * Expected to fail since page is not (yet) part of the enclave. 102762306a36Sopenharmony_ci * The first #PF will trigger the addition of the page to the 102862306a36Sopenharmony_ci * enclave, but since the new page needs an EACCEPT from within the 102962306a36Sopenharmony_ci * enclave before it can be used it would not be possible 103062306a36Sopenharmony_ci * to successfully return to the failing instruction. This is the 103162306a36Sopenharmony_ci * cause of the second #PF captured here having the SGX bit set, 103262306a36Sopenharmony_ci * it is from hardware preventing the page from being used. 103362306a36Sopenharmony_ci */ 103462306a36Sopenharmony_ci put_addr_op.value = MAGIC; 103562306a36Sopenharmony_ci put_addr_op.addr = (unsigned long)addr; 103662306a36Sopenharmony_ci put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci EXPECT_EQ(self->run.function, ERESUME); 104162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 14); 104262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, (unsigned long)addr); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci if (self->run.exception_error_code == 0x6) { 104562306a36Sopenharmony_ci munmap(addr, PAGE_SIZE); 104662306a36Sopenharmony_ci SKIP(return, "Kernel does not support adding pages to initialized enclave"); 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0x8007); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci self->run.exception_vector = 0; 105262306a36Sopenharmony_ci self->run.exception_error_code = 0; 105362306a36Sopenharmony_ci self->run.exception_addr = 0; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* Handle AEX by running EACCEPT from new entry point. */ 105662306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base + PAGE_SIZE; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci eaccept_op.epc_addr = self->encl.encl_base + total_size; 105962306a36Sopenharmony_ci eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING; 106062306a36Sopenharmony_ci eaccept_op.ret = 0; 106162306a36Sopenharmony_ci eaccept_op.header.type = ENCL_OP_EACCEPT; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 106662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 106762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 106862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 106962306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* Can now return to main TCS to resume execution. */ 107262306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci EXPECT_EQ(vdso_sgx_enter_enclave((unsigned long)&put_addr_op, 0, 0, 107562306a36Sopenharmony_ci ERESUME, 0, 0, 107662306a36Sopenharmony_ci &self->run), 107762306a36Sopenharmony_ci 0); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 108062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 108162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 108262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci /* 108562306a36Sopenharmony_ci * Read memory from newly added page that was just written to, 108662306a36Sopenharmony_ci * confirming that data previously written (MAGIC) is present. 108762306a36Sopenharmony_ci */ 108862306a36Sopenharmony_ci get_addr_op.value = 0; 108962306a36Sopenharmony_ci get_addr_op.addr = (unsigned long)addr; 109062306a36Sopenharmony_ci get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci EXPECT_EQ(get_addr_op.value, MAGIC); 109562306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 109662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 109762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 109862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci munmap(addr, PAGE_SIZE); 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci/* 110462306a36Sopenharmony_ci * Test for the addition of pages to an initialized enclave via a 110562306a36Sopenharmony_ci * pre-emptive run of EACCEPT on page to be added. 110662306a36Sopenharmony_ci */ 110762306a36Sopenharmony_ciTEST_F(enclave, augment_via_eaccept) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci struct encl_op_get_from_addr get_addr_op; 111062306a36Sopenharmony_ci struct encl_op_put_to_addr put_addr_op; 111162306a36Sopenharmony_ci struct encl_op_eaccept eaccept_op; 111262306a36Sopenharmony_ci size_t total_size = 0; 111362306a36Sopenharmony_ci void *addr; 111462306a36Sopenharmony_ci int i; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci if (!sgx2_supported()) 111762306a36Sopenharmony_ci SKIP(return, "SGX2 not supported"); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 112262306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci for (i = 0; i < self->encl.nr_segments; i++) { 112562306a36Sopenharmony_ci struct encl_segment *seg = &self->encl.segment_tbl[i]; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci total_size += seg->size; 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci /* 113162306a36Sopenharmony_ci * Actual enclave size is expected to be larger than the loaded 113262306a36Sopenharmony_ci * test enclave since enclave size must be a power of 2 in bytes while 113362306a36Sopenharmony_ci * test_encl does not consume it all. 113462306a36Sopenharmony_ci */ 113562306a36Sopenharmony_ci EXPECT_LT(total_size + PAGE_SIZE, self->encl.encl_size); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci /* 113862306a36Sopenharmony_ci * mmap() a page at end of existing enclave to be used for dynamic 113962306a36Sopenharmony_ci * EPC page. 114062306a36Sopenharmony_ci * 114162306a36Sopenharmony_ci * Kernel will allow new mapping using any permissions if it 114262306a36Sopenharmony_ci * falls into the enclave's address range but not backed 114362306a36Sopenharmony_ci * by existing enclave pages. 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci addr = mmap((void *)self->encl.encl_base + total_size, PAGE_SIZE, 114762306a36Sopenharmony_ci PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED, 114862306a36Sopenharmony_ci self->encl.fd, 0); 114962306a36Sopenharmony_ci EXPECT_NE(addr, MAP_FAILED); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci self->run.exception_vector = 0; 115262306a36Sopenharmony_ci self->run.exception_error_code = 0; 115362306a36Sopenharmony_ci self->run.exception_addr = 0; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* 115662306a36Sopenharmony_ci * Run EACCEPT on new page to trigger the #PF->EAUG->EACCEPT(again 115762306a36Sopenharmony_ci * without a #PF). All should be transparent to userspace. 115862306a36Sopenharmony_ci */ 115962306a36Sopenharmony_ci eaccept_op.epc_addr = self->encl.encl_base + total_size; 116062306a36Sopenharmony_ci eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING; 116162306a36Sopenharmony_ci eaccept_op.ret = 0; 116262306a36Sopenharmony_ci eaccept_op.header.type = ENCL_OP_EACCEPT; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (self->run.exception_vector == 14 && 116762306a36Sopenharmony_ci self->run.exception_error_code == 4 && 116862306a36Sopenharmony_ci self->run.exception_addr == self->encl.encl_base + total_size) { 116962306a36Sopenharmony_ci munmap(addr, PAGE_SIZE); 117062306a36Sopenharmony_ci SKIP(return, "Kernel does not support adding pages to initialized enclave"); 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 117462306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 117562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 117662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 117762306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci /* 118062306a36Sopenharmony_ci * New page should be accessible from within enclave - attempt to 118162306a36Sopenharmony_ci * write to it. 118262306a36Sopenharmony_ci */ 118362306a36Sopenharmony_ci put_addr_op.value = MAGIC; 118462306a36Sopenharmony_ci put_addr_op.addr = (unsigned long)addr; 118562306a36Sopenharmony_ci put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 119062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 119162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 119262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci /* 119562306a36Sopenharmony_ci * Read memory from newly added page that was just written to, 119662306a36Sopenharmony_ci * confirming that data previously written (MAGIC) is present. 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_ci get_addr_op.value = 0; 119962306a36Sopenharmony_ci get_addr_op.addr = (unsigned long)addr; 120062306a36Sopenharmony_ci get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci EXPECT_EQ(get_addr_op.value, MAGIC); 120562306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 120662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 120762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 120862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci munmap(addr, PAGE_SIZE); 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci/* 121462306a36Sopenharmony_ci * SGX2 page type modification test in two phases: 121562306a36Sopenharmony_ci * Phase 1: 121662306a36Sopenharmony_ci * Create a new TCS, consisting out of three new pages (stack page with regular 121762306a36Sopenharmony_ci * page type, SSA page with regular page type, and TCS page with TCS page 121862306a36Sopenharmony_ci * type) in an initialized enclave and run a simple workload within it. 121962306a36Sopenharmony_ci * Phase 2: 122062306a36Sopenharmony_ci * Remove the three pages added in phase 1, add a new regular page at the 122162306a36Sopenharmony_ci * same address that previously hosted the TCS page and verify that it can 122262306a36Sopenharmony_ci * be modified. 122362306a36Sopenharmony_ci */ 122462306a36Sopenharmony_ciTEST_F(enclave, tcs_create) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci struct encl_op_init_tcs_page init_tcs_page_op; 122762306a36Sopenharmony_ci struct sgx_enclave_remove_pages remove_ioc; 122862306a36Sopenharmony_ci struct encl_op_get_from_addr get_addr_op; 122962306a36Sopenharmony_ci struct sgx_enclave_modify_types modt_ioc; 123062306a36Sopenharmony_ci struct encl_op_put_to_addr put_addr_op; 123162306a36Sopenharmony_ci struct encl_op_get_from_buf get_buf_op; 123262306a36Sopenharmony_ci struct encl_op_put_to_buf put_buf_op; 123362306a36Sopenharmony_ci void *addr, *tcs, *stack_end, *ssa; 123462306a36Sopenharmony_ci struct encl_op_eaccept eaccept_op; 123562306a36Sopenharmony_ci size_t total_size = 0; 123662306a36Sopenharmony_ci uint64_t val_64; 123762306a36Sopenharmony_ci int errno_save; 123862306a36Sopenharmony_ci int ret, i; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, 124162306a36Sopenharmony_ci _metadata)); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 124462306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci /* 124762306a36Sopenharmony_ci * Hardware (SGX2) and kernel support is needed for this test. Start 124862306a36Sopenharmony_ci * with check that test has a chance of succeeding. 124962306a36Sopenharmony_ci */ 125062306a36Sopenharmony_ci memset(&modt_ioc, 0, sizeof(modt_ioc)); 125162306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (ret == -1) { 125462306a36Sopenharmony_ci if (errno == ENOTTY) 125562306a36Sopenharmony_ci SKIP(return, 125662306a36Sopenharmony_ci "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); 125762306a36Sopenharmony_ci else if (errno == ENODEV) 125862306a36Sopenharmony_ci SKIP(return, "System does not support SGX2"); 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci /* 126262306a36Sopenharmony_ci * Invalid parameters were provided during sanity check, 126362306a36Sopenharmony_ci * expect command to fail. 126462306a36Sopenharmony_ci */ 126562306a36Sopenharmony_ci EXPECT_EQ(ret, -1); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci /* 126862306a36Sopenharmony_ci * Add three regular pages via EAUG: one will be the TCS stack, one 126962306a36Sopenharmony_ci * will be the TCS SSA, and one will be the new TCS. The stack and 127062306a36Sopenharmony_ci * SSA will remain as regular pages, the TCS page will need its 127162306a36Sopenharmony_ci * type changed after populated with needed data. 127262306a36Sopenharmony_ci */ 127362306a36Sopenharmony_ci for (i = 0; i < self->encl.nr_segments; i++) { 127462306a36Sopenharmony_ci struct encl_segment *seg = &self->encl.segment_tbl[i]; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci total_size += seg->size; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci /* 128062306a36Sopenharmony_ci * Actual enclave size is expected to be larger than the loaded 128162306a36Sopenharmony_ci * test enclave since enclave size must be a power of 2 in bytes while 128262306a36Sopenharmony_ci * test_encl does not consume it all. 128362306a36Sopenharmony_ci */ 128462306a36Sopenharmony_ci EXPECT_LT(total_size + 3 * PAGE_SIZE, self->encl.encl_size); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci /* 128762306a36Sopenharmony_ci * mmap() three pages at end of existing enclave to be used for the 128862306a36Sopenharmony_ci * three new pages. 128962306a36Sopenharmony_ci */ 129062306a36Sopenharmony_ci addr = mmap((void *)self->encl.encl_base + total_size, 3 * PAGE_SIZE, 129162306a36Sopenharmony_ci PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, 129262306a36Sopenharmony_ci self->encl.fd, 0); 129362306a36Sopenharmony_ci EXPECT_NE(addr, MAP_FAILED); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci self->run.exception_vector = 0; 129662306a36Sopenharmony_ci self->run.exception_error_code = 0; 129762306a36Sopenharmony_ci self->run.exception_addr = 0; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci stack_end = (void *)self->encl.encl_base + total_size; 130062306a36Sopenharmony_ci tcs = (void *)self->encl.encl_base + total_size + PAGE_SIZE; 130162306a36Sopenharmony_ci ssa = (void *)self->encl.encl_base + total_size + 2 * PAGE_SIZE; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci /* 130462306a36Sopenharmony_ci * Run EACCEPT on each new page to trigger the 130562306a36Sopenharmony_ci * EACCEPT->(#PF)->EAUG->EACCEPT(again without a #PF) flow. 130662306a36Sopenharmony_ci */ 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci eaccept_op.epc_addr = (unsigned long)stack_end; 130962306a36Sopenharmony_ci eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING; 131062306a36Sopenharmony_ci eaccept_op.ret = 0; 131162306a36Sopenharmony_ci eaccept_op.header.type = ENCL_OP_EACCEPT; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci if (self->run.exception_vector == 14 && 131662306a36Sopenharmony_ci self->run.exception_error_code == 4 && 131762306a36Sopenharmony_ci self->run.exception_addr == (unsigned long)stack_end) { 131862306a36Sopenharmony_ci munmap(addr, 3 * PAGE_SIZE); 131962306a36Sopenharmony_ci SKIP(return, "Kernel does not support adding pages to initialized enclave"); 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 132362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 132462306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 132562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 132662306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci eaccept_op.epc_addr = (unsigned long)ssa; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 133362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 133462306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 133562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 133662306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci eaccept_op.epc_addr = (unsigned long)tcs; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 134362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 134462306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 134562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 134662306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* 134962306a36Sopenharmony_ci * Three new pages added to enclave. Now populate the TCS page with 135062306a36Sopenharmony_ci * needed data. This should be done from within enclave. Provide 135162306a36Sopenharmony_ci * the function that will do the actual data population with needed 135262306a36Sopenharmony_ci * data. 135362306a36Sopenharmony_ci */ 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* 135662306a36Sopenharmony_ci * New TCS will use the "encl_dyn_entry" entrypoint that expects 135762306a36Sopenharmony_ci * stack to begin in page before TCS page. 135862306a36Sopenharmony_ci */ 135962306a36Sopenharmony_ci val_64 = encl_get_entry(&self->encl, "encl_dyn_entry"); 136062306a36Sopenharmony_ci EXPECT_NE(val_64, 0); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci init_tcs_page_op.tcs_page = (unsigned long)tcs; 136362306a36Sopenharmony_ci init_tcs_page_op.ssa = (unsigned long)total_size + 2 * PAGE_SIZE; 136462306a36Sopenharmony_ci init_tcs_page_op.entry = val_64; 136562306a36Sopenharmony_ci init_tcs_page_op.header.type = ENCL_OP_INIT_TCS_PAGE; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&init_tcs_page_op, &self->run, true), 0); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 137062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 137162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 137262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci /* Change TCS page type to TCS. */ 137562306a36Sopenharmony_ci memset(&modt_ioc, 0, sizeof(modt_ioc)); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci modt_ioc.offset = total_size + PAGE_SIZE; 137862306a36Sopenharmony_ci modt_ioc.length = PAGE_SIZE; 137962306a36Sopenharmony_ci modt_ioc.page_type = SGX_PAGE_TYPE_TCS; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); 138262306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 138562306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 138662306a36Sopenharmony_ci EXPECT_EQ(modt_ioc.result, 0); 138762306a36Sopenharmony_ci EXPECT_EQ(modt_ioc.count, 4096); 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci /* EACCEPT new TCS page from enclave. */ 139062306a36Sopenharmony_ci eaccept_op.epc_addr = (unsigned long)tcs; 139162306a36Sopenharmony_ci eaccept_op.flags = SGX_SECINFO_TCS | SGX_SECINFO_MODIFIED; 139262306a36Sopenharmony_ci eaccept_op.ret = 0; 139362306a36Sopenharmony_ci eaccept_op.header.type = ENCL_OP_EACCEPT; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 139862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 139962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 140062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 140162306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci /* Run workload from new TCS. */ 140462306a36Sopenharmony_ci self->run.tcs = (unsigned long)tcs; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci /* 140762306a36Sopenharmony_ci * Simple workload to write to data buffer and read value back. 140862306a36Sopenharmony_ci */ 140962306a36Sopenharmony_ci put_buf_op.header.type = ENCL_OP_PUT_TO_BUFFER; 141062306a36Sopenharmony_ci put_buf_op.value = MAGIC; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_buf_op, &self->run, true), 0); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 141562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 141662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 141762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci get_buf_op.header.type = ENCL_OP_GET_FROM_BUFFER; 142062306a36Sopenharmony_ci get_buf_op.value = 0; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_buf_op, &self->run, true), 0); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci EXPECT_EQ(get_buf_op.value, MAGIC); 142562306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 142662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 142762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 142862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* 143162306a36Sopenharmony_ci * Phase 2 of test: 143262306a36Sopenharmony_ci * Remove pages associated with new TCS, create a regular page 143362306a36Sopenharmony_ci * where TCS page used to be and verify it can be used as a regular 143462306a36Sopenharmony_ci * page. 143562306a36Sopenharmony_ci */ 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* Start page removal by requesting change of page type to PT_TRIM. */ 143862306a36Sopenharmony_ci memset(&modt_ioc, 0, sizeof(modt_ioc)); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci modt_ioc.offset = total_size; 144162306a36Sopenharmony_ci modt_ioc.length = 3 * PAGE_SIZE; 144262306a36Sopenharmony_ci modt_ioc.page_type = SGX_PAGE_TYPE_TRIM; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); 144562306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 144862306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 144962306a36Sopenharmony_ci EXPECT_EQ(modt_ioc.result, 0); 145062306a36Sopenharmony_ci EXPECT_EQ(modt_ioc.count, 3 * PAGE_SIZE); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci /* 145362306a36Sopenharmony_ci * Enter enclave via TCS #1 and approve page removal by sending 145462306a36Sopenharmony_ci * EACCEPT for each of three removed pages. 145562306a36Sopenharmony_ci */ 145662306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci eaccept_op.epc_addr = (unsigned long)stack_end; 145962306a36Sopenharmony_ci eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED; 146062306a36Sopenharmony_ci eaccept_op.ret = 0; 146162306a36Sopenharmony_ci eaccept_op.header.type = ENCL_OP_EACCEPT; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 146662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 146762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 146862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 146962306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci eaccept_op.epc_addr = (unsigned long)tcs; 147262306a36Sopenharmony_ci eaccept_op.ret = 0; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 147762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 147862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 147962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 148062306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci eaccept_op.epc_addr = (unsigned long)ssa; 148362306a36Sopenharmony_ci eaccept_op.ret = 0; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 148862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 148962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 149062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 149162306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci /* Send final ioctl() to complete page removal. */ 149462306a36Sopenharmony_ci memset(&remove_ioc, 0, sizeof(remove_ioc)); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci remove_ioc.offset = total_size; 149762306a36Sopenharmony_ci remove_ioc.length = 3 * PAGE_SIZE; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc); 150062306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 150362306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 150462306a36Sopenharmony_ci EXPECT_EQ(remove_ioc.count, 3 * PAGE_SIZE); 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci /* 150762306a36Sopenharmony_ci * Enter enclave via TCS #1 and access location where TCS #3 was to 150862306a36Sopenharmony_ci * trigger dynamic add of regular page at that location. 150962306a36Sopenharmony_ci */ 151062306a36Sopenharmony_ci eaccept_op.epc_addr = (unsigned long)tcs; 151162306a36Sopenharmony_ci eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING; 151262306a36Sopenharmony_ci eaccept_op.ret = 0; 151362306a36Sopenharmony_ci eaccept_op.header.type = ENCL_OP_EACCEPT; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 151862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 151962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 152062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 152162306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci /* 152462306a36Sopenharmony_ci * New page should be accessible from within enclave - write to it. 152562306a36Sopenharmony_ci */ 152662306a36Sopenharmony_ci put_addr_op.value = MAGIC; 152762306a36Sopenharmony_ci put_addr_op.addr = (unsigned long)tcs; 152862306a36Sopenharmony_ci put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 153362306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 153462306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 153562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci /* 153862306a36Sopenharmony_ci * Read memory from newly added page that was just written to, 153962306a36Sopenharmony_ci * confirming that data previously written (MAGIC) is present. 154062306a36Sopenharmony_ci */ 154162306a36Sopenharmony_ci get_addr_op.value = 0; 154262306a36Sopenharmony_ci get_addr_op.addr = (unsigned long)tcs; 154362306a36Sopenharmony_ci get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci EXPECT_EQ(get_addr_op.value, MAGIC); 154862306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 154962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 155062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 155162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci munmap(addr, 3 * PAGE_SIZE); 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci/* 155762306a36Sopenharmony_ci * Ensure sane behavior if user requests page removal, does not run 155862306a36Sopenharmony_ci * EACCEPT from within enclave but still attempts to finalize page removal 155962306a36Sopenharmony_ci * with the SGX_IOC_ENCLAVE_REMOVE_PAGES ioctl(). The latter should fail 156062306a36Sopenharmony_ci * because the removal was not EACCEPTed from within the enclave. 156162306a36Sopenharmony_ci */ 156262306a36Sopenharmony_ciTEST_F(enclave, remove_added_page_no_eaccept) 156362306a36Sopenharmony_ci{ 156462306a36Sopenharmony_ci struct sgx_enclave_remove_pages remove_ioc; 156562306a36Sopenharmony_ci struct encl_op_get_from_addr get_addr_op; 156662306a36Sopenharmony_ci struct sgx_enclave_modify_types modt_ioc; 156762306a36Sopenharmony_ci struct encl_op_put_to_addr put_addr_op; 156862306a36Sopenharmony_ci unsigned long data_start; 156962306a36Sopenharmony_ci int ret, errno_save; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 157462306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci /* 157762306a36Sopenharmony_ci * Hardware (SGX2) and kernel support is needed for this test. Start 157862306a36Sopenharmony_ci * with check that test has a chance of succeeding. 157962306a36Sopenharmony_ci */ 158062306a36Sopenharmony_ci memset(&modt_ioc, 0, sizeof(modt_ioc)); 158162306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci if (ret == -1) { 158462306a36Sopenharmony_ci if (errno == ENOTTY) 158562306a36Sopenharmony_ci SKIP(return, 158662306a36Sopenharmony_ci "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); 158762306a36Sopenharmony_ci else if (errno == ENODEV) 158862306a36Sopenharmony_ci SKIP(return, "System does not support SGX2"); 158962306a36Sopenharmony_ci } 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci /* 159262306a36Sopenharmony_ci * Invalid parameters were provided during sanity check, 159362306a36Sopenharmony_ci * expect command to fail. 159462306a36Sopenharmony_ci */ 159562306a36Sopenharmony_ci EXPECT_EQ(ret, -1); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci /* 159862306a36Sopenharmony_ci * Page that will be removed is the second data page in the .data 159962306a36Sopenharmony_ci * segment. This forms part of the local encl_buffer within the 160062306a36Sopenharmony_ci * enclave. 160162306a36Sopenharmony_ci */ 160262306a36Sopenharmony_ci data_start = self->encl.encl_base + 160362306a36Sopenharmony_ci encl_get_data_offset(&self->encl) + PAGE_SIZE; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci /* 160662306a36Sopenharmony_ci * Sanity check that page at @data_start is writable before 160762306a36Sopenharmony_ci * removing it. 160862306a36Sopenharmony_ci * 160962306a36Sopenharmony_ci * Start by writing MAGIC to test page. 161062306a36Sopenharmony_ci */ 161162306a36Sopenharmony_ci put_addr_op.value = MAGIC; 161262306a36Sopenharmony_ci put_addr_op.addr = data_start; 161362306a36Sopenharmony_ci put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0); 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 161862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 161962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 162062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci /* 162362306a36Sopenharmony_ci * Read memory that was just written to, confirming that data 162462306a36Sopenharmony_ci * previously written (MAGIC) is present. 162562306a36Sopenharmony_ci */ 162662306a36Sopenharmony_ci get_addr_op.value = 0; 162762306a36Sopenharmony_ci get_addr_op.addr = data_start; 162862306a36Sopenharmony_ci get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci EXPECT_EQ(get_addr_op.value, MAGIC); 163362306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 163462306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 163562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 163662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci /* Start page removal by requesting change of page type to PT_TRIM */ 163962306a36Sopenharmony_ci memset(&modt_ioc, 0, sizeof(modt_ioc)); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci modt_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; 164262306a36Sopenharmony_ci modt_ioc.length = PAGE_SIZE; 164362306a36Sopenharmony_ci modt_ioc.page_type = SGX_PAGE_TYPE_TRIM; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); 164662306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 164962306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 165062306a36Sopenharmony_ci EXPECT_EQ(modt_ioc.result, 0); 165162306a36Sopenharmony_ci EXPECT_EQ(modt_ioc.count, 4096); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci /* Skip EACCEPT */ 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci /* Send final ioctl() to complete page removal */ 165662306a36Sopenharmony_ci memset(&remove_ioc, 0, sizeof(remove_ioc)); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci remove_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; 165962306a36Sopenharmony_ci remove_ioc.length = PAGE_SIZE; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc); 166262306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci /* Operation not permitted since EACCEPT was omitted. */ 166562306a36Sopenharmony_ci EXPECT_EQ(ret, -1); 166662306a36Sopenharmony_ci EXPECT_EQ(errno_save, EPERM); 166762306a36Sopenharmony_ci EXPECT_EQ(remove_ioc.count, 0); 166862306a36Sopenharmony_ci} 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci/* 167162306a36Sopenharmony_ci * Request enclave page removal but instead of correctly following with 167262306a36Sopenharmony_ci * EACCEPT a read attempt to page is made from within the enclave. 167362306a36Sopenharmony_ci */ 167462306a36Sopenharmony_ciTEST_F(enclave, remove_added_page_invalid_access) 167562306a36Sopenharmony_ci{ 167662306a36Sopenharmony_ci struct encl_op_get_from_addr get_addr_op; 167762306a36Sopenharmony_ci struct encl_op_put_to_addr put_addr_op; 167862306a36Sopenharmony_ci struct sgx_enclave_modify_types ioc; 167962306a36Sopenharmony_ci unsigned long data_start; 168062306a36Sopenharmony_ci int ret, errno_save; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 168562306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci /* 168862306a36Sopenharmony_ci * Hardware (SGX2) and kernel support is needed for this test. Start 168962306a36Sopenharmony_ci * with check that test has a chance of succeeding. 169062306a36Sopenharmony_ci */ 169162306a36Sopenharmony_ci memset(&ioc, 0, sizeof(ioc)); 169262306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci if (ret == -1) { 169562306a36Sopenharmony_ci if (errno == ENOTTY) 169662306a36Sopenharmony_ci SKIP(return, 169762306a36Sopenharmony_ci "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); 169862306a36Sopenharmony_ci else if (errno == ENODEV) 169962306a36Sopenharmony_ci SKIP(return, "System does not support SGX2"); 170062306a36Sopenharmony_ci } 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci /* 170362306a36Sopenharmony_ci * Invalid parameters were provided during sanity check, 170462306a36Sopenharmony_ci * expect command to fail. 170562306a36Sopenharmony_ci */ 170662306a36Sopenharmony_ci EXPECT_EQ(ret, -1); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci /* 170962306a36Sopenharmony_ci * Page that will be removed is the second data page in the .data 171062306a36Sopenharmony_ci * segment. This forms part of the local encl_buffer within the 171162306a36Sopenharmony_ci * enclave. 171262306a36Sopenharmony_ci */ 171362306a36Sopenharmony_ci data_start = self->encl.encl_base + 171462306a36Sopenharmony_ci encl_get_data_offset(&self->encl) + PAGE_SIZE; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci /* 171762306a36Sopenharmony_ci * Sanity check that page at @data_start is writable before 171862306a36Sopenharmony_ci * removing it. 171962306a36Sopenharmony_ci * 172062306a36Sopenharmony_ci * Start by writing MAGIC to test page. 172162306a36Sopenharmony_ci */ 172262306a36Sopenharmony_ci put_addr_op.value = MAGIC; 172362306a36Sopenharmony_ci put_addr_op.addr = data_start; 172462306a36Sopenharmony_ci put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0); 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 172962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 173062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 173162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci /* 173462306a36Sopenharmony_ci * Read memory that was just written to, confirming that data 173562306a36Sopenharmony_ci * previously written (MAGIC) is present. 173662306a36Sopenharmony_ci */ 173762306a36Sopenharmony_ci get_addr_op.value = 0; 173862306a36Sopenharmony_ci get_addr_op.addr = data_start; 173962306a36Sopenharmony_ci get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci EXPECT_EQ(get_addr_op.value, MAGIC); 174462306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 174562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 174662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 174762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci /* Start page removal by requesting change of page type to PT_TRIM. */ 175062306a36Sopenharmony_ci memset(&ioc, 0, sizeof(ioc)); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; 175362306a36Sopenharmony_ci ioc.length = PAGE_SIZE; 175462306a36Sopenharmony_ci ioc.page_type = SGX_PAGE_TYPE_TRIM; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc); 175762306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 176062306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 176162306a36Sopenharmony_ci EXPECT_EQ(ioc.result, 0); 176262306a36Sopenharmony_ci EXPECT_EQ(ioc.count, 4096); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci /* 176562306a36Sopenharmony_ci * Read from page that was just removed. 176662306a36Sopenharmony_ci */ 176762306a36Sopenharmony_ci get_addr_op.value = 0; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci /* 177262306a36Sopenharmony_ci * From kernel perspective the page is present but according to SGX the 177362306a36Sopenharmony_ci * page should not be accessible so a #PF with SGX bit set is 177462306a36Sopenharmony_ci * expected. 177562306a36Sopenharmony_ci */ 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci EXPECT_EQ(self->run.function, ERESUME); 177862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 14); 177962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0x8005); 178062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, data_start); 178162306a36Sopenharmony_ci} 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci/* 178462306a36Sopenharmony_ci * Request enclave page removal and correctly follow with 178562306a36Sopenharmony_ci * EACCEPT but do not follow with removal ioctl() but instead a read attempt 178662306a36Sopenharmony_ci * to removed page is made from within the enclave. 178762306a36Sopenharmony_ci */ 178862306a36Sopenharmony_ciTEST_F(enclave, remove_added_page_invalid_access_after_eaccept) 178962306a36Sopenharmony_ci{ 179062306a36Sopenharmony_ci struct encl_op_get_from_addr get_addr_op; 179162306a36Sopenharmony_ci struct encl_op_put_to_addr put_addr_op; 179262306a36Sopenharmony_ci struct sgx_enclave_modify_types ioc; 179362306a36Sopenharmony_ci struct encl_op_eaccept eaccept_op; 179462306a36Sopenharmony_ci unsigned long data_start; 179562306a36Sopenharmony_ci int ret, errno_save; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 180062306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci /* 180362306a36Sopenharmony_ci * Hardware (SGX2) and kernel support is needed for this test. Start 180462306a36Sopenharmony_ci * with check that test has a chance of succeeding. 180562306a36Sopenharmony_ci */ 180662306a36Sopenharmony_ci memset(&ioc, 0, sizeof(ioc)); 180762306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci if (ret == -1) { 181062306a36Sopenharmony_ci if (errno == ENOTTY) 181162306a36Sopenharmony_ci SKIP(return, 181262306a36Sopenharmony_ci "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); 181362306a36Sopenharmony_ci else if (errno == ENODEV) 181462306a36Sopenharmony_ci SKIP(return, "System does not support SGX2"); 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci /* 181862306a36Sopenharmony_ci * Invalid parameters were provided during sanity check, 181962306a36Sopenharmony_ci * expect command to fail. 182062306a36Sopenharmony_ci */ 182162306a36Sopenharmony_ci EXPECT_EQ(ret, -1); 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci /* 182462306a36Sopenharmony_ci * Page that will be removed is the second data page in the .data 182562306a36Sopenharmony_ci * segment. This forms part of the local encl_buffer within the 182662306a36Sopenharmony_ci * enclave. 182762306a36Sopenharmony_ci */ 182862306a36Sopenharmony_ci data_start = self->encl.encl_base + 182962306a36Sopenharmony_ci encl_get_data_offset(&self->encl) + PAGE_SIZE; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci /* 183262306a36Sopenharmony_ci * Sanity check that page at @data_start is writable before 183362306a36Sopenharmony_ci * removing it. 183462306a36Sopenharmony_ci * 183562306a36Sopenharmony_ci * Start by writing MAGIC to test page. 183662306a36Sopenharmony_ci */ 183762306a36Sopenharmony_ci put_addr_op.value = MAGIC; 183862306a36Sopenharmony_ci put_addr_op.addr = data_start; 183962306a36Sopenharmony_ci put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 184462306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 184562306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 184662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci /* 184962306a36Sopenharmony_ci * Read memory that was just written to, confirming that data 185062306a36Sopenharmony_ci * previously written (MAGIC) is present. 185162306a36Sopenharmony_ci */ 185262306a36Sopenharmony_ci get_addr_op.value = 0; 185362306a36Sopenharmony_ci get_addr_op.addr = data_start; 185462306a36Sopenharmony_ci get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci EXPECT_EQ(get_addr_op.value, MAGIC); 185962306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 186062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 186162306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 186262306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci /* Start page removal by requesting change of page type to PT_TRIM. */ 186562306a36Sopenharmony_ci memset(&ioc, 0, sizeof(ioc)); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; 186862306a36Sopenharmony_ci ioc.length = PAGE_SIZE; 186962306a36Sopenharmony_ci ioc.page_type = SGX_PAGE_TYPE_TRIM; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc); 187262306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 187562306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 187662306a36Sopenharmony_ci EXPECT_EQ(ioc.result, 0); 187762306a36Sopenharmony_ci EXPECT_EQ(ioc.count, 4096); 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci eaccept_op.epc_addr = (unsigned long)data_start; 188062306a36Sopenharmony_ci eaccept_op.ret = 0; 188162306a36Sopenharmony_ci eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED; 188262306a36Sopenharmony_ci eaccept_op.header.type = ENCL_OP_EACCEPT; 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 188762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 188862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 188962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 189062306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci /* Skip ioctl() to remove page. */ 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci /* 189562306a36Sopenharmony_ci * Read from page that was just removed. 189662306a36Sopenharmony_ci */ 189762306a36Sopenharmony_ci get_addr_op.value = 0; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci /* 190262306a36Sopenharmony_ci * From kernel perspective the page is present but according to SGX the 190362306a36Sopenharmony_ci * page should not be accessible so a #PF with SGX bit set is 190462306a36Sopenharmony_ci * expected. 190562306a36Sopenharmony_ci */ 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci EXPECT_EQ(self->run.function, ERESUME); 190862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 14); 190962306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0x8005); 191062306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, data_start); 191162306a36Sopenharmony_ci} 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ciTEST_F(enclave, remove_untouched_page) 191462306a36Sopenharmony_ci{ 191562306a36Sopenharmony_ci struct sgx_enclave_remove_pages remove_ioc; 191662306a36Sopenharmony_ci struct sgx_enclave_modify_types modt_ioc; 191762306a36Sopenharmony_ci struct encl_op_eaccept eaccept_op; 191862306a36Sopenharmony_ci unsigned long data_start; 191962306a36Sopenharmony_ci int ret, errno_save; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci /* 192462306a36Sopenharmony_ci * Hardware (SGX2) and kernel support is needed for this test. Start 192562306a36Sopenharmony_ci * with check that test has a chance of succeeding. 192662306a36Sopenharmony_ci */ 192762306a36Sopenharmony_ci memset(&modt_ioc, 0, sizeof(modt_ioc)); 192862306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci if (ret == -1) { 193162306a36Sopenharmony_ci if (errno == ENOTTY) 193262306a36Sopenharmony_ci SKIP(return, 193362306a36Sopenharmony_ci "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); 193462306a36Sopenharmony_ci else if (errno == ENODEV) 193562306a36Sopenharmony_ci SKIP(return, "System does not support SGX2"); 193662306a36Sopenharmony_ci } 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci /* 193962306a36Sopenharmony_ci * Invalid parameters were provided during sanity check, 194062306a36Sopenharmony_ci * expect command to fail. 194162306a36Sopenharmony_ci */ 194262306a36Sopenharmony_ci EXPECT_EQ(ret, -1); 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci /* SGX2 is supported by kernel and hardware, test can proceed. */ 194562306a36Sopenharmony_ci memset(&self->run, 0, sizeof(self->run)); 194662306a36Sopenharmony_ci self->run.tcs = self->encl.encl_base; 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci data_start = self->encl.encl_base + 194962306a36Sopenharmony_ci encl_get_data_offset(&self->encl) + PAGE_SIZE; 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci memset(&modt_ioc, 0, sizeof(modt_ioc)); 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci modt_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; 195462306a36Sopenharmony_ci modt_ioc.length = PAGE_SIZE; 195562306a36Sopenharmony_ci modt_ioc.page_type = SGX_PAGE_TYPE_TRIM; 195662306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); 195762306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 196062306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 196162306a36Sopenharmony_ci EXPECT_EQ(modt_ioc.result, 0); 196262306a36Sopenharmony_ci EXPECT_EQ(modt_ioc.count, 4096); 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci /* 196562306a36Sopenharmony_ci * Enter enclave via TCS #1 and approve page removal by sending 196662306a36Sopenharmony_ci * EACCEPT for removed page. 196762306a36Sopenharmony_ci */ 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci eaccept_op.epc_addr = data_start; 197062306a36Sopenharmony_ci eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED; 197162306a36Sopenharmony_ci eaccept_op.ret = 0; 197262306a36Sopenharmony_ci eaccept_op.header.type = ENCL_OP_EACCEPT; 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); 197562306a36Sopenharmony_ci EXPECT_EEXIT(&self->run); 197662306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_vector, 0); 197762306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_error_code, 0); 197862306a36Sopenharmony_ci EXPECT_EQ(self->run.exception_addr, 0); 197962306a36Sopenharmony_ci EXPECT_EQ(eaccept_op.ret, 0); 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci memset(&remove_ioc, 0, sizeof(remove_ioc)); 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci remove_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; 198462306a36Sopenharmony_ci remove_ioc.length = PAGE_SIZE; 198562306a36Sopenharmony_ci ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc); 198662306a36Sopenharmony_ci errno_save = ret == -1 ? errno : 0; 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci EXPECT_EQ(ret, 0); 198962306a36Sopenharmony_ci EXPECT_EQ(errno_save, 0); 199062306a36Sopenharmony_ci EXPECT_EQ(remove_ioc.count, 4096); 199162306a36Sopenharmony_ci} 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ciTEST_HARNESS_MAIN 1994