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