From: Reinette Chatre <reinette.chatre@intel.com>
To: dave.hansen@linux.intel.com, jarkko@kernel.org,
tglx@linutronix.de, bp@alien8.de, luto@kernel.org,
mingo@redhat.com, linux-sgx@vger.kernel.org, x86@kernel.org
Cc: seanjc@google.com, kai.huang@intel.com, cathy.zhang@intel.com,
cedric.xing@intel.com, haitao.huang@intel.com,
mark.shanahan@intel.com, hpa@zytor.com,
linux-kernel@vger.kernel.org
Subject: [PATCH V2 21/32] selftests/sgx: Test two different SGX2 EAUG flows
Date: Mon, 7 Feb 2022 16:45:43 -0800 [thread overview]
Message-ID: <32c1116934a588bd3e6c174684e3e36a05c0a4d4.1644274683.git.reinette.chatre@intel.com> (raw)
In-Reply-To: <cover.1644274683.git.reinette.chatre@intel.com>
Enclave pages can be added to an initialized enclave when an address
belonging to the enclave but without a backing page is accessed from
within the enclave.
Accessing memory without a backing enclave page from within an enclave
can be in different ways:
1) Pre-emptively run ENCLU[EACCEPT]. Since the addition of a page
always needs to be accepted by the enclave via ENCLU[EACCEPT] this
flow is efficient since the first execution of ENCLU[EACCEPT]
triggers the addition of the page and when execution returns to the
same instruction the second execution would be successful as an
acceptance of the page.
2) A direct read or write. The flow where a direct read or write
triggers the page addition execution cannot resume from the
instruction (read/write) that triggered the fault but instead
the enclave needs to be entered at a different entry point to
run needed ENCLU[EACCEPT] before execution can return to the
original entry point and the read/write instruction that faulted.
Add tests for both flows.
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
Changes since v1:
- Replace __cpuid() definition and usage with __cpuid_count().
- Fix accuracy of comments.
tools/testing/selftests/sgx/main.c | 243 +++++++++++++++++++++++++++++
1 file changed, 243 insertions(+)
diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c
index 1398cd1b0983..68285603b3f0 100644
--- a/tools/testing/selftests/sgx/main.c
+++ b/tools/testing/selftests/sgx/main.c
@@ -86,6 +86,15 @@ static bool vdso_get_symtab(void *addr, struct vdso_symtab *symtab)
return true;
}
+static inline int sgx2_supported(void)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ __cpuid_count(SGX_CPUID, 0x0, eax, ebx, ecx, edx);
+
+ return eax & 0x2;
+}
+
static unsigned long elf_sym_hash(const char *name)
{
unsigned long h = 0, high;
@@ -882,4 +891,238 @@ TEST_F(enclave, epcm_permissions)
EXPECT_EQ(self->run.exception_addr, 0);
}
+/*
+ * Test the addition of pages to an initialized enclave via writing to
+ * a page belonging to the enclave's address space but was not added
+ * during enclave creation.
+ */
+TEST_F(enclave, augment)
+{
+ struct encl_op_get_from_addr get_addr_op;
+ struct encl_op_put_to_addr put_addr_op;
+ struct encl_op_eaccept eaccept_op;
+ size_t total_size = 0;
+ void *addr;
+ int i;
+
+ if (!sgx2_supported())
+ SKIP(return, "SGX2 not supported");
+
+ ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
+
+ memset(&self->run, 0, sizeof(self->run));
+ self->run.tcs = self->encl.encl_base;
+
+ for (i = 0; i < self->encl.nr_segments; i++) {
+ struct encl_segment *seg = &self->encl.segment_tbl[i];
+
+ total_size += seg->size;
+ }
+
+ /*
+ * Actual enclave size is expected to be larger than the loaded
+ * test enclave since enclave size must be a power of 2 in bytes
+ * and test_encl does not consume it all.
+ */
+ EXPECT_LT(total_size + PAGE_SIZE, self->encl.encl_size);
+
+ /*
+ * Create memory mapping for the page that will be added. New
+ * memory mapping is for one page right after all existing
+ * mappings.
+ */
+ addr = mmap((void *)self->encl.encl_base + total_size, PAGE_SIZE,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_SHARED | MAP_FIXED, self->encl.fd, 0);
+ EXPECT_NE(addr, MAP_FAILED);
+
+ self->run.exception_vector = 0;
+ self->run.exception_error_code = 0;
+ self->run.exception_addr = 0;
+
+ /*
+ * Attempt to write to the new page from within enclave.
+ * Expected to fail since page is not (yet) part of the enclave.
+ * The first #PF will trigger the addition of the page to the
+ * enclave, but since the new page needs an EACCEPT from within the
+ * enclave before it can be used it would not be possible
+ * to successfully return to the failing instruction. This is the
+ * cause of the second #PF captured here having the SGX bit set,
+ * it is from hardware preventing the page from being used.
+ */
+ put_addr_op.value = MAGIC;
+ put_addr_op.addr = (unsigned long)addr;
+ put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
+
+ EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
+
+ EXPECT_EQ(self->run.function, ERESUME);
+ EXPECT_EQ(self->run.exception_vector, 14);
+ EXPECT_EQ(self->run.exception_addr, (unsigned long)addr);
+
+ if (self->run.exception_error_code == 0x6) {
+ munmap(addr, PAGE_SIZE);
+ SKIP(return, "Kernel does not support adding pages to initialized enclave");
+ }
+
+ EXPECT_EQ(self->run.exception_error_code, 0x8007);
+
+ self->run.exception_vector = 0;
+ self->run.exception_error_code = 0;
+ self->run.exception_addr = 0;
+
+ /* Handle AEX by running EACCEPT from new entry point. */
+ self->run.tcs = self->encl.encl_base + PAGE_SIZE;
+
+ eaccept_op.epc_addr = self->encl.encl_base + total_size;
+ eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING;
+ eaccept_op.ret = 0;
+ eaccept_op.header.type = ENCL_OP_EACCEPT;
+
+ EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
+
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.exception_vector, 0);
+ EXPECT_EQ(self->run.exception_error_code, 0);
+ EXPECT_EQ(self->run.exception_addr, 0);
+ EXPECT_EQ(eaccept_op.ret, 0);
+
+ /* Can now return to main TCS to resume execution. */
+ self->run.tcs = self->encl.encl_base;
+
+ EXPECT_EQ(vdso_sgx_enter_enclave((unsigned long)&put_addr_op, 0, 0,
+ ERESUME, 0, 0,
+ &self->run),
+ 0);
+
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.exception_vector, 0);
+ EXPECT_EQ(self->run.exception_error_code, 0);
+ EXPECT_EQ(self->run.exception_addr, 0);
+
+ /*
+ * Read memory from newly added page that was just written to,
+ * confirming that data previously written (MAGIC) is present.
+ */
+ get_addr_op.value = 0;
+ get_addr_op.addr = (unsigned long)addr;
+ get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
+
+ EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
+
+ EXPECT_EQ(get_addr_op.value, MAGIC);
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.exception_vector, 0);
+ EXPECT_EQ(self->run.exception_error_code, 0);
+ EXPECT_EQ(self->run.exception_addr, 0);
+
+ munmap(addr, PAGE_SIZE);
+}
+
+/*
+ * Test for the addition of pages to an initialized enclave via a
+ * pre-emptive run of EACCEPT on page to be added.
+ */
+TEST_F(enclave, augment_via_eaccept)
+{
+ struct encl_op_get_from_addr get_addr_op;
+ struct encl_op_put_to_addr put_addr_op;
+ struct encl_op_eaccept eaccept_op;
+ size_t total_size = 0;
+ void *addr;
+ int i;
+
+ if (!sgx2_supported())
+ SKIP(return, "SGX2 not supported");
+
+ ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
+
+ memset(&self->run, 0, sizeof(self->run));
+ self->run.tcs = self->encl.encl_base;
+
+ for (i = 0; i < self->encl.nr_segments; i++) {
+ struct encl_segment *seg = &self->encl.segment_tbl[i];
+
+ total_size += seg->size;
+ }
+
+ /*
+ * Actual enclave size is expected to be larger than the loaded
+ * test enclave since enclave size must be a power of 2 in bytes while
+ * test_encl does not consume it all.
+ */
+ EXPECT_LT(total_size + PAGE_SIZE, self->encl.encl_size);
+
+ /*
+ * mmap() a page at end of existing enclave to be used for dynamic
+ * EPC page.
+ */
+
+ addr = mmap((void *)self->encl.encl_base + total_size, PAGE_SIZE,
+ PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED,
+ self->encl.fd, 0);
+ EXPECT_NE(addr, MAP_FAILED);
+
+ self->run.exception_vector = 0;
+ self->run.exception_error_code = 0;
+ self->run.exception_addr = 0;
+
+ /*
+ * Run EACCEPT on new page to trigger the #PF->EAUG->EACCEPT(again
+ * without a #PF). All should be transparent to userspace.
+ */
+ eaccept_op.epc_addr = self->encl.encl_base + total_size;
+ eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING;
+ eaccept_op.ret = 0;
+ eaccept_op.header.type = ENCL_OP_EACCEPT;
+
+ EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
+
+ if (self->run.exception_vector == 14 &&
+ self->run.exception_error_code == 4 &&
+ self->run.exception_addr == self->encl.encl_base + total_size) {
+ munmap(addr, PAGE_SIZE);
+ SKIP(return, "Kernel does not support adding pages to initialized enclave");
+ }
+
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.exception_vector, 0);
+ EXPECT_EQ(self->run.exception_error_code, 0);
+ EXPECT_EQ(self->run.exception_addr, 0);
+ EXPECT_EQ(eaccept_op.ret, 0);
+
+ /*
+ * New page should be accessible from within enclave - attempt to
+ * write to it.
+ */
+ put_addr_op.value = MAGIC;
+ put_addr_op.addr = (unsigned long)addr;
+ put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
+
+ EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
+
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.exception_vector, 0);
+ EXPECT_EQ(self->run.exception_error_code, 0);
+ EXPECT_EQ(self->run.exception_addr, 0);
+
+ /*
+ * Read memory from newly added page that was just written to,
+ * confirming that data previously written (MAGIC) is present.
+ */
+ get_addr_op.value = 0;
+ get_addr_op.addr = (unsigned long)addr;
+ get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
+
+ EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
+
+ EXPECT_EQ(get_addr_op.value, MAGIC);
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.exception_vector, 0);
+ EXPECT_EQ(self->run.exception_error_code, 0);
+ EXPECT_EQ(self->run.exception_addr, 0);
+
+ munmap(addr, PAGE_SIZE);
+}
+
TEST_HARNESS_MAIN
--
2.25.1
next prev parent reply other threads:[~2022-02-08 1:07 UTC|newest]
Thread overview: 130+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-08 0:45 [PATCH V2 00/32] x86/sgx and selftests/sgx: Support SGX2 Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 01/32] x86/sgx: Add short descriptions to ENCLS wrappers Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 02/32] x86/sgx: Add wrapper for SGX2 EMODPR function Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 03/32] x86/sgx: Add wrapper for SGX2 EMODT function Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 04/32] x86/sgx: Add wrapper for SGX2 EAUG function Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 05/32] Documentation/x86: Document SGX permission details Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 06/32] x86/sgx: Support VMA permissions more relaxed than enclave permissions Reinette Chatre
2022-03-07 17:10 ` Jarkko Sakkinen
2022-03-07 17:36 ` Reinette Chatre
2022-03-08 8:14 ` Jarkko Sakkinen
2022-03-08 9:06 ` Jarkko Sakkinen
2022-03-08 9:12 ` Jarkko Sakkinen
2022-03-08 16:04 ` Reinette Chatre
2022-03-08 17:00 ` Jarkko Sakkinen
2022-03-08 17:49 ` Reinette Chatre
2022-03-08 18:46 ` Jarkko Sakkinen
2022-03-11 11:06 ` Dr. Greg
2022-02-08 0:45 ` [PATCH V2 07/32] x86/sgx: Add pfn_mkwrite() handler for present PTEs Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 08/32] x86/sgx: x86/sgx: Add sgx_encl_page->vm_run_prot_bits for dynamic permission changes Reinette Chatre
2022-03-04 8:55 ` Jarkko Sakkinen
2022-03-04 19:19 ` Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 09/32] x86/sgx: Export sgx_encl_ewb_cpumask() Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 10/32] x86/sgx: Rename sgx_encl_ewb_cpumask() as sgx_encl_cpumask() Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 11/32] x86/sgx: Move PTE zap code to new sgx_zap_enclave_ptes() Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 12/32] x86/sgx: Make sgx_ipi_cb() available internally Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 13/32] x86/sgx: Create utility to validate user provided offset and length Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 14/32] x86/sgx: Keep record of SGX page type Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 15/32] x86/sgx: Support relaxing of enclave page permissions Reinette Chatre
2022-03-04 8:59 ` Jarkko Sakkinen
2022-02-08 0:45 ` [PATCH V2 16/32] x86/sgx: Support restricting " Reinette Chatre
2022-02-21 0:49 ` Jarkko Sakkinen
2022-02-22 18:35 ` Reinette Chatre
2022-02-23 15:46 ` Jarkko Sakkinen
2022-02-23 19:55 ` Reinette Chatre
2022-02-28 12:27 ` Jarkko Sakkinen
2022-02-23 19:21 ` Dhanraj, Vijay
2022-02-23 22:42 ` Reinette Chatre
2022-02-28 12:24 ` Jarkko Sakkinen
2022-02-28 13:19 ` Jarkko Sakkinen
2022-02-28 15:16 ` Dave Hansen
2022-02-28 17:44 ` Dhanraj, Vijay
2022-03-01 13:26 ` Jarkko Sakkinen
2022-03-01 13:42 ` Jarkko Sakkinen
2022-03-01 17:48 ` Reinette Chatre
2022-03-02 2:05 ` Jarkko Sakkinen
2022-03-02 2:11 ` Jarkko Sakkinen
2022-03-02 4:03 ` Jarkko Sakkinen
2022-03-02 22:57 ` Reinette Chatre
2022-03-03 16:08 ` Haitao Huang
2022-03-03 21:23 ` Reinette Chatre
2022-03-03 21:44 ` Dave Hansen
2022-03-05 3:19 ` Jarkko Sakkinen
2022-03-06 0:15 ` Jarkko Sakkinen
2022-03-06 0:25 ` Jarkko Sakkinen
2022-03-10 5:43 ` Jarkko Sakkinen
2022-03-10 5:59 ` Jarkko Sakkinen
2022-03-03 23:18 ` Jarkko Sakkinen
2022-03-04 4:03 ` Haitao Huang
2022-03-04 8:30 ` Jarkko Sakkinen
2022-03-04 15:51 ` Haitao Huang
2022-03-05 1:02 ` Jarkko Sakkinen
2022-03-06 14:24 ` Haitao Huang
2022-03-03 23:12 ` Jarkko Sakkinen
2022-03-04 0:48 ` Reinette Chatre
2022-03-10 6:10 ` Jarkko Sakkinen
2022-03-10 18:33 ` Haitao Huang
2022-03-11 12:10 ` Jarkko Sakkinen
2022-03-11 12:16 ` Jarkko Sakkinen
2022-03-11 12:33 ` Jarkko Sakkinen
2022-03-11 17:53 ` Reinette Chatre
2022-03-11 18:11 ` Jarkko Sakkinen
2022-03-11 19:28 ` Reinette Chatre
2022-03-14 3:42 ` Jarkko Sakkinen
2022-03-14 3:45 ` Jarkko Sakkinen
2022-03-14 3:54 ` Jarkko Sakkinen
2022-03-14 15:32 ` Reinette Chatre
2022-03-17 4:30 ` Jarkko Sakkinen
2022-03-17 22:08 ` Reinette Chatre
2022-03-17 22:51 ` Jarkko Sakkinen
2022-03-18 0:11 ` Reinette Chatre
2022-03-20 0:24 ` Jarkko Sakkinen
2022-03-28 23:22 ` Reinette Chatre
2022-03-30 15:00 ` Jarkko Sakkinen
2022-03-30 15:02 ` Jarkko Sakkinen
2022-03-14 2:49 ` Jarkko Sakkinen
2022-03-14 2:50 ` Jarkko Sakkinen
2022-03-14 2:58 ` Jarkko Sakkinen
2022-03-14 15:39 ` Haitao Huang
2022-03-17 4:34 ` Jarkko Sakkinen
2022-03-17 14:42 ` Haitao Huang
2022-03-17 4:37 ` Jarkko Sakkinen
2022-03-17 14:47 ` Haitao Huang
2022-03-17 7:01 ` Jarkko Sakkinen
2022-03-17 7:11 ` Jarkko Sakkinen
2022-03-17 14:28 ` Haitao Huang
2022-03-17 21:50 ` Jarkko Sakkinen
2022-03-17 22:00 ` Jarkko Sakkinen
2022-03-17 22:23 ` Jarkko Sakkinen
2022-02-08 0:45 ` [PATCH V2 17/32] selftests/sgx: Add test for EPCM permission changes Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 18/32] selftests/sgx: Add test for TCS page " Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 19/32] x86/sgx: Support adding of pages to an initialized enclave Reinette Chatre
2022-02-19 11:57 ` Jarkko Sakkinen
2022-02-19 12:01 ` Jarkko Sakkinen
2022-02-20 18:40 ` Jarkko Sakkinen
2022-02-22 19:19 ` Reinette Chatre
2022-02-23 15:46 ` Jarkko Sakkinen
2022-03-07 16:16 ` Jarkko Sakkinen
2022-02-08 0:45 ` [PATCH V2 20/32] x86/sgx: Tighten accessible memory range after enclave initialization Reinette Chatre
2022-02-08 0:45 ` Reinette Chatre [this message]
2022-03-07 16:39 ` [PATCH V2 21/32] selftests/sgx: Test two different SGX2 EAUG flows Jarkko Sakkinen
2022-02-08 0:45 ` [PATCH V2 22/32] x86/sgx: Support modifying SGX page type Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 23/32] x86/sgx: Support complete page removal Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 24/32] Documentation/x86: Introduce enclave runtime management section Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 25/32] selftests/sgx: Introduce dynamic entry point Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 26/32] selftests/sgx: Introduce TCS initialization enclave operation Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 27/32] selftests/sgx: Test complete changing of page type flow Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 28/32] selftests/sgx: Test faulty enclave behavior Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 29/32] selftests/sgx: Test invalid access to removed enclave page Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 30/32] selftests/sgx: Test reclaiming of untouched page Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 31/32] x86/sgx: Free up EPC pages directly to support large page ranges Reinette Chatre
2022-02-08 0:45 ` [PATCH V2 32/32] selftests/sgx: Page removal stress test Reinette Chatre
2022-02-22 20:27 ` [PATCH V2 00/32] x86/sgx and selftests/sgx: Support SGX2 Nathaniel McCallum
2022-02-22 22:39 ` Reinette Chatre
2022-02-23 13:24 ` Nathaniel McCallum
2022-02-23 18:25 ` Reinette Chatre
2022-03-02 16:57 ` Nathaniel McCallum
2022-03-02 21:20 ` Reinette Chatre
2022-03-03 1:13 ` Nathaniel McCallum
2022-03-03 17:49 ` Reinette Chatre
2022-03-04 0:57 ` Jarkko Sakkinen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=32c1116934a588bd3e6c174684e3e36a05c0a4d4.1644274683.git.reinette.chatre@intel.com \
--to=reinette.chatre@intel.com \
--cc=bp@alien8.de \
--cc=cathy.zhang@intel.com \
--cc=cedric.xing@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=haitao.huang@intel.com \
--cc=hpa@zytor.com \
--cc=jarkko@kernel.org \
--cc=kai.huang@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sgx@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mark.shanahan@intel.com \
--cc=mingo@redhat.com \
--cc=seanjc@google.com \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).