brintos

brintos / linux-shallow public Read only

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