diff options
author | Jarkko Sakkinen | 2022-05-13 09:11:26 +0300 |
---|---|---|
committer | Jarkko Sakkinen | 2022-05-13 09:14:34 +0300 |
commit | 1c9f12ad04044fca8cbf602e3295c26b0829ea97 (patch) | |
tree | 4a0ec208cd7c2cb5d0354e98a03e4ed7a108dd70 | |
parent | 1197ad7586a7c19e4877147b740e6cecef3814f5 (diff) | |
download | aur-1c9f12ad04044fca8cbf602e3295c26b0829ea97.tar.gz |
build: update to 5.17.7.arch1
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@iki.fi>
38 files changed, 3003 insertions, 199 deletions
@@ -1,8 +1,8 @@ pkgbase = linux-sgx pkgdesc = Linux - pkgver = 5.17.4.arch1 + pkgver = 5.17.7.arch1 pkgrel = 1 - url = https://github.com/archlinux/linux/commits/v5.17.4.arch1 + url = https://github.com/archlinux/linux/commits/v5.17.7.arch1 arch = x86_64 license = GPL2 makedepends = bc @@ -20,7 +20,7 @@ pkgbase = linux-sgx makedepends = imagemagick makedepends = git options = !strip - source = archlinux-linux::git+https://github.com/archlinux/linux?signed#tag=v5.17.4-arch1 + source = archlinux-linux::git+https://github.com/archlinux/linux?signed#tag=v5.17.7-arch1 source = config validpgpkeys = ABAF11C65A2970B130ABE3C479BE3E4300411886 validpgpkeys = 647F28654894E3BD457199BE38DBBDC86092693E diff --git a/0001-x86-sgx-Disconnect-backing-page-references-from-dirt.patch b/0001-x86-sgx-Disconnect-backing-page-references-from-dirt.patch new file mode 100644 index 000000000000..4d9839913e31 --- /dev/null +++ b/0001-x86-sgx-Disconnect-backing-page-references-from-dirt.patch @@ -0,0 +1,167 @@ +From 16c0d19cdf8ea458d7388593e7f9537bd545f3a7 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Thu, 12 May 2022 14:50:57 -0700 +Subject: [PATCH 01/36] x86/sgx: Disconnect backing page references from dirty + status + +SGX uses shmem backing storage to store encrypted enclave pages +and their crypto metadata when enclave pages are moved out of +enclave memory. Two shmem backing storage pages are associated with +each enclave page - one backing page to contain the encrypted +enclave page data and one backing page (shared by a few +enclave pages) to contain the crypto metadata used by the +processor to verify the enclave page when it is loaded back into +the enclave. + +sgx_encl_put_backing() is used to release references to the +backing storage and, optionally, mark both backing store pages +as dirty. + +Managing references and dirty status together in this way results +in both backing store pages marked as dirty, even if only one of +the backing store pages are changed. + +Additionally, waiting until the page reference is dropped to set +the page dirty risks a race with the page fault handler that +may load outdated data into the enclave when a page is faulted +right after it is reclaimed. + +Consider what happens if the reclaimer writes a page to the backing +store and the page is immediately faulted back, before the reclaimer +is able to set the dirty bit of the page: + +sgx_reclaim_pages() { sgx_vma_fault() { + ... + sgx_encl_get_backing(); + ... ... + sgx_reclaimer_write() { + mutex_lock(&encl->lock); + /* Write data to backing store */ + mutex_unlock(&encl->lock); + } + mutex_lock(&encl->lock); + __sgx_encl_eldu() { + ... + /* + * Enclave backing store + * page not released + * nor marked dirty - + * contents may not be + * up to date. + */ + sgx_encl_get_backing(); + ... + /* + * Enclave data restored + * from backing store + * and PCMD pages that + * are not up to date. + * ENCLS[ELDU] faults + * because of MAC or PCMD + * checking failure. + */ + sgx_encl_put_backing(); + } + ... + /* set page dirty */ + sgx_encl_put_backing(); + ... + mutex_unlock(&encl->lock); +} } + +Remove the option to sgx_encl_put_backing() to set the backing +pages as dirty and set the needed pages as dirty right after +receiving important data while enclave mutex is held. This ensures that +the page fault handler can get up to date data from a page and prepares +the code for a following change where only one of the backing pages +need to be marked as dirty. + +Cc: stable@vger.kernel.org +Fixes: 1728ab54b4be ("x86/sgx: Add a page reclaimer") +Suggested-by: Dave Hansen <dave.hansen@linux.intel.com> +Tested-by: Haitao Huang <haitao.huang@intel.com> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +Link: https://lore.kernel.org/linux-sgx/8922e48f-6646-c7cc-6393-7c78dcf23d23@intel.com/ +--- + arch/x86/kernel/cpu/sgx/encl.c | 10 ++-------- + arch/x86/kernel/cpu/sgx/encl.h | 2 +- + arch/x86/kernel/cpu/sgx/main.c | 6 ++++-- + 3 files changed, 7 insertions(+), 11 deletions(-) + +diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c +index 7c63a1911fae..398695a20605 100644 +--- a/arch/x86/kernel/cpu/sgx/encl.c ++++ b/arch/x86/kernel/cpu/sgx/encl.c +@@ -94,7 +94,7 @@ static int __sgx_encl_eldu(struct sgx_encl_page *encl_page, + kunmap_atomic(pcmd_page); + kunmap_atomic((void *)(unsigned long)pginfo.contents); + +- sgx_encl_put_backing(&b, false); ++ sgx_encl_put_backing(&b); + + sgx_encl_truncate_backing_page(encl, page_index); + +@@ -645,15 +645,9 @@ int sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index, + /** + * sgx_encl_put_backing() - Unpin the backing storage + * @backing: data for accessing backing storage for the page +- * @do_write: mark pages dirty + */ +-void sgx_encl_put_backing(struct sgx_backing *backing, bool do_write) ++void sgx_encl_put_backing(struct sgx_backing *backing) + { +- if (do_write) { +- set_page_dirty(backing->pcmd); +- set_page_dirty(backing->contents); +- } +- + put_page(backing->pcmd); + put_page(backing->contents); + } +diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h +index fec43ca65065..d44e7372151f 100644 +--- a/arch/x86/kernel/cpu/sgx/encl.h ++++ b/arch/x86/kernel/cpu/sgx/encl.h +@@ -107,7 +107,7 @@ void sgx_encl_release(struct kref *ref); + int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm); + int sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index, + struct sgx_backing *backing); +-void sgx_encl_put_backing(struct sgx_backing *backing, bool do_write); ++void sgx_encl_put_backing(struct sgx_backing *backing); + int sgx_encl_test_and_clear_young(struct mm_struct *mm, + struct sgx_encl_page *page); + +diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c +index 8e4bc6453d26..e71df40a4f38 100644 +--- a/arch/x86/kernel/cpu/sgx/main.c ++++ b/arch/x86/kernel/cpu/sgx/main.c +@@ -191,6 +191,8 @@ static int __sgx_encl_ewb(struct sgx_epc_page *epc_page, void *va_slot, + backing->pcmd_offset; + + ret = __ewb(&pginfo, sgx_get_epc_virt_addr(epc_page), va_slot); ++ set_page_dirty(backing->pcmd); ++ set_page_dirty(backing->contents); + + kunmap_atomic((void *)(unsigned long)(pginfo.metadata - + backing->pcmd_offset)); +@@ -320,7 +322,7 @@ static void sgx_reclaimer_write(struct sgx_epc_page *epc_page, + sgx_encl_free_epc_page(encl->secs.epc_page); + encl->secs.epc_page = NULL; + +- sgx_encl_put_backing(&secs_backing, true); ++ sgx_encl_put_backing(&secs_backing); + } + + out: +@@ -411,7 +413,7 @@ static void sgx_reclaim_pages(void) + + encl_page = epc_page->owner; + sgx_reclaimer_write(epc_page, &backing[i]); +- sgx_encl_put_backing(&backing[i], true); ++ sgx_encl_put_backing(&backing[i]); + + kref_put(&encl_page->encl->refcount, sgx_encl_release); + epc_page->flags &= ~SGX_EPC_PAGE_RECLAIMER_TRACKED; +-- +2.36.1 + diff --git a/0002-x86-sgx-Mark-PCMD-page-as-dirty-when-modifying-conte.patch b/0002-x86-sgx-Mark-PCMD-page-as-dirty-when-modifying-conte.patch new file mode 100644 index 000000000000..b1dabf98c596 --- /dev/null +++ b/0002-x86-sgx-Mark-PCMD-page-as-dirty-when-modifying-conte.patch @@ -0,0 +1,39 @@ +From 29ebcc3dd06578be9cb3d59007e9466cb336f618 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Thu, 12 May 2022 14:50:58 -0700 +Subject: [PATCH 02/36] x86/sgx: Mark PCMD page as dirty when modifying + contents + +Recent commit 08999b2489b4 ("x86/sgx: Free backing memory +after faulting the enclave page") expanded __sgx_encl_eldu() +to clear an enclave page's PCMD (Paging Crypto MetaData) +from the PCMD page in the backing store after the enclave +page is restored to the enclave. + +Since the PCMD page in the backing store is modified the page +should be marked as dirty to ensure the modified data is retained. + +Cc: stable@vger.kernel.org +Fixes: 08999b2489b4 ("x86/sgx: Free backing memory after faulting the enclave page") +Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> +Tested-by: Haitao Huang <haitao.huang@intel.com> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + arch/x86/kernel/cpu/sgx/encl.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c +index 398695a20605..5104a428b72c 100644 +--- a/arch/x86/kernel/cpu/sgx/encl.c ++++ b/arch/x86/kernel/cpu/sgx/encl.c +@@ -84,6 +84,7 @@ static int __sgx_encl_eldu(struct sgx_encl_page *encl_page, + } + + memset(pcmd_page + b.pcmd_offset, 0, sizeof(struct sgx_pcmd)); ++ set_page_dirty(b.pcmd); + + /* + * The area for the PCMD in the page was zeroed above. Check if the +-- +2.36.1 + diff --git a/0003-x86-sgx-Obtain-backing-storage-page-with-enclave-mut.patch b/0003-x86-sgx-Obtain-backing-storage-page-with-enclave-mut.patch new file mode 100644 index 000000000000..622b25abd6b5 --- /dev/null +++ b/0003-x86-sgx-Obtain-backing-storage-page-with-enclave-mut.patch @@ -0,0 +1,130 @@ +From a455a2c6f55a696cfe170f3f62c1390760dab06c Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Thu, 12 May 2022 14:50:59 -0700 +Subject: [PATCH 03/36] x86/sgx: Obtain backing storage page with enclave mutex + held + +Haitao reported encountering a WARN triggered by the ENCLS[ELDU] +instruction faulting with a #GP. + +The WARN is encountered when the reclaimer evicts a range of +pages from the enclave when the same pages are faulted back +right away. + +The SGX backing storage is accessed on two paths: when there +are insufficient free pages in the EPC the reclaimer works +to move enclave pages to the backing storage and as enclaves +access pages that have been moved to the backing storage +they are retrieved from there as part of page fault handling. + +An oversubscribed SGX system will often run the reclaimer and +page fault handler concurrently and needs to ensure that the +backing store is accessed safely between the reclaimer and +the page fault handler. This is not the case because the +reclaimer accesses the backing store without the enclave mutex +while the page fault handler accesses the backing store with +the enclave mutex. + +Consider the scenario where a page is faulted while a page sharing +a PCMD page with the faulted page is being reclaimed. The +consequence is a race between the reclaimer and page fault +handler, the reclaimer attempting to access a PCMD at the +same time it is truncated by the page fault handler. This +could result in lost PCMD data. Data may still be +lost if the reclaimer wins the race, this is addressed in +the following patch. + +The reclaimer accesses pages from the backing storage without +holding the enclave mutex and runs the risk of concurrently +accessing the backing storage with the page fault handler that +does access the backing storage with the enclave mutex held. + +In the scenario below a PCMD page is truncated from the backing +store after all its pages have been loaded in to the enclave +at the same time the PCMD page is loaded from the backing store +when one of its pages are reclaimed: + +sgx_reclaim_pages() { sgx_vma_fault() { + ... + mutex_lock(&encl->lock); + ... + __sgx_encl_eldu() { + ... + if (pcmd_page_empty) { +/* + * EPC page being reclaimed /* + * shares a PCMD page with an * PCMD page truncated + * enclave page that is being * while requested from + * faulted in. * reclaimer. + */ */ +sgx_encl_get_backing() <----------> sgx_encl_truncate_backing_page() + } + mutex_unlock(&encl->lock); +} } + +In this scenario there is a race between the reclaimer and the page fault +handler when the reclaimer attempts to get access to the same PCMD page +that is being truncated. This could result in the reclaimer writing to +the PCMD page that is then truncated, causing the PCMD data to be lost, +or in a new PCMD page being allocated. The lost PCMD data may still occur +after protecting the backing store access with the mutex - this is fixed +in the next patch. By ensuring the backing store is accessed with the mutex +held the enclave page state can be made accurate with the +SGX_ENCL_PAGE_BEING_RECLAIMED flag accurately reflecting that a page +is in the process of being reclaimed. + +Consistently protect the reclaimer's backing store access with the +enclave's mutex to ensure that it can safely run concurrently with the +page fault handler. + +Cc: stable@vger.kernel.org +Fixes: 1728ab54b4be ("x86/sgx: Add a page reclaimer") +Reported-by: Haitao Huang <haitao.huang@intel.com> +Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> +Tested-by: Jarkko Sakkinen <jarkko@kernel.org> +Tested-by: Haitao Huang <haitao.huang@intel.com> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + arch/x86/kernel/cpu/sgx/main.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c +index e71df40a4f38..ab4ec54bbdd9 100644 +--- a/arch/x86/kernel/cpu/sgx/main.c ++++ b/arch/x86/kernel/cpu/sgx/main.c +@@ -310,6 +310,7 @@ static void sgx_reclaimer_write(struct sgx_epc_page *epc_page, + sgx_encl_ewb(epc_page, backing); + encl_page->epc_page = NULL; + encl->secs_child_cnt--; ++ sgx_encl_put_backing(backing); + + if (!encl->secs_child_cnt && test_bit(SGX_ENCL_INITIALIZED, &encl->flags)) { + ret = sgx_encl_get_backing(encl, PFN_DOWN(encl->size), +@@ -381,11 +382,14 @@ static void sgx_reclaim_pages(void) + goto skip; + + page_index = PFN_DOWN(encl_page->desc - encl_page->encl->base); ++ ++ mutex_lock(&encl_page->encl->lock); + ret = sgx_encl_get_backing(encl_page->encl, page_index, &backing[i]); +- if (ret) ++ if (ret) { ++ mutex_unlock(&encl_page->encl->lock); + goto skip; ++ } + +- mutex_lock(&encl_page->encl->lock); + encl_page->desc |= SGX_ENCL_PAGE_BEING_RECLAIMED; + mutex_unlock(&encl_page->encl->lock); + continue; +@@ -413,7 +417,6 @@ static void sgx_reclaim_pages(void) + + encl_page = epc_page->owner; + sgx_reclaimer_write(epc_page, &backing[i]); +- sgx_encl_put_backing(&backing[i]); + + kref_put(&encl_page->encl->refcount, sgx_encl_release); + epc_page->flags &= ~SGX_EPC_PAGE_RECLAIMER_TRACKED; +-- +2.36.1 + diff --git a/0004-x86-sgx-Fix-race-between-reclaimer-and-page-fault-ha.patch b/0004-x86-sgx-Fix-race-between-reclaimer-and-page-fault-ha.patch new file mode 100644 index 000000000000..85cc8359b731 --- /dev/null +++ b/0004-x86-sgx-Fix-race-between-reclaimer-and-page-fault-ha.patch @@ -0,0 +1,255 @@ +From c5894032c2cbbc1836785f2d0150bc34305760ae Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Thu, 12 May 2022 14:51:00 -0700 +Subject: [PATCH 04/36] x86/sgx: Fix race between reclaimer and page fault + handler + +Haitao reported encountering a WARN triggered by the ENCLS[ELDU] +instruction faulting with a #GP. + +The WARN is encountered when the reclaimer evicts a range of +pages from the enclave when the same pages are faulted back right away. + +Consider two enclave pages (ENCLAVE_A and ENCLAVE_B) +sharing a PCMD page (PCMD_AB). ENCLAVE_A is in the +enclave memory and ENCLAVE_B is in the backing store. PCMD_AB contains +just one entry, that of ENCLAVE_B. + +Scenario proceeds where ENCLAVE_A is being evicted from the enclave +while ENCLAVE_B is faulted in. + +sgx_reclaim_pages() { + + ... + + /* + * Reclaim ENCLAVE_A + */ + mutex_lock(&encl->lock); + /* + * Get a reference to ENCLAVE_A's + * shmem page where enclave page + * encrypted data will be stored + * as well as a reference to the + * enclave page's PCMD data page, + * PCMD_AB. + * Release mutex before writing + * any data to the shmem pages. + */ + sgx_encl_get_backing(...); + encl_page->desc |= SGX_ENCL_PAGE_BEING_RECLAIMED; + mutex_unlock(&encl->lock); + + /* + * Fault ENCLAVE_B + */ + + sgx_vma_fault() { + + mutex_lock(&encl->lock); + /* + * Get reference to + * ENCLAVE_B's shmem page + * as well as PCMD_AB. + */ + sgx_encl_get_backing(...) + /* + * Load page back into + * enclave via ELDU. + */ + /* + * Release reference to + * ENCLAVE_B' shmem page and + * PCMD_AB. + */ + sgx_encl_put_backing(...); + /* + * PCMD_AB is found empty so + * it and ENCLAVE_B's shmem page + * are truncated. + */ + /* Truncate ENCLAVE_B backing page */ + sgx_encl_truncate_backing_page(); + /* Truncate PCMD_AB */ + sgx_encl_truncate_backing_page(); + + mutex_unlock(&encl->lock); + + ... + } + mutex_lock(&encl->lock); + encl_page->desc &= + ~SGX_ENCL_PAGE_BEING_RECLAIMED; + /* + * Write encrypted contents of + * ENCLAVE_A to ENCLAVE_A shmem + * page and its PCMD data to + * PCMD_AB. + */ + sgx_encl_put_backing(...) + + /* + * Reference to PCMD_AB is + * dropped and it is truncated. + * ENCLAVE_A's PCMD data is lost. + */ + mutex_unlock(&encl->lock); +} + +What happens next depends on whether it is ENCLAVE_A being faulted +in or ENCLAVE_B being evicted - but both end up with ENCLS[ELDU] faulting +with a #GP. + +If ENCLAVE_A is faulted then at the time sgx_encl_get_backing() is called +a new PCMD page is allocated and providing the empty PCMD data for +ENCLAVE_A would cause ENCLS[ELDU] to #GP + +If ENCLAVE_B is evicted first then a new PCMD_AB would be allocated by the +reclaimer but later when ENCLAVE_A is faulted the ENCLS[ELDU] instruction +would #GP during its checks of the PCMD value and the WARN would be +encountered. + +Noting that the reclaimer sets SGX_ENCL_PAGE_BEING_RECLAIMED at the time +it obtains a reference to the backing store pages of an enclave page it +is in the process of reclaiming, fix the race by only truncating the PCMD +page after ensuring that no page sharing the PCMD page is in the process +of being reclaimed. + +Cc: stable@vger.kernel.org +Fixes: 08999b2489b4 ("x86/sgx: Free backing memory after faulting the enclave page") +Reported-by: Haitao Huang <haitao.huang@intel.com> +Tested-by: Haitao Huang <haitao.huang@intel.com> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + arch/x86/kernel/cpu/sgx/encl.c | 94 +++++++++++++++++++++++++++++++++- + 1 file changed, 93 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c +index 5104a428b72c..243f3bd78145 100644 +--- a/arch/x86/kernel/cpu/sgx/encl.c ++++ b/arch/x86/kernel/cpu/sgx/encl.c +@@ -12,6 +12,92 @@ + #include "encls.h" + #include "sgx.h" + ++#define PCMDS_PER_PAGE (PAGE_SIZE / sizeof(struct sgx_pcmd)) ++/* ++ * 32 PCMD entries share a PCMD page. PCMD_FIRST_MASK is used to ++ * determine the page index associated with the first PCMD entry ++ * within a PCMD page. ++ */ ++#define PCMD_FIRST_MASK GENMASK(4, 0) ++ ++/** ++ * reclaimer_writing_to_pcmd() - Query if any enclave page associated with ++ * a PCMD page is in process of being reclaimed. ++ * @encl: Enclave to which PCMD page belongs ++ * @start_addr: Address of enclave page using first entry within the PCMD page ++ * ++ * When an enclave page is reclaimed some Paging Crypto MetaData (PCMD) is ++ * stored. The PCMD data of a reclaimed enclave page contains enough ++ * information for the processor to verify the page at the time ++ * it is loaded back into the Enclave Page Cache (EPC). ++ * ++ * The backing storage to which enclave pages are reclaimed is laid out as ++ * follows: ++ * Encrypted enclave pages:SECS page:PCMD pages ++ * ++ * Each PCMD page contains the PCMD metadata of ++ * PAGE_SIZE/sizeof(struct sgx_pcmd) enclave pages. ++ * ++ * A PCMD page can only be truncated if it is (a) empty, and (b) not in the ++ * process of getting data (and thus soon being non-empty). (b) is tested with ++ * a check if an enclave page sharing the PCMD page is in the process of being ++ * reclaimed. ++ * ++ * The reclaimer sets the SGX_ENCL_PAGE_BEING_RECLAIMED flag when it ++ * intends to reclaim that enclave page - it means that the PCMD page ++ * associated with that enclave page is about to get some data and thus ++ * even if the PCMD page is empty, it should not be truncated. ++ * ++ * Context: Enclave mutex (&sgx_encl->lock) must be held. ++ * Return: 1 if the reclaimer is about to write to the PCMD page ++ * 0 if the reclaimer has no intention to write to the PCMD page ++ */ ++static int reclaimer_writing_to_pcmd(struct sgx_encl *encl, ++ unsigned long start_addr) ++{ ++ int reclaimed = 0; ++ int i; ++ ++ /* ++ * PCMD_FIRST_MASK is based on number of PCMD entries within ++ * PCMD page being 32. ++ */ ++ BUILD_BUG_ON(PCMDS_PER_PAGE != 32); ++ ++ for (i = 0; i < PCMDS_PER_PAGE; i++) { ++ struct sgx_encl_page *entry; ++ unsigned long addr; ++ ++ addr = start_addr + i * PAGE_SIZE; ++ ++ /* ++ * Stop when reaching the SECS page - it does not ++ * have a page_array entry and its reclaim is ++ * started and completed with enclave mutex held so ++ * it does not use the SGX_ENCL_PAGE_BEING_RECLAIMED ++ * flag. ++ */ ++ if (addr == encl->base + encl->size) ++ break; ++ ++ entry = xa_load(&encl->page_array, PFN_DOWN(addr)); ++ if (!entry) ++ continue; ++ ++ /* ++ * VA page slot ID uses same bit as the flag so it is important ++ * to ensure that the page is not already in backing store. ++ */ ++ if (entry->epc_page && ++ (entry->desc & SGX_ENCL_PAGE_BEING_RECLAIMED)) { ++ reclaimed = 1; ++ break; ++ } ++ } ++ ++ return reclaimed; ++} ++ + /* + * Calculate byte offset of a PCMD struct associated with an enclave page. PCMD's + * follow right after the EPC data in the backing storage. In addition to the +@@ -47,6 +133,7 @@ static int __sgx_encl_eldu(struct sgx_encl_page *encl_page, + unsigned long va_offset = encl_page->desc & SGX_ENCL_PAGE_VA_OFFSET_MASK; + struct sgx_encl *encl = encl_page->encl; + pgoff_t page_index, page_pcmd_off; ++ unsigned long pcmd_first_page; + struct sgx_pageinfo pginfo; + struct sgx_backing b; + bool pcmd_page_empty; +@@ -58,6 +145,11 @@ static int __sgx_encl_eldu(struct sgx_encl_page *encl_page, + else + page_index = PFN_DOWN(encl->size); + ++ /* ++ * Address of enclave page using the first entry within the PCMD page. ++ */ ++ pcmd_first_page = PFN_PHYS(page_index & ~PCMD_FIRST_MASK) + encl->base; ++ + page_pcmd_off = sgx_encl_get_backing_page_pcmd_offset(encl, page_index); + + ret = sgx_encl_get_backing(encl, page_index, &b); +@@ -99,7 +191,7 @@ static int __sgx_encl_eldu(struct sgx_encl_page *encl_page, + + sgx_encl_truncate_backing_page(encl, page_index); + +- if (pcmd_page_empty) ++ if (pcmd_page_empty && !reclaimer_writing_to_pcmd(encl, pcmd_first_page)) + sgx_encl_truncate_backing_page(encl, PFN_DOWN(page_pcmd_off)); + + return ret; +-- +2.36.1 + diff --git a/0005-x86-sgx-Ensure-no-data-in-PCMD-page-after-truncate.patch b/0005-x86-sgx-Ensure-no-data-in-PCMD-page-after-truncate.patch new file mode 100644 index 000000000000..64d68a2b75ba --- /dev/null +++ b/0005-x86-sgx-Ensure-no-data-in-PCMD-page-after-truncate.patch @@ -0,0 +1,59 @@ +From 5e9c8f738e0c7feee2121685e15e653cdbb998e9 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Thu, 12 May 2022 14:51:01 -0700 +Subject: [PATCH 05/36] x86/sgx: Ensure no data in PCMD page after truncate + +A PCMD (Paging Crypto MetaData) page contains the PCMD +structures of enclave pages that have been encrypted and +moved to the shmem backing store. When all enclave pages +sharing a PCMD page are loaded in the enclave, there is no +need for the PCMD page and it can be truncated from the +backing store. + +A few issues appeared around the truncation of PCMD pages. The +known issues have been addressed but the PCMD handling code could +be made more robust by loudly complaining if any new issue appears +in this area. + +Add a check that will complain with a warning if the PCMD page is not +actually empty after it has been truncated. There should never be data +in the PCMD page at this point since it is was just checked to be empty +and truncated with enclave mutex held and is updated with the +enclave mutex held. + +Suggested-by: Dave Hansen <dave.hansen@linux.intel.com> +Tested-by: Haitao Huang <haitao.huang@intel.com> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + arch/x86/kernel/cpu/sgx/encl.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c +index 243f3bd78145..3c24e6124d95 100644 +--- a/arch/x86/kernel/cpu/sgx/encl.c ++++ b/arch/x86/kernel/cpu/sgx/encl.c +@@ -187,12 +187,20 @@ static int __sgx_encl_eldu(struct sgx_encl_page *encl_page, + kunmap_atomic(pcmd_page); + kunmap_atomic((void *)(unsigned long)pginfo.contents); + ++ get_page(b.pcmd); + sgx_encl_put_backing(&b); + + sgx_encl_truncate_backing_page(encl, page_index); + +- if (pcmd_page_empty && !reclaimer_writing_to_pcmd(encl, pcmd_first_page)) ++ if (pcmd_page_empty && !reclaimer_writing_to_pcmd(encl, pcmd_first_page)) { + sgx_encl_truncate_backing_page(encl, PFN_DOWN(page_pcmd_off)); ++ pcmd_page = kmap_atomic(b.pcmd); ++ if (memchr_inv(pcmd_page, 0, PAGE_SIZE)) ++ pr_warn("PCMD page not empty after truncate.\n"); ++ kunmap_atomic(pcmd_page); ++ } ++ ++ put_page(b.pcmd); + + return ret; + } +-- +2.36.1 + diff --git a/0001-x86-sgx-Add-short-descriptions-to-ENCLS-wrappers.patch b/0006-x86-sgx-Add-short-descriptions-to-ENCLS-wrappers.patch index 1e3220adb8c7..6c46a0df4fc4 100644 --- a/0001-x86-sgx-Add-short-descriptions-to-ENCLS-wrappers.patch +++ b/0006-x86-sgx-Add-short-descriptions-to-ENCLS-wrappers.patch @@ -1,7 +1,7 @@ -From 51105664980e12f8f34730c20725ae3ca2229c3e Mon Sep 17 00:00:00 2001 +From 911e551ff47ec3e18b776b9d86b4c2e64cd675be Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:01 -0700 -Subject: [PATCH 01/31] x86/sgx: Add short descriptions to ENCLS wrappers +Date: Tue, 10 May 2022 11:08:37 -0700 +Subject: [PATCH 06/36] x86/sgx: Add short descriptions to ENCLS wrappers The SGX ENCLS instruction uses EAX to specify an SGX function and may require additional registers, depending on the SGX function. @@ -105,5 +105,5 @@ index fa04a73daf9c..0e22fa8f77c5 100644 void *va) { -- -2.35.2 +2.36.1 diff --git a/0002-x86-sgx-Add-wrapper-for-SGX2-EMODPR-function.patch b/0007-x86-sgx-Add-wrapper-for-SGX2-EMODPR-function.patch index 02a8bd059f9d..3fe683efeab0 100644 --- a/0002-x86-sgx-Add-wrapper-for-SGX2-EMODPR-function.patch +++ b/0007-x86-sgx-Add-wrapper-for-SGX2-EMODPR-function.patch @@ -1,7 +1,7 @@ -From 7f9ca1bdebe92d16d0e176e7dbb0425e3563a2b5 Mon Sep 17 00:00:00 2001 +From 5c8cc5465580ccb7614303a2ba49f9ec253a6ff1 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:02 -0700 -Subject: [PATCH 02/31] x86/sgx: Add wrapper for SGX2 EMODPR function +Date: Tue, 10 May 2022 11:08:38 -0700 +Subject: [PATCH 07/36] x86/sgx: Add wrapper for SGX2 EMODPR function Add a wrapper for the EMODPR ENCLS leaf function used to restrict enclave page permissions as maintained in the @@ -79,5 +79,5 @@ index 0e22fa8f77c5..2b091912f038 100644 + #endif /* _X86_ENCLS_H */ -- -2.35.2 +2.36.1 diff --git a/0003-x86-sgx-Add-wrapper-for-SGX2-EMODT-function.patch b/0008-x86-sgx-Add-wrapper-for-SGX2-EMODT-function.patch index 0bd84703ff56..b9e5783f860f 100644 --- a/0003-x86-sgx-Add-wrapper-for-SGX2-EMODT-function.patch +++ b/0008-x86-sgx-Add-wrapper-for-SGX2-EMODT-function.patch @@ -1,7 +1,7 @@ -From 65f997c50816e3314722b49a4f55ea51eb865d1d Mon Sep 17 00:00:00 2001 +From 86327191b4402a01042948f410f810837105b97d Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:03 -0700 -Subject: [PATCH 03/31] x86/sgx: Add wrapper for SGX2 EMODT function +Date: Tue, 10 May 2022 11:08:39 -0700 +Subject: [PATCH 08/36] x86/sgx: Add wrapper for SGX2 EMODT function Add a wrapper for the EMODT ENCLS leaf function used to change the type of an enclave page as maintained in the @@ -46,5 +46,5 @@ index 2b091912f038..7a1ecf704ec1 100644 + #endif /* _X86_ENCLS_H */ -- -2.35.2 +2.36.1 diff --git a/0004-x86-sgx-Add-wrapper-for-SGX2-EAUG-function.patch b/0009-x86-sgx-Add-wrapper-for-SGX2-EAUG-function.patch index 09d7a58080e8..6c025947f265 100644 --- a/0004-x86-sgx-Add-wrapper-for-SGX2-EAUG-function.patch +++ b/0009-x86-sgx-Add-wrapper-for-SGX2-EAUG-function.patch @@ -1,7 +1,7 @@ -From c2eaa596a76f7f407e8e590d8b78839a8ac034a8 Mon Sep 17 00:00:00 2001 +From 904af2dd1bb04758ad2327793ee10f24a944f7b6 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:04 -0700 -Subject: [PATCH 04/31] x86/sgx: Add wrapper for SGX2 EAUG function +Date: Tue, 10 May 2022 11:08:40 -0700 +Subject: [PATCH 09/36] x86/sgx: Add wrapper for SGX2 EAUG function Add a wrapper for the EAUG ENCLS leaf function used to add a page to an initialized enclave. @@ -38,5 +38,5 @@ index 7a1ecf704ec1..99004b02e2ed 100644 + #endif /* _X86_ENCLS_H */ -- -2.35.2 +2.36.1 diff --git a/0005-x86-sgx-Support-loading-enclave-page-without-VMA-per.patch b/0010-x86-sgx-Support-loading-enclave-page-without-VMA-per.patch index aebc50bcdeb6..3b096adb8f8b 100644 --- a/0005-x86-sgx-Support-loading-enclave-page-without-VMA-per.patch +++ b/0010-x86-sgx-Support-loading-enclave-page-without-VMA-per.patch @@ -1,7 +1,7 @@ -From 836478d4e8f9a6b1ce067e597f29e59eb1422423 Mon Sep 17 00:00:00 2001 +From d88ad0efa7127c861cd5aaf241349b5f9a0fbd53 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:05 -0700 -Subject: [PATCH 05/31] x86/sgx: Support loading enclave page without VMA +Date: Tue, 10 May 2022 11:08:41 -0700 +Subject: [PATCH 10/36] x86/sgx: Support loading enclave page without VMA permissions check sgx_encl_load_page() is used to find and load an enclave page into @@ -30,10 +30,10 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c -index 001808e3901c..b45fcecea4bd 100644 +index 3c24e6124d95..7ad8b475306a 100644 --- a/arch/x86/kernel/cpu/sgx/encl.c +++ b/arch/x86/kernel/cpu/sgx/encl.c -@@ -90,25 +90,10 @@ static struct sgx_epc_page *sgx_encl_eldu(struct sgx_encl_page *encl_page, +@@ -232,25 +232,10 @@ static struct sgx_epc_page *sgx_encl_eldu(struct sgx_encl_page *encl_page, return epc_page; } @@ -61,7 +61,7 @@ index 001808e3901c..b45fcecea4bd 100644 /* Entry successfully located. */ if (entry->epc_page) { -@@ -134,6 +119,40 @@ static struct sgx_encl_page *sgx_encl_load_page(struct sgx_encl *encl, +@@ -276,6 +261,40 @@ static struct sgx_encl_page *sgx_encl_load_page(struct sgx_encl *encl, return entry; } @@ -102,7 +102,7 @@ index 001808e3901c..b45fcecea4bd 100644 static vm_fault_t sgx_vma_fault(struct vm_fault *vmf) { unsigned long addr = (unsigned long)vmf->address; -@@ -155,7 +174,7 @@ static vm_fault_t sgx_vma_fault(struct vm_fault *vmf) +@@ -297,7 +316,7 @@ static vm_fault_t sgx_vma_fault(struct vm_fault *vmf) mutex_lock(&encl->lock); @@ -111,7 +111,7 @@ index 001808e3901c..b45fcecea4bd 100644 if (IS_ERR(entry)) { mutex_unlock(&encl->lock); -@@ -303,7 +322,7 @@ static struct sgx_encl_page *sgx_encl_reserve_page(struct sgx_encl *encl, +@@ -445,7 +464,7 @@ static struct sgx_encl_page *sgx_encl_reserve_page(struct sgx_encl *encl, for ( ; ; ) { mutex_lock(&encl->lock); @@ -121,7 +121,7 @@ index 001808e3901c..b45fcecea4bd 100644 break; diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h -index fec43ca65065..6b34efba1602 100644 +index d44e7372151f..522a17e4fd2d 100644 --- a/arch/x86/kernel/cpu/sgx/encl.h +++ b/arch/x86/kernel/cpu/sgx/encl.h @@ -116,5 +116,7 @@ unsigned int sgx_alloc_va_slot(struct sgx_va_page *va_page); @@ -133,5 +133,5 @@ index fec43ca65065..6b34efba1602 100644 #endif /* _X86_ENCL_H */ -- -2.35.2 +2.36.1 diff --git a/0006-x86-sgx-Export-sgx_encl_ewb_cpumask.patch b/0011-x86-sgx-Export-sgx_encl_ewb_cpumask.patch index fa2f045f83ac..2d636c371e62 100644 --- a/0006-x86-sgx-Export-sgx_encl_ewb_cpumask.patch +++ b/0011-x86-sgx-Export-sgx_encl_ewb_cpumask.patch @@ -1,7 +1,7 @@ -From 100959e3e9bf237de44f769e204aee46e61b5765 Mon Sep 17 00:00:00 2001 +From 3d04d12e9ee7efadb490cba7ba12e8d4b833b9af Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:06 -0700 -Subject: [PATCH 06/31] x86/sgx: Export sgx_encl_ewb_cpumask() +Date: Tue, 10 May 2022 11:08:42 -0700 +Subject: [PATCH 11/36] x86/sgx: Export sgx_encl_ewb_cpumask() Using sgx_encl_ewb_cpumask() to learn which CPUs might have executed an enclave is useful to ensure that TLBs are cleared when changes are @@ -31,10 +31,10 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 3 files changed, 68 insertions(+), 29 deletions(-) diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c -index b45fcecea4bd..2845ec4faf24 100644 +index 7ad8b475306a..6953d331f8d5 100644 --- a/arch/x86/kernel/cpu/sgx/encl.c +++ b/arch/x86/kernel/cpu/sgx/encl.c -@@ -570,6 +570,73 @@ int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm) +@@ -714,6 +714,73 @@ int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm) return 0; } @@ -109,7 +109,7 @@ index b45fcecea4bd..2845ec4faf24 100644 pgoff_t index) { diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h -index 6b34efba1602..d2acb4debde5 100644 +index 522a17e4fd2d..c6afa58ea3e6 100644 --- a/arch/x86/kernel/cpu/sgx/encl.h +++ b/arch/x86/kernel/cpu/sgx/encl.h @@ -105,6 +105,7 @@ int sgx_encl_may_map(struct sgx_encl *encl, unsigned long start, @@ -119,12 +119,12 @@ index 6b34efba1602..d2acb4debde5 100644 +const cpumask_t *sgx_encl_ewb_cpumask(struct sgx_encl *encl); int sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index, struct sgx_backing *backing); - void sgx_encl_put_backing(struct sgx_backing *backing, bool do_write); + void sgx_encl_put_backing(struct sgx_backing *backing); diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c -index 4b41efc9e367..d481e8b0e7bc 100644 +index ab4ec54bbdd9..2a926278dd29 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c -@@ -203,35 +203,6 @@ static void sgx_ipi_cb(void *info) +@@ -205,35 +205,6 @@ static void sgx_ipi_cb(void *info) { } @@ -161,5 +161,5 @@ index 4b41efc9e367..d481e8b0e7bc 100644 * Swap page to the regular memory transformed to the blocked state by using * EBLOCK, which means that it can no longer be referenced (no new TLB entries). -- -2.35.2 +2.36.1 diff --git a/0007-x86-sgx-Rename-sgx_encl_ewb_cpumask-as-sgx_encl_cpum.patch b/0012-x86-sgx-Rename-sgx_encl_ewb_cpumask-as-sgx_encl_cpum.patch index 7575ed87b0ed..1e5e7875039f 100644 --- a/0007-x86-sgx-Rename-sgx_encl_ewb_cpumask-as-sgx_encl_cpum.patch +++ b/0012-x86-sgx-Rename-sgx_encl_ewb_cpumask-as-sgx_encl_cpum.patch @@ -1,7 +1,7 @@ -From b87d36265a3ceb1574d68772f29c61a24433070e Mon Sep 17 00:00:00 2001 +From c8182e673630ff65fad540a4773ac7d2888ac7e5 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:07 -0700 -Subject: [PATCH 07/31] x86/sgx: Rename sgx_encl_ewb_cpumask() as +Date: Tue, 10 May 2022 11:08:43 -0700 +Subject: [PATCH 12/36] x86/sgx: Rename sgx_encl_ewb_cpumask() as sgx_encl_cpumask() sgx_encl_ewb_cpumask() is no longer unique to the reclaimer where it @@ -27,10 +27,10 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c -index 2845ec4faf24..f241596ba411 100644 +index 6953d331f8d5..7539cef6e66b 100644 --- a/arch/x86/kernel/cpu/sgx/encl.c +++ b/arch/x86/kernel/cpu/sgx/encl.c -@@ -571,7 +571,7 @@ int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm) +@@ -715,7 +715,7 @@ int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm) } /** @@ -39,7 +39,7 @@ index 2845ec4faf24..f241596ba411 100644 * @encl: the enclave * * Some SGX functions require that no cached linear-to-physical address -@@ -596,7 +596,7 @@ int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm) +@@ -740,7 +740,7 @@ int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm) * The following flow is used to support SGX functions that require that * no cached linear-to-physical address mappings are present: * 1) Execute ENCLS[ETRACK] to initiate hardware tracking. @@ -48,7 +48,7 @@ index 2845ec4faf24..f241596ba411 100644 * accessing the enclave. * 3) Send IPI to identified CPUs, kicking them out of the enclave and * thus flushing all locally cached linear-to-physical address mappings. -@@ -613,7 +613,7 @@ int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm) +@@ -757,7 +757,7 @@ int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm) * * Return: cpumask of CPUs that might be accessing @encl */ @@ -58,7 +58,7 @@ index 2845ec4faf24..f241596ba411 100644 cpumask_t *cpumask = &encl->cpumask; struct sgx_encl_mm *encl_mm; diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h -index d2acb4debde5..e59c2cbf71e2 100644 +index c6afa58ea3e6..ef8cf106904b 100644 --- a/arch/x86/kernel/cpu/sgx/encl.h +++ b/arch/x86/kernel/cpu/sgx/encl.h @@ -105,7 +105,7 @@ int sgx_encl_may_map(struct sgx_encl *encl, unsigned long start, @@ -69,12 +69,12 @@ index d2acb4debde5..e59c2cbf71e2 100644 +const cpumask_t *sgx_encl_cpumask(struct sgx_encl *encl); int sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index, struct sgx_backing *backing); - void sgx_encl_put_backing(struct sgx_backing *backing, bool do_write); + void sgx_encl_put_backing(struct sgx_backing *backing); diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c -index d481e8b0e7bc..60b166bff7b4 100644 +index 2a926278dd29..7b53a69d501f 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c -@@ -249,7 +249,7 @@ static void sgx_encl_ewb(struct sgx_epc_page *epc_page, +@@ -251,7 +251,7 @@ static void sgx_encl_ewb(struct sgx_epc_page *epc_page, * miss cpus that entered the enclave between * generating the mask and incrementing epoch. */ @@ -84,5 +84,5 @@ index d481e8b0e7bc..60b166bff7b4 100644 ret = __sgx_encl_ewb(epc_page, va_slot, backing); } -- -2.35.2 +2.36.1 diff --git a/0008-x86-sgx-Move-PTE-zap-code-to-new-sgx_zap_enclave_pte.patch b/0013-x86-sgx-Move-PTE-zap-code-to-new-sgx_zap_enclave_pte.patch index d9f052f0eed2..d3884fb03a10 100644 --- a/0008-x86-sgx-Move-PTE-zap-code-to-new-sgx_zap_enclave_pte.patch +++ b/0013-x86-sgx-Move-PTE-zap-code-to-new-sgx_zap_enclave_pte.patch @@ -1,7 +1,7 @@ -From 1e61402b92958e49b5cbb4e47fb8238273e279f4 Mon Sep 17 00:00:00 2001 +From 3068bc10f54b083eb4d7b85e1420fa1d57ff5b1d Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:08 -0700 -Subject: [PATCH 08/31] x86/sgx: Move PTE zap code to new +Date: Tue, 10 May 2022 11:08:44 -0700 +Subject: [PATCH 13/36] x86/sgx: Move PTE zap code to new sgx_zap_enclave_ptes() The SGX reclaimer removes page table entries pointing to pages that are @@ -32,10 +32,10 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c -index f241596ba411..a872bd7e953a 100644 +index 7539cef6e66b..c6cac43b40d6 100644 --- a/arch/x86/kernel/cpu/sgx/encl.c +++ b/arch/x86/kernel/cpu/sgx/encl.c -@@ -562,7 +562,7 @@ int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm) +@@ -706,7 +706,7 @@ int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm) spin_lock(&encl->mm_lock); list_add_rcu(&encl_mm->list, &encl->mm_list); @@ -44,7 +44,7 @@ index f241596ba411..a872bd7e953a 100644 smp_wmb(); encl->mm_list_version++; spin_unlock(&encl->mm_lock); -@@ -751,6 +751,49 @@ int sgx_encl_test_and_clear_young(struct mm_struct *mm, +@@ -887,6 +887,49 @@ int sgx_encl_test_and_clear_young(struct mm_struct *mm, return ret; } @@ -95,11 +95,11 @@ index f241596ba411..a872bd7e953a 100644 * sgx_alloc_va_page() - Allocate a Version Array (VA) page * diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h -index e59c2cbf71e2..1b15d22f6757 100644 +index ef8cf106904b..f72a674e2605 100644 --- a/arch/x86/kernel/cpu/sgx/encl.h +++ b/arch/x86/kernel/cpu/sgx/encl.h @@ -111,7 +111,7 @@ int sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index, - void sgx_encl_put_backing(struct sgx_backing *backing, bool do_write); + void sgx_encl_put_backing(struct sgx_backing *backing); int sgx_encl_test_and_clear_young(struct mm_struct *mm, struct sgx_encl_page *page); - @@ -108,7 +108,7 @@ index e59c2cbf71e2..1b15d22f6757 100644 unsigned int sgx_alloc_va_slot(struct sgx_va_page *va_page); void sgx_free_va_slot(struct sgx_va_page *va_page, unsigned int offset); diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c -index 60b166bff7b4..06492dcffcf1 100644 +index 7b53a69d501f..9df2221af498 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -137,36 +137,9 @@ static void sgx_reclaimer_block(struct sgx_epc_page *epc_page) @@ -151,5 +151,5 @@ index 60b166bff7b4..06492dcffcf1 100644 mutex_lock(&encl->lock); -- -2.35.2 +2.36.1 diff --git a/0009-x86-sgx-Make-sgx_ipi_cb-available-internally.patch b/0014-x86-sgx-Make-sgx_ipi_cb-available-internally.patch index b52276685cbc..914073b8ea0a 100644 --- a/0009-x86-sgx-Make-sgx_ipi_cb-available-internally.patch +++ b/0014-x86-sgx-Make-sgx_ipi_cb-available-internally.patch @@ -1,7 +1,7 @@ -From 8f56418b1b9d2f70f0b81f6f7f04c2f7ba7e1746 Mon Sep 17 00:00:00 2001 +From f3aa084da6b464114361270c037e177de0dbfa5f Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:09 -0700 -Subject: [PATCH 09/31] x86/sgx: Make sgx_ipi_cb() available internally +Date: Tue, 10 May 2022 11:08:45 -0700 +Subject: [PATCH 14/36] x86/sgx: Make sgx_ipi_cb() available internally The ETRACK function followed by an IPI to all CPUs within an enclave is a common pattern with more frequent use in support of SGX2. @@ -17,10 +17,10 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c -index 06492dcffcf1..1a3014aec490 100644 +index 9df2221af498..180ad840b226 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c -@@ -172,7 +172,7 @@ static int __sgx_encl_ewb(struct sgx_epc_page *epc_page, void *va_slot, +@@ -174,7 +174,7 @@ static int __sgx_encl_ewb(struct sgx_epc_page *epc_page, void *va_slot, return ret; } @@ -43,5 +43,5 @@ index 0f17def9fe6f..b30cee4de903 100644 int __init sgx_vepc_init(void); #else -- -2.35.2 +2.36.1 diff --git a/0010-x86-sgx-Create-utility-to-validate-user-provided-off.patch b/0015-x86-sgx-Create-utility-to-validate-user-provided-off.patch index 341d82ac56f6..8610e8b5d785 100644 --- a/0010-x86-sgx-Create-utility-to-validate-user-provided-off.patch +++ b/0015-x86-sgx-Create-utility-to-validate-user-provided-off.patch @@ -1,7 +1,7 @@ -From 87e7f3c34d6cdd9e2e4d5ff630e85c954c087122 Mon Sep 17 00:00:00 2001 +From 7e214d2e919619ab3dbc4547f0f03986009245f3 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:10 -0700 -Subject: [PATCH 10/31] x86/sgx: Create utility to validate user provided +Date: Tue, 10 May 2022 11:08:46 -0700 +Subject: [PATCH 15/36] x86/sgx: Create utility to validate user provided offset and length User provided offset and length is validated when parsing the parameters @@ -64,5 +64,5 @@ index 83df20e3e633..a66795e0b685 100644 if (copy_from_user(&secinfo, (void __user *)add_arg.secinfo, -- -2.35.2 +2.36.1 diff --git a/0011-x86-sgx-Keep-record-of-SGX-page-type.patch b/0016-x86-sgx-Keep-record-of-SGX-page-type.patch index 5ad1c20ab63d..1b68f9062ccb 100644 --- a/0011-x86-sgx-Keep-record-of-SGX-page-type.patch +++ b/0016-x86-sgx-Keep-record-of-SGX-page-type.patch @@ -1,7 +1,7 @@ -From 588655546cf6bda0ae880233e40240b6a0a6cbbe Mon Sep 17 00:00:00 2001 +From f00cceb541c0ed451da982dd4bcf2df721c23902 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:11 -0700 -Subject: [PATCH 11/31] x86/sgx: Keep record of SGX page type +Date: Tue, 10 May 2022 11:08:47 -0700 +Subject: [PATCH 16/36] x86/sgx: Keep record of SGX page type SGX2 functions are not allowed on all page types. For example, ENCLS[EMODPR] is only allowed on regular SGX enclave pages and @@ -27,7 +27,6 @@ while only using three bits. Transition to a bitfield for the two members to support the additional information without increasing the space consumed by the struct. -Acked-by: Jarkko Sakkinen <jarkko@kernel.org> Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> --- @@ -51,7 +50,7 @@ index d67810b50a81..eae20fa52b93 100644 enum sgx_page_type { SGX_PAGE_TYPE_SECS, diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h -index 1b15d22f6757..07abfc70c8e3 100644 +index f72a674e2605..799d4cdb12d5 100644 --- a/arch/x86/kernel/cpu/sgx/encl.h +++ b/arch/x86/kernel/cpu/sgx/encl.h @@ -27,7 +27,8 @@ @@ -85,5 +84,5 @@ index a66795e0b685..21078c6643f7 100644 if (flags & SGX_PAGE_MEASURE) { -- -2.35.2 +2.36.1 diff --git a/0012-x86-sgx-Export-sgx_encl_-grow-shrink.patch b/0017-x86-sgx-Export-sgx_encl_-grow-shrink.patch index a096dc6633ba..a3088a91009e 100644 --- a/0012-x86-sgx-Export-sgx_encl_-grow-shrink.patch +++ b/0017-x86-sgx-Export-sgx_encl_-grow-shrink.patch @@ -1,7 +1,7 @@ -From 224652fefdf04993c3e61f8a5beefe395489c7d0 Mon Sep 17 00:00:00 2001 +From f2b77aae84955b467adb8e9b570c04d84cebb863 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:12 -0700 -Subject: [PATCH 12/31] x86/sgx: Export sgx_encl_{grow,shrink}() +Date: Tue, 10 May 2022 11:08:48 -0700 +Subject: [PATCH 17/36] x86/sgx: Export sgx_encl_{grow,shrink}() In order to use sgx_encl_{grow,shrink}() in the page augmentation code located in encl.c, export these functions. @@ -15,7 +15,7 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h -index 07abfc70c8e3..9d673d9531f0 100644 +index 799d4cdb12d5..b6b53c0346ad 100644 --- a/arch/x86/kernel/cpu/sgx/encl.h +++ b/arch/x86/kernel/cpu/sgx/encl.h @@ -120,5 +120,7 @@ bool sgx_va_page_full(struct sgx_va_page *va_page); @@ -49,5 +49,5 @@ index 21078c6643f7..2df27dd8b30d 100644 encl->page_cnt--; -- -2.35.2 +2.36.1 diff --git a/0013-x86-sgx-Export-sgx_encl_page_alloc.patch b/0018-x86-sgx-Export-sgx_encl_page_alloc.patch index 50c010eac95b..0098ef6799b7 100644 --- a/0013-x86-sgx-Export-sgx_encl_page_alloc.patch +++ b/0018-x86-sgx-Export-sgx_encl_page_alloc.patch @@ -1,7 +1,7 @@ -From 25c6413856fe1d73bef5dfb3c8a6bddc728fe37a Mon Sep 17 00:00:00 2001 +From dd73a72bdd8afde9390e4cb281a858ba1482413c Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen <jarkko@kernel.org> -Date: Wed, 13 Apr 2022 14:10:13 -0700 -Subject: [PATCH 13/31] x86/sgx: Export sgx_encl_page_alloc() +Date: Tue, 10 May 2022 11:08:49 -0700 +Subject: [PATCH 18/36] x86/sgx: Export sgx_encl_page_alloc() Move sgx_encl_page_alloc() to encl.c and export it so that it can be used in the implementation for support of adding pages to initialized @@ -16,10 +16,10 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c -index a872bd7e953a..38e42c2d3592 100644 +index c6cac43b40d6..5e6a64d8e3d6 100644 --- a/arch/x86/kernel/cpu/sgx/encl.c +++ b/arch/x86/kernel/cpu/sgx/encl.c -@@ -751,6 +751,38 @@ int sgx_encl_test_and_clear_young(struct mm_struct *mm, +@@ -887,6 +887,38 @@ int sgx_encl_test_and_clear_young(struct mm_struct *mm, return ret; } @@ -59,11 +59,11 @@ index a872bd7e953a..38e42c2d3592 100644 * sgx_zap_enclave_ptes() - remove PTEs mapping the address from enclave * @encl: the enclave diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h -index 9d673d9531f0..253ebdd1c5be 100644 +index b6b53c0346ad..2cb58ab868e5 100644 --- a/arch/x86/kernel/cpu/sgx/encl.h +++ b/arch/x86/kernel/cpu/sgx/encl.h @@ -112,6 +112,9 @@ int sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index, - void sgx_encl_put_backing(struct sgx_backing *backing, bool do_write); + void sgx_encl_put_backing(struct sgx_backing *backing); int sgx_encl_test_and_clear_young(struct mm_struct *mm, struct sgx_encl_page *page); +struct sgx_encl_page *sgx_encl_page_alloc(struct sgx_encl *encl, @@ -116,5 +116,5 @@ index 2df27dd8b30d..bb8cdb2ad0d1 100644 { u64 perm = secinfo->flags & SGX_SECINFO_PERMISSION_MASK; -- -2.35.2 +2.36.1 diff --git a/0014-x86-sgx-Support-VA-page-allocation-without-reclaimin.patch b/0019-x86-sgx-Support-VA-page-allocation-without-reclaimin.patch index bad182536397..7fe43ad0f976 100644 --- a/0014-x86-sgx-Support-VA-page-allocation-without-reclaimin.patch +++ b/0019-x86-sgx-Support-VA-page-allocation-without-reclaimin.patch @@ -1,7 +1,7 @@ -From dc8e57ec148e5f440afaedea7705742bf2f00236 Mon Sep 17 00:00:00 2001 +From fd4616da8dc62cdf1976b27742a567efd5aac146 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:14 -0700 -Subject: [PATCH 14/31] x86/sgx: Support VA page allocation without reclaiming +Date: Tue, 10 May 2022 11:08:50 -0700 +Subject: [PATCH 19/36] x86/sgx: Support VA page allocation without reclaiming struct sgx_encl should be protected with the mutex sgx_encl->lock. One exception is sgx_encl->page_cnt that @@ -34,7 +34,7 @@ initialization. No functional change. Reported-by: Haitao Huang <haitao.huang@intel.com> -Tested-by: Haitao Huang <haitao.huang@intel.com> +Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> --- arch/x86/kernel/cpu/sgx/encl.c | 6 ++++-- @@ -43,10 +43,10 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c -index 38e42c2d3592..8729b254b0cc 100644 +index 5e6a64d8e3d6..ea81e597dd18 100644 --- a/arch/x86/kernel/cpu/sgx/encl.c +++ b/arch/x86/kernel/cpu/sgx/encl.c -@@ -828,6 +828,8 @@ void sgx_zap_enclave_ptes(struct sgx_encl *encl, unsigned long addr) +@@ -964,6 +964,8 @@ void sgx_zap_enclave_ptes(struct sgx_encl *encl, unsigned long addr) /** * sgx_alloc_va_page() - Allocate a Version Array (VA) page @@ -55,7 +55,7 @@ index 38e42c2d3592..8729b254b0cc 100644 * * Allocate a free EPC page and convert it to a Version Array (VA) page. * -@@ -835,12 +837,12 @@ void sgx_zap_enclave_ptes(struct sgx_encl *encl, unsigned long addr) +@@ -971,12 +973,12 @@ void sgx_zap_enclave_ptes(struct sgx_encl *encl, unsigned long addr) * a VA page, * -errno otherwise */ @@ -71,7 +71,7 @@ index 38e42c2d3592..8729b254b0cc 100644 return ERR_CAST(epc_page); diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h -index 253ebdd1c5be..66adb8faec45 100644 +index 2cb58ab868e5..3d0e0ba3edf5 100644 --- a/arch/x86/kernel/cpu/sgx/encl.h +++ b/arch/x86/kernel/cpu/sgx/encl.h @@ -116,14 +116,14 @@ struct sgx_encl_page *sgx_encl_page_alloc(struct sgx_encl *encl, @@ -132,5 +132,5 @@ index bb8cdb2ad0d1..5d41aa204761 100644 ret = PTR_ERR(va_page); goto err_out_free; -- -2.35.2 +2.36.1 diff --git a/0015-x86-sgx-Support-restricting-of-enclave-page-permissi.patch b/0020-x86-sgx-Support-restricting-of-enclave-page-permissi.patch index 1efe9f470ce2..943aed066ea8 100644 --- a/0015-x86-sgx-Support-restricting-of-enclave-page-permissi.patch +++ b/0020-x86-sgx-Support-restricting-of-enclave-page-permissi.patch @@ -1,7 +1,7 @@ -From 8ff9ec59a55ea1ccc5f17f8053e747a963efc327 Mon Sep 17 00:00:00 2001 +From f77e5b90440a4709d58907d7a467bedbfe8ed4d8 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:15 -0700 -Subject: [PATCH 15/31] x86/sgx: Support restricting of enclave page +Date: Tue, 10 May 2022 11:08:51 -0700 +Subject: [PATCH 20/36] x86/sgx: Support restricting of enclave page permissions In the initial (SGX1) version of SGX, pages in an enclave need to be @@ -43,6 +43,10 @@ the EPCM permissions from within the enclave without the kernel knowing. An attempt to relax permissions using this call will be ignored by the hardware. +Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> +Tested-by: Jarkko Sakkinen <jarkko@kernel.org> +Tested-by: Haitao Huang <haitao.huang@intel.com> +Tested-by: Vijay Dhanraj <vijay.dhanraj@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> --- arch/x86/include/uapi/asm/sgx.h | 21 ++++ @@ -89,7 +93,7 @@ index f4b81587e90b..82648c006470 100644 /** diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c -index 5d41aa204761..395b4e58a295 100644 +index 5d41aa204761..720188d86ed4 100644 --- a/arch/x86/kernel/cpu/sgx/ioctl.c +++ b/arch/x86/kernel/cpu/sgx/ioctl.c @@ -660,6 +660,218 @@ static long sgx_ioc_enclave_provision(struct sgx_encl *encl, void __user *arg) @@ -290,11 +294,11 @@ index 5d41aa204761..395b4e58a295 100644 + return -EINVAL; + + /* -+ * Read access is required for the enclave to be able to use the page. -+ * SGX instructions like ENCLU[EMODPE] and ENCLU[EACCEPT] require -+ * read access. ++ * Fail early if invalid permissions requested to prevent ENCLS[EMODPR] ++ * from faulting later when the CPU does the same check. + */ -+ if (!(params.permissions & SGX_SECINFO_R)) ++ if ((params.permissions & SGX_SECINFO_W) && ++ !(params.permissions & SGX_SECINFO_R)) + return -EINVAL; + + if (params.result || params.count) @@ -323,5 +327,5 @@ index 5d41aa204761..395b4e58a295 100644 ret = -ENOIOCTLCMD; break; -- -2.35.2 +2.36.1 diff --git a/0016-x86-sgx-Support-adding-of-pages-to-an-initialized-en.patch b/0021-x86-sgx-Support-adding-of-pages-to-an-initialized-en.patch index 38ad636ed843..d8a57679dd30 100644 --- a/0016-x86-sgx-Support-adding-of-pages-to-an-initialized-en.patch +++ b/0021-x86-sgx-Support-adding-of-pages-to-an-initialized-en.patch @@ -1,7 +1,7 @@ -From 467c051f0ccb4a65846d9c174fbb4587e028d008 Mon Sep 17 00:00:00 2001 +From a819692d9ebd58f1791a63fdaf5d412ac41a0147 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:16 -0700 -Subject: [PATCH 16/31] x86/sgx: Support adding of pages to an initialized +Date: Tue, 10 May 2022 11:08:52 -0700 +Subject: [PATCH 21/36] x86/sgx: Support adding of pages to an initialized enclave With SGX1 an enclave needs to be created with its maximum memory demands @@ -42,16 +42,18 @@ ENCLU[EACCEPT]. Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> Tested-by: Jarkko Sakkinen <jarkko@kernel.org> +Tested-by: Haitao Huang <haitao.huang@intel.com> +Tested-by: Vijay Dhanraj <vijay.dhanraj@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> --- arch/x86/kernel/cpu/sgx/encl.c | 117 +++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c -index 8729b254b0cc..91d648f68080 100644 +index ea81e597dd18..e5b61a59199f 100644 --- a/arch/x86/kernel/cpu/sgx/encl.c +++ b/arch/x86/kernel/cpu/sgx/encl.c -@@ -153,6 +153,112 @@ struct sgx_encl_page *sgx_encl_load_page(struct sgx_encl *encl, +@@ -295,6 +295,112 @@ struct sgx_encl_page *sgx_encl_load_page(struct sgx_encl *encl, return __sgx_encl_load_page(encl, entry); } @@ -71,13 +73,13 @@ index 8729b254b0cc..91d648f68080 100644 +static vm_fault_t sgx_encl_eaug_page(struct vm_area_struct *vma, + struct sgx_encl *encl, unsigned long addr) +{ ++ vm_fault_t vmret = VM_FAULT_SIGBUS; + struct sgx_pageinfo pginfo = {0}; + struct sgx_encl_page *encl_page; + struct sgx_epc_page *epc_page; + struct sgx_va_page *va_page; + unsigned long phys_addr; + u64 secinfo_flags; -+ vm_fault_t vmret; + int ret; + + if (!test_bit(SGX_ENCL_INITIALIZED, &encl->flags)) @@ -94,20 +96,19 @@ index 8729b254b0cc..91d648f68080 100644 + if (IS_ERR(encl_page)) + return VM_FAULT_OOM; + -+ epc_page = sgx_alloc_epc_page(encl_page, true); -+ if (IS_ERR(epc_page)) { -+ kfree(encl_page); -+ return VM_FAULT_SIGBUS; -+ } -+ + mutex_lock(&encl->lock); + -+ va_page = sgx_encl_grow(encl, false); -+ if (IS_ERR(va_page)) { -+ ret = PTR_ERR(va_page); ++ epc_page = sgx_alloc_epc_page(encl_page, false); ++ if (IS_ERR(epc_page)) { ++ if (PTR_ERR(epc_page) == -EBUSY) ++ vmret = VM_FAULT_NOPAGE; + goto err_out_unlock; + } + ++ va_page = sgx_encl_grow(encl, false); ++ if (IS_ERR(va_page)) ++ goto err_out_epc; ++ + if (va_page) + list_add(&va_page->list, &encl->va_pages); + @@ -153,18 +154,19 @@ index 8729b254b0cc..91d648f68080 100644 + +err_out_shrink: + sgx_encl_shrink(encl, va_page); ++err_out_epc: ++ sgx_encl_free_epc_page(epc_page); +err_out_unlock: + mutex_unlock(&encl->lock); -+ sgx_encl_free_epc_page(epc_page); + kfree(encl_page); + -+ return VM_FAULT_SIGBUS; ++ return vmret; +} + static vm_fault_t sgx_vma_fault(struct vm_fault *vmf) { unsigned long addr = (unsigned long)vmf->address; -@@ -172,6 +278,17 @@ static vm_fault_t sgx_vma_fault(struct vm_fault *vmf) +@@ -314,6 +420,17 @@ static vm_fault_t sgx_vma_fault(struct vm_fault *vmf) if (unlikely(!encl)) return VM_FAULT_SIGBUS; @@ -183,5 +185,5 @@ index 8729b254b0cc..91d648f68080 100644 entry = sgx_encl_load_page_in_vma(encl, addr, vma->vm_flags); -- -2.35.2 +2.36.1 diff --git a/0017-x86-sgx-Tighten-accessible-memory-range-after-enclav.patch b/0022-x86-sgx-Tighten-accessible-memory-range-after-enclav.patch index 66ea43b7d590..c7de7fe6289f 100644 --- a/0017-x86-sgx-Tighten-accessible-memory-range-after-enclav.patch +++ b/0022-x86-sgx-Tighten-accessible-memory-range-after-enclav.patch @@ -1,7 +1,7 @@ -From e190e78cfceb89eb658cb27afe5456dc2ba24dd4 Mon Sep 17 00:00:00 2001 +From 1f35f20bc83570295e19d6fbf5fb053527975e9b Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:17 -0700 -Subject: [PATCH 17/31] x86/sgx: Tighten accessible memory range after enclave +Date: Tue, 10 May 2022 11:08:53 -0700 +Subject: [PATCH 22/36] x86/sgx: Tighten accessible memory range after enclave initialization Before an enclave is initialized the enclave's memory range is unknown. @@ -38,10 +38,10 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 1 file changed, 5 insertions(+) diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c -index 91d648f68080..ae4f444f4a43 100644 +index e5b61a59199f..295a9c946cef 100644 --- a/arch/x86/kernel/cpu/sgx/encl.c +++ b/arch/x86/kernel/cpu/sgx/encl.c -@@ -361,6 +361,11 @@ int sgx_encl_may_map(struct sgx_encl *encl, unsigned long start, +@@ -503,6 +503,11 @@ int sgx_encl_may_map(struct sgx_encl *encl, unsigned long start, XA_STATE(xas, &encl->page_array, PFN_DOWN(start)); @@ -54,5 +54,5 @@ index 91d648f68080..ae4f444f4a43 100644 * Disallow READ_IMPLIES_EXEC tasks as their VMA permissions might * conflict with the enclave page permissions. -- -2.35.2 +2.36.1 diff --git a/0018-x86-sgx-Support-modifying-SGX-page-type.patch b/0023-x86-sgx-Support-modifying-SGX-page-type.patch index d4f871756959..900563e5980d 100644 --- a/0018-x86-sgx-Support-modifying-SGX-page-type.patch +++ b/0023-x86-sgx-Support-modifying-SGX-page-type.patch @@ -1,7 +1,7 @@ -From 710eae1c72f307515eda27b51dac3b320ddd3305 Mon Sep 17 00:00:00 2001 +From f53f0d00eb02b3893c2a424b84661df18216cd24 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:18 -0700 -Subject: [PATCH 18/31] x86/sgx: Support modifying SGX page type +Date: Tue, 10 May 2022 11:08:54 -0700 +Subject: [PATCH 23/36] x86/sgx: Support modifying SGX page type Every enclave contains one or more Thread Control Structures (TCS). The TCS contains meta-data used by the hardware to save and restore thread @@ -50,14 +50,18 @@ from the kernel perspective with page table entries and internal state. The page may be moved to swap. Any access until ENCLU[EACCEPT] will encounter a page fault with SGX flag set in error code. +Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> +Tested-by: Jarkko Sakkinen <jarkko@kernel.org> +Tested-by: Haitao Huang <haitao.huang@intel.com> +Tested-by: Vijay Dhanraj <vijay.dhanraj@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> --- - arch/x86/include/uapi/asm/sgx.h | 19 +++ - arch/x86/kernel/cpu/sgx/ioctl.c | 201 ++++++++++++++++++++++++++++++++ - 2 files changed, 220 insertions(+) + arch/x86/include/uapi/asm/sgx.h | 20 ++++ + arch/x86/kernel/cpu/sgx/ioctl.c | 202 ++++++++++++++++++++++++++++++++ + 2 files changed, 222 insertions(+) diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h -index 82648c006470..de4d1af628d5 100644 +index 82648c006470..567f6166c24a 100644 --- a/arch/x86/include/uapi/asm/sgx.h +++ b/arch/x86/include/uapi/asm/sgx.h @@ -31,6 +31,8 @@ enum sgx_page_flags { @@ -65,16 +69,17 @@ index 82648c006470..de4d1af628d5 100644 #define SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS \ _IOWR(SGX_MAGIC, 0x05, struct sgx_enclave_restrict_permissions) +#define SGX_IOC_ENCLAVE_MODIFY_TYPES \ -+ _IOWR(SGX_MAGIC, 0x06, struct sgx_enclave_modify_type) ++ _IOWR(SGX_MAGIC, 0x06, struct sgx_enclave_modify_types) /** * struct sgx_enclave_create - parameter structure for the -@@ -97,6 +99,23 @@ struct sgx_enclave_restrict_permissions { +@@ -97,6 +99,24 @@ struct sgx_enclave_restrict_permissions { __u64 count; }; +/** -+ * struct sgx_enclave_modify_type - parameters for %SGX_IOC_ENCLAVE_MODIFY_TYPES ++ * struct sgx_enclave_modify_types - parameters for ioctl ++ * %SGX_IOC_ENCLAVE_MODIFY_TYPES + * @offset: starting page offset (page aligned relative to enclave base + * address defined in SECS) + * @length: length of memory (multiple of the page size) @@ -82,7 +87,7 @@ index 82648c006470..de4d1af628d5 100644 + * @result: (output) SGX result code of ENCLS[EMODT] function + * @count: (output) bytes successfully changed (multiple of page size) + */ -+struct sgx_enclave_modify_type { ++struct sgx_enclave_modify_types { + __u64 offset; + __u64 length; + __u64 page_type; @@ -94,15 +99,15 @@ index 82648c006470..de4d1af628d5 100644 /** diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c -index 395b4e58a295..8709f131ae40 100644 +index 720188d86ed4..9ccafbfc4811 100644 --- a/arch/x86/kernel/cpu/sgx/ioctl.c +++ b/arch/x86/kernel/cpu/sgx/ioctl.c -@@ -872,6 +872,204 @@ static long sgx_ioc_enclave_restrict_permissions(struct sgx_encl *encl, +@@ -872,6 +872,205 @@ static long sgx_ioc_enclave_restrict_permissions(struct sgx_encl *encl, return ret; } +/** -+ * sgx_enclave_modify_type() - Modify type of SGX enclave pages ++ * sgx_enclave_modify_types() - Modify type of SGX enclave pages + * @encl: Enclave to which the pages belong. + * @modt: Checked parameters from user about which pages need modifying + * and their new page type. @@ -111,8 +116,8 @@ index 395b4e58a295..8709f131ae40 100644 + * - 0: Success + * - -errno: Otherwise + */ -+static long sgx_enclave_modify_type(struct sgx_encl *encl, -+ struct sgx_enclave_modify_type *modt) ++static long sgx_enclave_modify_types(struct sgx_encl *encl, ++ struct sgx_enclave_modify_types *modt) +{ + unsigned long max_prot_restore; + enum sgx_page_type page_type; @@ -248,9 +253,9 @@ index 395b4e58a295..8709f131ae40 100644 +} + +/** -+ * sgx_ioc_enclave_modify_type() - handler for %SGX_IOC_ENCLAVE_MODIFY_TYPES ++ * sgx_ioc_enclave_modify_types() - handler for %SGX_IOC_ENCLAVE_MODIFY_TYPES + * @encl: an enclave pointer -+ * @arg: userspace pointer to a &struct sgx_enclave_modify_type instance ++ * @arg: userspace pointer to a &struct sgx_enclave_modify_types instance + * + * Ability to change the enclave page type supports the following use cases: + * @@ -270,9 +275,10 @@ index 395b4e58a295..8709f131ae40 100644 + * - 0: Success + * - -errno: Otherwise + */ -+static long sgx_ioc_enclave_modify_type(struct sgx_encl *encl, void __user *arg) ++static long sgx_ioc_enclave_modify_types(struct sgx_encl *encl, ++ void __user *arg) +{ -+ struct sgx_enclave_modify_type params; ++ struct sgx_enclave_modify_types params; + long ret; + + ret = sgx_ioc_sgx2_ready(encl); @@ -291,7 +297,7 @@ index 395b4e58a295..8709f131ae40 100644 + if (params.result || params.count) + return -EINVAL; + -+ ret = sgx_enclave_modify_type(encl, ¶ms); ++ ret = sgx_enclave_modify_types(encl, ¶ms); + + if (copy_to_user(arg, ¶ms, sizeof(params))) + return -EFAULT; @@ -302,16 +308,16 @@ index 395b4e58a295..8709f131ae40 100644 long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { struct sgx_encl *encl = filep->private_data; -@@ -897,6 +1095,9 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +@@ -897,6 +1096,9 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) ret = sgx_ioc_enclave_restrict_permissions(encl, (void __user *)arg); break; + case SGX_IOC_ENCLAVE_MODIFY_TYPES: -+ ret = sgx_ioc_enclave_modify_type(encl, (void __user *)arg); ++ ret = sgx_ioc_enclave_modify_types(encl, (void __user *)arg); + break; default: ret = -ENOIOCTLCMD; break; -- -2.35.2 +2.36.1 diff --git a/0019-x86-sgx-Support-complete-page-removal.patch b/0024-x86-sgx-Support-complete-page-removal.patch index bd641e00b777..fc69b5333f0f 100644 --- a/0019-x86-sgx-Support-complete-page-removal.patch +++ b/0024-x86-sgx-Support-complete-page-removal.patch @@ -1,7 +1,7 @@ -From 9a8e4129b4520df5f77037e8be9a69d9878dc949 Mon Sep 17 00:00:00 2001 +From 7d00f6a6de9df6f5daf6f6d866220de01cedd7c7 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:19 -0700 -Subject: [PATCH 19/31] x86/sgx: Support complete page removal +Date: Tue, 10 May 2022 11:08:55 -0700 +Subject: [PATCH 24/36] x86/sgx: Support complete page removal The SGX2 page removal flow was introduced in previous patch and is as follows: @@ -32,6 +32,9 @@ If the user omits running SGX_IOC_ENCLAVE_REMOVE_PAGES the pages will still be removed when the enclave is unloaded. Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> +Tested-by: Haitao Huang <haitao.huang@intel.com> +Tested-by: Vijay Dhanraj <vijay.dhanraj@intel.com> +Tested-by: Jarkko Sakkinen <jarkko@kernel.org> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> --- arch/x86/include/uapi/asm/sgx.h | 21 +++++ @@ -39,19 +42,19 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 2 files changed, 166 insertions(+) diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h -index de4d1af628d5..ec708bd30528 100644 +index 567f6166c24a..2dd35bbdc822 100644 --- a/arch/x86/include/uapi/asm/sgx.h +++ b/arch/x86/include/uapi/asm/sgx.h @@ -33,6 +33,8 @@ enum sgx_page_flags { _IOWR(SGX_MAGIC, 0x05, struct sgx_enclave_restrict_permissions) #define SGX_IOC_ENCLAVE_MODIFY_TYPES \ - _IOWR(SGX_MAGIC, 0x06, struct sgx_enclave_modify_type) + _IOWR(SGX_MAGIC, 0x06, struct sgx_enclave_modify_types) +#define SGX_IOC_ENCLAVE_REMOVE_PAGES \ + _IOWR(SGX_MAGIC, 0x07, struct sgx_enclave_remove_pages) /** * struct sgx_enclave_create - parameter structure for the -@@ -116,6 +118,25 @@ struct sgx_enclave_modify_type { +@@ -117,6 +119,25 @@ struct sgx_enclave_modify_types { __u64 count; }; @@ -78,10 +81,10 @@ index de4d1af628d5..ec708bd30528 100644 /** diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c -index 8709f131ae40..f9a1654a49b7 100644 +index 9ccafbfc4811..1a2595f261d3 100644 --- a/arch/x86/kernel/cpu/sgx/ioctl.c +++ b/arch/x86/kernel/cpu/sgx/ioctl.c -@@ -1070,6 +1070,148 @@ static long sgx_ioc_enclave_modify_type(struct sgx_encl *encl, void __user *arg) +@@ -1071,6 +1071,148 @@ static long sgx_ioc_enclave_modify_types(struct sgx_encl *encl, return ret; } @@ -230,9 +233,9 @@ index 8709f131ae40..f9a1654a49b7 100644 long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { struct sgx_encl *encl = filep->private_data; -@@ -1098,6 +1240,9 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +@@ -1099,6 +1241,9 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) case SGX_IOC_ENCLAVE_MODIFY_TYPES: - ret = sgx_ioc_enclave_modify_type(encl, (void __user *)arg); + ret = sgx_ioc_enclave_modify_types(encl, (void __user *)arg); break; + case SGX_IOC_ENCLAVE_REMOVE_PAGES: + ret = sgx_ioc_enclave_remove_pages(encl, (void __user *)arg); @@ -241,5 +244,5 @@ index 8709f131ae40..f9a1654a49b7 100644 ret = -ENOIOCTLCMD; break; -- -2.35.2 +2.36.1 diff --git a/0020-x86-sgx-Free-up-EPC-pages-directly-to-support-large-.patch b/0025-x86-sgx-Free-up-EPC-pages-directly-to-support-large-.patch index bd86089962d2..b5400b4daf6f 100644 --- a/0020-x86-sgx-Free-up-EPC-pages-directly-to-support-large-.patch +++ b/0025-x86-sgx-Free-up-EPC-pages-directly-to-support-large-.patch @@ -1,7 +1,7 @@ -From 0ed2b241836b30d344da4f8f73ce87878aea5c87 Mon Sep 17 00:00:00 2001 +From 1414f7b29435dc53d5e0d685244210e50f55c1e5 Mon Sep 17 00:00:00 2001 From: Reinette Chatre <reinette.chatre@intel.com> -Date: Wed, 13 Apr 2022 14:10:20 -0700 -Subject: [PATCH 20/31] x86/sgx: Free up EPC pages directly to support large +Date: Tue, 10 May 2022 11:08:56 -0700 +Subject: [PATCH 25/36] x86/sgx: Free up EPC pages directly to support large page ranges The page reclaimer ensures availability of EPC pages across all @@ -32,7 +32,7 @@ Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> 3 files changed, 18 insertions(+) diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c -index f9a1654a49b7..83674d054c13 100644 +index 1a2595f261d3..ebe79d60619f 100644 --- a/arch/x86/kernel/cpu/sgx/ioctl.c +++ b/arch/x86/kernel/cpu/sgx/ioctl.c @@ -745,6 +745,8 @@ sgx_enclave_restrict_permissions(struct sgx_encl *encl, @@ -44,7 +44,7 @@ index f9a1654a49b7..83674d054c13 100644 mutex_lock(&encl->lock); entry = sgx_encl_load_page(encl, addr); -@@ -910,6 +912,8 @@ static long sgx_enclave_modify_type(struct sgx_encl *encl, +@@ -910,6 +912,8 @@ static long sgx_enclave_modify_types(struct sgx_encl *encl, for (c = 0 ; c < modt->length; c += PAGE_SIZE) { addr = encl->base + modt->offset + c; @@ -53,7 +53,7 @@ index f9a1654a49b7..83674d054c13 100644 mutex_lock(&encl->lock); entry = sgx_encl_load_page(encl, addr); -@@ -1095,6 +1099,8 @@ static long sgx_encl_remove_pages(struct sgx_encl *encl, +@@ -1096,6 +1100,8 @@ static long sgx_encl_remove_pages(struct sgx_encl *encl, for (c = 0 ; c < params->length; c += PAGE_SIZE) { addr = encl->base + params->offset + c; @@ -63,10 +63,10 @@ index f9a1654a49b7..83674d054c13 100644 entry = sgx_encl_load_page(encl, addr); diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c -index 1a3014aec490..c6adb7edebca 100644 +index 180ad840b226..5acd4c54d904 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c -@@ -378,6 +378,17 @@ static bool sgx_should_reclaim(unsigned long watermark) +@@ -375,6 +375,17 @@ static bool sgx_should_reclaim(unsigned long watermark) !list_empty(&sgx_active_page_list); } @@ -97,5 +97,5 @@ index b30cee4de903..0f2020653fba 100644 int sgx_unmark_page_reclaimable(struct sgx_epc_page *page); struct sgx_epc_page *sgx_alloc_epc_page(void *owner, bool reclaim); -- -2.35.2 +2.36.1 diff --git a/0026-Documentation-x86-Introduce-enclave-runtime-manageme.patch b/0026-Documentation-x86-Introduce-enclave-runtime-manageme.patch new file mode 100644 index 000000000000..a4d973cf42f0 --- /dev/null +++ b/0026-Documentation-x86-Introduce-enclave-runtime-manageme.patch @@ -0,0 +1,47 @@ +From 77a37ace712749fe260acdf83b1a59e1b4340342 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:08:57 -0700 +Subject: [PATCH 26/36] Documentation/x86: Introduce enclave runtime management + section + +Enclave runtime management is introduced following the pattern +of the section describing enclave building. Provide a brief +summary of enclave runtime management, pointing to the functions +implementing the ioctl()s that will contain details within their +kernel-doc. + +Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + Documentation/x86/sgx.rst | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/Documentation/x86/sgx.rst b/Documentation/x86/sgx.rst +index 265568a9292c..2bcbffacbed5 100644 +--- a/Documentation/x86/sgx.rst ++++ b/Documentation/x86/sgx.rst +@@ -100,6 +100,21 @@ pages and establish enclave page permissions. + sgx_ioc_enclave_init + sgx_ioc_enclave_provision + ++Enclave runtime management ++-------------------------- ++ ++Systems supporting SGX2 additionally support changes to initialized ++enclaves: modifying enclave page permissions and type, and dynamically ++adding and removing of enclave pages. When an enclave accesses an address ++within its address range that does not have a backing page then a new ++regular page will be dynamically added to the enclave. The enclave is ++still required to run EACCEPT on the new page before it can be used. ++ ++.. kernel-doc:: arch/x86/kernel/cpu/sgx/ioctl.c ++ :functions: sgx_ioc_enclave_restrict_permissions ++ sgx_ioc_enclave_modify_types ++ sgx_ioc_enclave_remove_pages ++ + Enclave vDSO + ------------ + +-- +2.36.1 + diff --git a/0027-selftests-sgx-Add-test-for-EPCM-permission-changes.patch b/0027-selftests-sgx-Add-test-for-EPCM-permission-changes.patch new file mode 100644 index 000000000000..06016886a48a --- /dev/null +++ b/0027-selftests-sgx-Add-test-for-EPCM-permission-changes.patch @@ -0,0 +1,356 @@ +From d2441d3dc8f024a09ddb07268947c76f19c36555 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:08:58 -0700 +Subject: [PATCH 27/36] selftests/sgx: Add test for EPCM permission changes + +EPCM permission changes could be made from within (to relax +permissions) or out (to restrict permissions) the enclave. Kernel +support is needed when permissions are restricted to be able to +call the privileged ENCLS[EMODPR] instruction. EPCM permissions +can be relaxed via ENCLU[EMODPE] from within the enclave but the +enclave still depends on the kernel to install PTEs with the needed +permissions. + +Add a test that exercises a few of the enclave page permission flows: +1) Test starts with a RW (from enclave and kernel perspective) + enclave page that is mapped via a RW VMA. +2) Use the SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS ioctl() to restrict + the enclave (EPCM) page permissions to read-only. +3) Run ENCLU[EACCEPT] from within the enclave to accept the new page + permissions. +4) Attempt to write to the enclave page from within the enclave - this + should fail with a page fault on the EPCM permissions since the page + table entry continues to allow RW access. +5) Restore EPCM permissions to RW by running ENCLU[EMODPE] from within + the enclave. +6) Attempt to write to the enclave page from within the enclave - this + should succeed since both EPCM and PTE permissions allow this access. + +Acked-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + tools/testing/selftests/sgx/defines.h | 15 ++ + tools/testing/selftests/sgx/main.c | 214 ++++++++++++++++++++++++ + tools/testing/selftests/sgx/test_encl.c | 38 +++++ + 3 files changed, 267 insertions(+) + +diff --git a/tools/testing/selftests/sgx/defines.h b/tools/testing/selftests/sgx/defines.h +index 02d775789ea7..b638eb98c80c 100644 +--- a/tools/testing/selftests/sgx/defines.h ++++ b/tools/testing/selftests/sgx/defines.h +@@ -24,6 +24,8 @@ enum encl_op_type { + ENCL_OP_PUT_TO_ADDRESS, + ENCL_OP_GET_FROM_ADDRESS, + ENCL_OP_NOP, ++ ENCL_OP_EACCEPT, ++ ENCL_OP_EMODPE, + ENCL_OP_MAX, + }; + +@@ -53,4 +55,17 @@ struct encl_op_get_from_addr { + uint64_t addr; + }; + ++struct encl_op_eaccept { ++ struct encl_op_header header; ++ uint64_t epc_addr; ++ uint64_t flags; ++ uint64_t ret; ++}; ++ ++struct encl_op_emodpe { ++ struct encl_op_header header; ++ uint64_t epc_addr; ++ uint64_t flags; ++}; ++ + #endif /* DEFINES_H */ +diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c +index dd74fa42302e..46eac09cd955 100644 +--- a/tools/testing/selftests/sgx/main.c ++++ b/tools/testing/selftests/sgx/main.c +@@ -25,6 +25,18 @@ static const uint64_t MAGIC = 0x1122334455667788ULL; + static const uint64_t MAGIC2 = 0x8877665544332211ULL; + vdso_sgx_enter_enclave_t vdso_sgx_enter_enclave; + ++/* ++ * Security Information (SECINFO) data structure needed by a few SGX ++ * instructions (eg. ENCLU[EACCEPT] and ENCLU[EMODPE]) holds meta-data ++ * about an enclave page. &enum sgx_secinfo_page_state specifies the ++ * secinfo flags used for page state. ++ */ ++enum sgx_secinfo_page_state { ++ SGX_SECINFO_PENDING = (1 << 3), ++ SGX_SECINFO_MODIFIED = (1 << 4), ++ SGX_SECINFO_PR = (1 << 5), ++}; ++ + struct vdso_symtab { + Elf64_Sym *elf_symtab; + const char *elf_symstrtab; +@@ -555,4 +567,206 @@ TEST_F(enclave, pte_permissions) + EXPECT_EQ(self->run.exception_addr, 0); + } + ++/* ++ * Enclave page permission test. ++ * ++ * Modify and restore enclave page's EPCM (enclave) permissions from ++ * outside enclave (ENCLS[EMODPR] via kernel) as well as from within ++ * enclave (via ENCLU[EMODPE]). Check for page fault if ++ * VMA allows access but EPCM permissions do not. ++ */ ++TEST_F(enclave, epcm_permissions) ++{ ++ struct sgx_enclave_restrict_permissions restrict_ioc; ++ struct encl_op_get_from_addr get_addr_op; ++ struct encl_op_put_to_addr put_addr_op; ++ struct encl_op_eaccept eaccept_op; ++ struct encl_op_emodpe emodpe_op; ++ unsigned long data_start; ++ int ret, errno_save; ++ ++ 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; ++ ++ /* ++ * Ensure kernel supports needed ioctl() and system supports needed ++ * commands. ++ */ ++ memset(&restrict_ioc, 0, sizeof(restrict_ioc)); ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, ++ &restrict_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ /* ++ * Invalid parameters were provided during sanity check, ++ * expect command to fail. ++ */ ++ ASSERT_EQ(ret, -1); ++ ++ /* ret == -1 */ ++ if (errno_save == ENOTTY) ++ SKIP(return, ++ "Kernel does not support SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS ioctl()"); ++ else if (errno_save == ENODEV) ++ SKIP(return, "System does not support SGX2"); ++ ++ /* ++ * Page that will have its permissions changed is the second data ++ * page in the .data segment. This forms part of the local encl_buffer ++ * within the enclave. ++ * ++ * At start of test @data_start should have EPCM as well as PTE and ++ * VMA permissions of RW. ++ */ ++ ++ data_start = self->encl.encl_base + ++ encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ ++ /* ++ * Sanity check that page at @data_start is writable before making ++ * any changes to page permissions. ++ * ++ * Start by writing MAGIC to test page. ++ */ ++ put_addr_op.value = MAGIC; ++ put_addr_op.addr = data_start; ++ 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 that was just written to, confirming that ++ * page is writable. ++ */ ++ get_addr_op.value = 0; ++ get_addr_op.addr = data_start; ++ 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); ++ ++ /* ++ * Change EPCM permissions to read-only. Kernel still considers ++ * the page writable. ++ */ ++ memset(&restrict_ioc, 0, sizeof(restrict_ioc)); ++ ++ restrict_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ restrict_ioc.length = PAGE_SIZE; ++ restrict_ioc.permissions = SGX_SECINFO_R; ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, ++ &restrict_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(restrict_ioc.result, 0); ++ EXPECT_EQ(restrict_ioc.count, 4096); ++ ++ /* ++ * EPCM permissions changed from kernel, need to EACCEPT from enclave. ++ */ ++ eaccept_op.epc_addr = data_start; ++ eaccept_op.flags = SGX_SECINFO_R | SGX_SECINFO_REG | SGX_SECINFO_PR; ++ 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); ++ ++ /* ++ * EPCM permissions of page is now read-only, expect #PF ++ * on EPCM when attempting to write to page from within enclave. ++ */ ++ put_addr_op.value = MAGIC2; ++ ++ 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_error_code, 0x8007); ++ EXPECT_EQ(self->run.exception_addr, data_start); ++ ++ self->run.exception_vector = 0; ++ self->run.exception_error_code = 0; ++ self->run.exception_addr = 0; ++ ++ /* ++ * Received AEX but cannot return to enclave at same entrypoint, ++ * need different TCS from where EPCM permission can be made writable ++ * again. ++ */ ++ self->run.tcs = self->encl.encl_base + PAGE_SIZE; ++ ++ /* ++ * Enter enclave at new TCS to change EPCM permissions to be ++ * writable again and thus fix the page fault that triggered the ++ * AEX. ++ */ ++ ++ emodpe_op.epc_addr = data_start; ++ emodpe_op.flags = SGX_SECINFO_R | SGX_SECINFO_W; ++ emodpe_op.header.type = ENCL_OP_EMODPE; ++ ++ EXPECT_EQ(ENCL_CALL(&emodpe_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); ++ ++ /* ++ * Attempt to return to main TCS to resume execution at faulting ++ * instruction, PTE should continue to allow writing to the page. ++ */ ++ self->run.tcs = self->encl.encl_base; ++ ++ /* ++ * Wrong page permissions that caused original fault has ++ * now been fixed via EPCM permissions. ++ * Resume execution in main TCS to re-attempt the memory access. ++ */ ++ 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); ++ ++ get_addr_op.value = 0; ++ ++ EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); ++ ++ EXPECT_EQ(get_addr_op.value, MAGIC2); ++ EXPECT_EEXIT(&self->run); ++ EXPECT_EQ(self->run.user_data, 0); ++ EXPECT_EQ(self->run.exception_vector, 0); ++ EXPECT_EQ(self->run.exception_error_code, 0); ++ EXPECT_EQ(self->run.exception_addr, 0); ++} ++ + TEST_HARNESS_MAIN +diff --git a/tools/testing/selftests/sgx/test_encl.c b/tools/testing/selftests/sgx/test_encl.c +index 4fca01cfd898..5b6c65331527 100644 +--- a/tools/testing/selftests/sgx/test_encl.c ++++ b/tools/testing/selftests/sgx/test_encl.c +@@ -11,6 +11,42 @@ + */ + static uint8_t encl_buffer[8192] = { 1 }; + ++enum sgx_enclu_function { ++ EACCEPT = 0x5, ++ EMODPE = 0x6, ++}; ++ ++static void do_encl_emodpe(void *_op) ++{ ++ struct sgx_secinfo secinfo __aligned(sizeof(struct sgx_secinfo)) = {0}; ++ struct encl_op_emodpe *op = _op; ++ ++ secinfo.flags = op->flags; ++ ++ asm volatile(".byte 0x0f, 0x01, 0xd7" ++ : ++ : "a" (EMODPE), ++ "b" (&secinfo), ++ "c" (op->epc_addr)); ++} ++ ++static void do_encl_eaccept(void *_op) ++{ ++ struct sgx_secinfo secinfo __aligned(sizeof(struct sgx_secinfo)) = {0}; ++ struct encl_op_eaccept *op = _op; ++ int rax; ++ ++ secinfo.flags = op->flags; ++ ++ asm volatile(".byte 0x0f, 0x01, 0xd7" ++ : "=a" (rax) ++ : "a" (EACCEPT), ++ "b" (&secinfo), ++ "c" (op->epc_addr)); ++ ++ op->ret = rax; ++} ++ + static void *memcpy(void *dest, const void *src, size_t n) + { + size_t i; +@@ -62,6 +98,8 @@ void encl_body(void *rdi, void *rsi) + do_encl_op_put_to_addr, + do_encl_op_get_from_addr, + do_encl_op_nop, ++ do_encl_eaccept, ++ do_encl_emodpe, + }; + + struct encl_op_header *op = (struct encl_op_header *)rdi; +-- +2.36.1 + diff --git a/0028-selftests-sgx-Add-test-for-TCS-page-permission-chang.patch b/0028-selftests-sgx-Add-test-for-TCS-page-permission-chang.patch new file mode 100644 index 000000000000..ebdf31843b1f --- /dev/null +++ b/0028-selftests-sgx-Add-test-for-TCS-page-permission-chang.patch @@ -0,0 +1,106 @@ +From 9df29e1b7db7988ade8f497ff8f29752c7fab17e Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:08:59 -0700 +Subject: [PATCH 28/36] selftests/sgx: Add test for TCS page permission changes + +Kernel should not allow permission changes on TCS pages. Add test to +confirm this behavior. + +Acked-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + tools/testing/selftests/sgx/main.c | 71 ++++++++++++++++++++++++++++++ + 1 file changed, 71 insertions(+) + +diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c +index 46eac09cd955..016ae3e5f398 100644 +--- a/tools/testing/selftests/sgx/main.c ++++ b/tools/testing/selftests/sgx/main.c +@@ -121,6 +121,24 @@ static Elf64_Sym *vdso_symtab_get(struct vdso_symtab *symtab, const char *name) + return NULL; + } + ++/* ++ * Return the offset in the enclave where the TCS segment can be found. ++ * The first RW segment loaded is the TCS. ++ */ ++static off_t encl_get_tcs_offset(struct encl *encl) ++{ ++ int i; ++ ++ for (i = 0; i < encl->nr_segments; i++) { ++ struct encl_segment *seg = &encl->segment_tbl[i]; ++ ++ if (i == 0 && seg->prot == (PROT_READ | PROT_WRITE)) ++ return seg->offset; ++ } ++ ++ return -1; ++} ++ + /* + * Return the offset in the enclave where the data segment can be found. + * The first RW segment loaded is the TCS, skip that to get info on the +@@ -567,6 +585,59 @@ TEST_F(enclave, pte_permissions) + EXPECT_EQ(self->run.exception_addr, 0); + } + ++/* ++ * Modifying permissions of TCS page should not be possible. ++ */ ++TEST_F(enclave, tcs_permissions) ++{ ++ struct sgx_enclave_restrict_permissions ioc; ++ int ret, errno_save; ++ ++ 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; ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ /* ++ * Ensure kernel supports needed ioctl() and system supports needed ++ * commands. ++ */ ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, &ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ /* ++ * Invalid parameters were provided during sanity check, ++ * expect command to fail. ++ */ ++ ASSERT_EQ(ret, -1); ++ ++ /* ret == -1 */ ++ if (errno_save == ENOTTY) ++ SKIP(return, ++ "Kernel does not support SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS ioctl()"); ++ else if (errno_save == ENODEV) ++ SKIP(return, "System does not support SGX2"); ++ ++ /* ++ * Attempt to make TCS page read-only. This is not allowed and ++ * should be prevented by the kernel. ++ */ ++ ioc.offset = encl_get_tcs_offset(&self->encl); ++ ioc.length = PAGE_SIZE; ++ ioc.permissions = SGX_SECINFO_R; ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_RESTRICT_PERMISSIONS, &ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, -1); ++ EXPECT_EQ(errno_save, EINVAL); ++ EXPECT_EQ(ioc.result, 0); ++ EXPECT_EQ(ioc.count, 0); ++} ++ + /* + * Enclave page permission test. + * +-- +2.36.1 + diff --git a/0029-selftests-sgx-Test-two-different-SGX2-EAUG-flows.patch b/0029-selftests-sgx-Test-two-different-SGX2-EAUG-flows.patch new file mode 100644 index 000000000000..daf53975f4bd --- /dev/null +++ b/0029-selftests-sgx-Test-two-different-SGX2-EAUG-flows.patch @@ -0,0 +1,302 @@ +From 322b7009f14f32e6de0e323703e902c0c4515852 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:09:00 -0700 +Subject: [PATCH 29/36] selftests/sgx: Test two different SGX2 EAUG flows + +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. + +Acked-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + tools/testing/selftests/sgx/main.c | 250 +++++++++++++++++++++++++++++ + 1 file changed, 250 insertions(+) + +diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c +index 016ae3e5f398..79c08e347112 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; +@@ -840,4 +849,245 @@ 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. ++ * Kernel will allow new mapping using any permissions if it ++ * falls into the enclave's address range but not backed ++ * by existing enclave pages. ++ */ ++ 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. ++ * ++ * Kernel will allow new mapping using any permissions if it ++ * falls into the enclave's address range but not backed ++ * by existing enclave pages. ++ */ ++ ++ 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.36.1 + diff --git a/0030-selftests-sgx-Introduce-dynamic-entry-point.patch b/0030-selftests-sgx-Introduce-dynamic-entry-point.patch new file mode 100644 index 000000000000..4bfcfbe42560 --- /dev/null +++ b/0030-selftests-sgx-Introduce-dynamic-entry-point.patch @@ -0,0 +1,50 @@ +From ec26d201dbda5703a17e31aeba91b6f8ad0ed47e Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:09:01 -0700 +Subject: [PATCH 30/36] selftests/sgx: Introduce dynamic entry point + +The test enclave (test_encl.elf) is built with two initialized +Thread Control Structures (TCS) included in the binary. Both TCS are +initialized with the same entry point, encl_entry, that correctly +computes the absolute address of the stack based on the stack of each +TCS that is also built into the binary. + +A new TCS can be added dynamically to the enclave and requires to be +initialized with an entry point used to enter the enclave. Since the +existing entry point, encl_entry, assumes that the TCS and its stack +exists at particular offsets within the binary it is not able to handle +a dynamically added TCS and its stack. + +Introduce a new entry point, encl_dyn_entry, that initializes the +absolute address of that thread's stack to the address immediately +preceding the TCS itself. It is now possible to dynamically add a +contiguous memory region to the enclave with the new stack preceding +the new TCS. With the new TCS initialized with encl_dyn_entry as entry +point the absolute address of the stack is computed correctly on entry. + +Acked-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + tools/testing/selftests/sgx/test_encl_bootstrap.S | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/tools/testing/selftests/sgx/test_encl_bootstrap.S b/tools/testing/selftests/sgx/test_encl_bootstrap.S +index 82fb0dfcbd23..03ae0f57e29d 100644 +--- a/tools/testing/selftests/sgx/test_encl_bootstrap.S ++++ b/tools/testing/selftests/sgx/test_encl_bootstrap.S +@@ -45,6 +45,12 @@ encl_entry: + # TCS #2. By adding the value of encl_stack to it, we get + # the absolute address for the stack. + lea (encl_stack)(%rbx), %rax ++ jmp encl_entry_core ++encl_dyn_entry: ++ # Entry point for dynamically created TCS page expected to follow ++ # its stack directly. ++ lea -1(%rbx), %rax ++encl_entry_core: + xchg %rsp, %rax + push %rax + +-- +2.36.1 + diff --git a/0031-selftests-sgx-Introduce-TCS-initialization-enclave-o.patch b/0031-selftests-sgx-Introduce-TCS-initialization-enclave-o.patch new file mode 100644 index 000000000000..2f7205e28264 --- /dev/null +++ b/0031-selftests-sgx-Introduce-TCS-initialization-enclave-o.patch @@ -0,0 +1,102 @@ +From 6a11aaed59fdac23b4ec6c5605381061488e3c07 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:09:02 -0700 +Subject: [PATCH 31/36] selftests/sgx: Introduce TCS initialization enclave + operation + +The Thread Control Structure (TCS) contains meta-data used by the +hardware to save and restore thread specific information when +entering/exiting the enclave. A TCS can be added to an initialized +enclave by first adding a new regular enclave page, initializing the +content of the new page from within the enclave, and then changing that +page's type to a TCS. + +Support the initialization of a TCS from within the enclave. +The variable information needed that should be provided from outside +the enclave is the address of the TCS, address of the State Save Area +(SSA), and the entry point that the thread should use to enter the +enclave. With this information provided all needed fields of a TCS +can be initialized. + +Acked-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + tools/testing/selftests/sgx/defines.h | 8 +++++++ + tools/testing/selftests/sgx/test_encl.c | 30 +++++++++++++++++++++++++ + 2 files changed, 38 insertions(+) + +diff --git a/tools/testing/selftests/sgx/defines.h b/tools/testing/selftests/sgx/defines.h +index b638eb98c80c..d8587c971941 100644 +--- a/tools/testing/selftests/sgx/defines.h ++++ b/tools/testing/selftests/sgx/defines.h +@@ -26,6 +26,7 @@ enum encl_op_type { + ENCL_OP_NOP, + ENCL_OP_EACCEPT, + ENCL_OP_EMODPE, ++ ENCL_OP_INIT_TCS_PAGE, + ENCL_OP_MAX, + }; + +@@ -68,4 +69,11 @@ struct encl_op_emodpe { + uint64_t flags; + }; + ++struct encl_op_init_tcs_page { ++ struct encl_op_header header; ++ uint64_t tcs_page; ++ uint64_t ssa; ++ uint64_t entry; ++}; ++ + #endif /* DEFINES_H */ +diff --git a/tools/testing/selftests/sgx/test_encl.c b/tools/testing/selftests/sgx/test_encl.c +index 5b6c65331527..c0d6397295e3 100644 +--- a/tools/testing/selftests/sgx/test_encl.c ++++ b/tools/testing/selftests/sgx/test_encl.c +@@ -57,6 +57,35 @@ static void *memcpy(void *dest, const void *src, size_t n) + return dest; + } + ++static void *memset(void *dest, int c, size_t n) ++{ ++ size_t i; ++ ++ for (i = 0; i < n; i++) ++ ((char *)dest)[i] = c; ++ ++ return dest; ++} ++ ++static void do_encl_init_tcs_page(void *_op) ++{ ++ struct encl_op_init_tcs_page *op = _op; ++ void *tcs = (void *)op->tcs_page; ++ uint32_t val_32; ++ ++ memset(tcs, 0, 16); /* STATE and FLAGS */ ++ memcpy(tcs + 16, &op->ssa, 8); /* OSSA */ ++ memset(tcs + 24, 0, 4); /* CSSA */ ++ val_32 = 1; ++ memcpy(tcs + 28, &val_32, 4); /* NSSA */ ++ memcpy(tcs + 32, &op->entry, 8); /* OENTRY */ ++ memset(tcs + 40, 0, 24); /* AEP, OFSBASE, OGSBASE */ ++ val_32 = 0xFFFFFFFF; ++ memcpy(tcs + 64, &val_32, 4); /* FSLIMIT */ ++ memcpy(tcs + 68, &val_32, 4); /* GSLIMIT */ ++ memset(tcs + 72, 0, 4024); /* Reserved */ ++} ++ + static void do_encl_op_put_to_buf(void *op) + { + struct encl_op_put_to_buf *op2 = op; +@@ -100,6 +129,7 @@ void encl_body(void *rdi, void *rsi) + do_encl_op_nop, + do_encl_eaccept, + do_encl_emodpe, ++ do_encl_init_tcs_page, + }; + + struct encl_op_header *op = (struct encl_op_header *)rdi; +-- +2.36.1 + diff --git a/0032-selftests-sgx-Test-complete-changing-of-page-type-fl.patch b/0032-selftests-sgx-Test-complete-changing-of-page-type-fl.patch new file mode 100644 index 000000000000..ac5aaf1ab695 --- /dev/null +++ b/0032-selftests-sgx-Test-complete-changing-of-page-type-fl.patch @@ -0,0 +1,448 @@ +From 7e1e0ea10dad3e8d2b372c220153e1455fab0619 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:09:03 -0700 +Subject: [PATCH 32/36] selftests/sgx: Test complete changing of page type flow + +Support for changing an enclave page's type enables an initialized +enclave to be expanded with support for more threads by changing the +type of a regular enclave page to that of a Thread Control Structure +(TCS). Additionally, being able to change a TCS or regular enclave +page's type to be trimmed (SGX_PAGE_TYPE_TRIM) initiates the removal +of the page from the enclave. + +Test changing page type to TCS as well as page removal flows +in two phases: In the first phase support for a new thread is +dynamically added to an initialized enclave and in the second phase +the pages associated with the new thread are removed from the enclave. +As an additional sanity check after the second phase the page used as +a TCS page during the first phase is added back as a regular page and +ensured that it can be written to (which is not possible if it was a +TCS page). + +Acked-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + tools/testing/selftests/sgx/load.c | 41 ++++ + tools/testing/selftests/sgx/main.c | 343 +++++++++++++++++++++++++++++ + tools/testing/selftests/sgx/main.h | 1 + + 3 files changed, 385 insertions(+) + +diff --git a/tools/testing/selftests/sgx/load.c b/tools/testing/selftests/sgx/load.c +index 006b464c8fc9..94bdeac1cf04 100644 +--- a/tools/testing/selftests/sgx/load.c ++++ b/tools/testing/selftests/sgx/load.c +@@ -130,6 +130,47 @@ static bool encl_ioc_add_pages(struct encl *encl, struct encl_segment *seg) + return true; + } + ++/* ++ * Parse the enclave code's symbol table to locate and return address of ++ * the provided symbol ++ */ ++uint64_t encl_get_entry(struct encl *encl, const char *symbol) ++{ ++ Elf64_Shdr *sections; ++ Elf64_Sym *symtab; ++ Elf64_Ehdr *ehdr; ++ char *sym_names; ++ int num_sym; ++ int i; ++ ++ ehdr = encl->bin; ++ sections = encl->bin + ehdr->e_shoff; ++ ++ for (i = 0; i < ehdr->e_shnum; i++) { ++ if (sections[i].sh_type == SHT_SYMTAB) { ++ symtab = (Elf64_Sym *)((char *)encl->bin + sections[i].sh_offset); ++ num_sym = sections[i].sh_size / sections[i].sh_entsize; ++ break; ++ } ++ } ++ ++ for (i = 0; i < ehdr->e_shnum; i++) { ++ if (sections[i].sh_type == SHT_STRTAB) { ++ sym_names = (char *)encl->bin + sections[i].sh_offset; ++ break; ++ } ++ } ++ ++ for (i = 0; i < num_sym; i++) { ++ Elf64_Sym *sym = &symtab[i]; ++ ++ if (!strcmp(symbol, sym_names + sym->st_name)) ++ return (uint64_t)sym->st_value; ++ } ++ ++ return 0; ++} ++ + bool encl_load(const char *path, struct encl *encl, unsigned long heap_size) + { + const char device_path[] = "/dev/sgx_enclave"; +diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c +index 79c08e347112..8bf43646e0bb 100644 +--- a/tools/testing/selftests/sgx/main.c ++++ b/tools/testing/selftests/sgx/main.c +@@ -1090,4 +1090,347 @@ TEST_F(enclave, augment_via_eaccept) + munmap(addr, PAGE_SIZE); + } + ++/* ++ * SGX2 page type modification test in two phases: ++ * Phase 1: ++ * Create a new TCS, consisting out of three new pages (stack page with regular ++ * page type, SSA page with regular page type, and TCS page with TCS page ++ * type) in an initialized enclave and run a simple workload within it. ++ * Phase 2: ++ * Remove the three pages added in phase 1, add a new regular page at the ++ * same address that previously hosted the TCS page and verify that it can ++ * be modified. ++ */ ++TEST_F(enclave, tcs_create) ++{ ++ struct encl_op_init_tcs_page init_tcs_page_op; ++ struct sgx_enclave_remove_pages remove_ioc; ++ struct encl_op_get_from_addr get_addr_op; ++ struct sgx_enclave_modify_types modt_ioc; ++ struct encl_op_put_to_addr put_addr_op; ++ struct encl_op_get_from_buf get_buf_op; ++ struct encl_op_put_to_buf put_buf_op; ++ void *addr, *tcs, *stack_end, *ssa; ++ struct encl_op_eaccept eaccept_op; ++ size_t total_size = 0; ++ uint64_t val_64; ++ int errno_save; ++ int ret, i; ++ ++ 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; ++ ++ /* ++ * Hardware (SGX2) and kernel support is needed for this test. Start ++ * with check that test has a chance of succeeding. ++ */ ++ memset(&modt_ioc, 0, sizeof(modt_ioc)); ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); ++ ++ if (ret == -1) { ++ if (errno == ENOTTY) ++ SKIP(return, ++ "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); ++ else if (errno == ENODEV) ++ SKIP(return, "System does not support SGX2"); ++ } ++ ++ /* ++ * Invalid parameters were provided during sanity check, ++ * expect command to fail. ++ */ ++ EXPECT_EQ(ret, -1); ++ ++ /* ++ * Add three regular pages via EAUG: one will be the TCS stack, one ++ * will be the TCS SSA, and one will be the new TCS. The stack and ++ * SSA will remain as regular pages, the TCS page will need its ++ * type changed after populated with needed data. ++ */ ++ 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 + 3 * PAGE_SIZE, self->encl.encl_size); ++ ++ /* ++ * mmap() three pages at end of existing enclave to be used for the ++ * three new pages. ++ */ ++ addr = mmap((void *)self->encl.encl_base + total_size, 3 * PAGE_SIZE, ++ PROT_READ | PROT_WRITE, 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; ++ ++ stack_end = (void *)self->encl.encl_base + total_size; ++ tcs = (void *)self->encl.encl_base + total_size + PAGE_SIZE; ++ ssa = (void *)self->encl.encl_base + total_size + 2 * PAGE_SIZE; ++ ++ /* ++ * Run EACCEPT on each new page to trigger the ++ * EACCEPT->(#PF)->EAUG->EACCEPT(again without a #PF) flow. ++ */ ++ ++ eaccept_op.epc_addr = (unsigned long)stack_end; ++ 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 == (unsigned long)stack_end) { ++ munmap(addr, 3 * 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); ++ ++ eaccept_op.epc_addr = (unsigned long)ssa; ++ ++ 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); ++ ++ eaccept_op.epc_addr = (unsigned long)tcs; ++ ++ 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); ++ ++ /* ++ * Three new pages added to enclave. Now populate the TCS page with ++ * needed data. This should be done from within enclave. Provide ++ * the function that will do the actual data population with needed ++ * data. ++ */ ++ ++ /* ++ * New TCS will use the "encl_dyn_entry" entrypoint that expects ++ * stack to begin in page before TCS page. ++ */ ++ val_64 = encl_get_entry(&self->encl, "encl_dyn_entry"); ++ EXPECT_NE(val_64, 0); ++ ++ init_tcs_page_op.tcs_page = (unsigned long)tcs; ++ init_tcs_page_op.ssa = (unsigned long)total_size + 2 * PAGE_SIZE; ++ init_tcs_page_op.entry = val_64; ++ init_tcs_page_op.header.type = ENCL_OP_INIT_TCS_PAGE; ++ ++ EXPECT_EQ(ENCL_CALL(&init_tcs_page_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); ++ ++ /* Change TCS page type to TCS. */ ++ memset(&modt_ioc, 0, sizeof(modt_ioc)); ++ ++ modt_ioc.offset = total_size + PAGE_SIZE; ++ modt_ioc.length = PAGE_SIZE; ++ modt_ioc.page_type = SGX_PAGE_TYPE_TCS; ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(modt_ioc.result, 0); ++ EXPECT_EQ(modt_ioc.count, 4096); ++ ++ /* EACCEPT new TCS page from enclave. */ ++ eaccept_op.epc_addr = (unsigned long)tcs; ++ eaccept_op.flags = SGX_SECINFO_TCS | SGX_SECINFO_MODIFIED; ++ 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); ++ ++ /* Run workload from new TCS. */ ++ self->run.tcs = (unsigned long)tcs; ++ ++ /* ++ * Simple workload to write to data buffer and read value back. ++ */ ++ put_buf_op.header.type = ENCL_OP_PUT_TO_BUFFER; ++ put_buf_op.value = MAGIC; ++ ++ EXPECT_EQ(ENCL_CALL(&put_buf_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); ++ ++ get_buf_op.header.type = ENCL_OP_GET_FROM_BUFFER; ++ get_buf_op.value = 0; ++ ++ EXPECT_EQ(ENCL_CALL(&get_buf_op, &self->run, true), 0); ++ ++ EXPECT_EQ(get_buf_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); ++ ++ /* ++ * Phase 2 of test: ++ * Remove pages associated with new TCS, create a regular page ++ * where TCS page used to be and verify it can be used as a regular ++ * page. ++ */ ++ ++ /* Start page removal by requesting change of page type to PT_TRIM. */ ++ memset(&modt_ioc, 0, sizeof(modt_ioc)); ++ ++ modt_ioc.offset = total_size; ++ modt_ioc.length = 3 * PAGE_SIZE; ++ modt_ioc.page_type = SGX_PAGE_TYPE_TRIM; ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(modt_ioc.result, 0); ++ EXPECT_EQ(modt_ioc.count, 3 * PAGE_SIZE); ++ ++ /* ++ * Enter enclave via TCS #1 and approve page removal by sending ++ * EACCEPT for each of three removed pages. ++ */ ++ self->run.tcs = self->encl.encl_base; ++ ++ eaccept_op.epc_addr = (unsigned long)stack_end; ++ eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED; ++ 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); ++ ++ eaccept_op.epc_addr = (unsigned long)tcs; ++ eaccept_op.ret = 0; ++ ++ 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); ++ ++ eaccept_op.epc_addr = (unsigned long)ssa; ++ eaccept_op.ret = 0; ++ ++ 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); ++ ++ /* Send final ioctl() to complete page removal. */ ++ memset(&remove_ioc, 0, sizeof(remove_ioc)); ++ ++ remove_ioc.offset = total_size; ++ remove_ioc.length = 3 * PAGE_SIZE; ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(remove_ioc.count, 3 * PAGE_SIZE); ++ ++ /* ++ * Enter enclave via TCS #1 and access location where TCS #3 was to ++ * trigger dynamic add of regular page at that location. ++ */ ++ eaccept_op.epc_addr = (unsigned long)tcs; ++ 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); ++ ++ /* ++ * New page should be accessible from within enclave - write to it. ++ */ ++ put_addr_op.value = MAGIC; ++ put_addr_op.addr = (unsigned long)tcs; ++ 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)tcs; ++ 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, 3 * PAGE_SIZE); ++} ++ + TEST_HARNESS_MAIN +diff --git a/tools/testing/selftests/sgx/main.h b/tools/testing/selftests/sgx/main.h +index b45c52ec7ab3..fc585be97e2f 100644 +--- a/tools/testing/selftests/sgx/main.h ++++ b/tools/testing/selftests/sgx/main.h +@@ -38,6 +38,7 @@ void encl_delete(struct encl *ctx); + bool encl_load(const char *path, struct encl *encl, unsigned long heap_size); + bool encl_measure(struct encl *encl); + bool encl_build(struct encl *encl); ++uint64_t encl_get_entry(struct encl *encl, const char *symbol); + + int sgx_enter_enclave(void *rdi, void *rsi, long rdx, u32 function, void *r8, void *r9, + struct sgx_enclave_run *run); +-- +2.36.1 + diff --git a/0033-selftests-sgx-Test-faulty-enclave-behavior.patch b/0033-selftests-sgx-Test-faulty-enclave-behavior.patch new file mode 100644 index 000000000000..adf4755a6198 --- /dev/null +++ b/0033-selftests-sgx-Test-faulty-enclave-behavior.patch @@ -0,0 +1,149 @@ +From aedac9dcb6fcb4be2650b05d71a85c77026282bc Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:09:04 -0700 +Subject: [PATCH 33/36] selftests/sgx: Test faulty enclave behavior + +Removing a page from an initialized enclave involves three steps: +first the user requests changing the page type to SGX_PAGE_TYPE_TRIM +via an ioctl(), on success the ENCLU[EACCEPT] instruction needs to be +run from within the enclave to accept the page removal, finally the +user requests page removal to be completed via an ioctl(). Only after +acceptance (ENCLU[EACCEPT]) from within the enclave can the kernel +remove the page from a running enclave. + +Test the behavior when the user's request to change the page type +succeeds, but the ENCLU[EACCEPT] instruction is not run before the +ioctl() requesting page removal is run. This should not be permitted. + +Acked-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + tools/testing/selftests/sgx/main.c | 114 +++++++++++++++++++++++++++++ + 1 file changed, 114 insertions(+) + +diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c +index 8bf43646e0bb..3a82bae915d1 100644 +--- a/tools/testing/selftests/sgx/main.c ++++ b/tools/testing/selftests/sgx/main.c +@@ -1433,4 +1433,118 @@ TEST_F(enclave, tcs_create) + munmap(addr, 3 * PAGE_SIZE); + } + ++/* ++ * Ensure sane behavior if user requests page removal, does not run ++ * EACCEPT from within enclave but still attempts to finalize page removal ++ * with the SGX_IOC_ENCLAVE_REMOVE_PAGES ioctl(). The latter should fail ++ * because the removal was not EACCEPTed from within the enclave. ++ */ ++TEST_F(enclave, remove_added_page_no_eaccept) ++{ ++ struct sgx_enclave_remove_pages remove_ioc; ++ struct encl_op_get_from_addr get_addr_op; ++ struct sgx_enclave_modify_types modt_ioc; ++ struct encl_op_put_to_addr put_addr_op; ++ unsigned long data_start; ++ int ret, errno_save; ++ ++ 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; ++ ++ /* ++ * Hardware (SGX2) and kernel support is needed for this test. Start ++ * with check that test has a chance of succeeding. ++ */ ++ memset(&modt_ioc, 0, sizeof(modt_ioc)); ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); ++ ++ if (ret == -1) { ++ if (errno == ENOTTY) ++ SKIP(return, ++ "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); ++ else if (errno == ENODEV) ++ SKIP(return, "System does not support SGX2"); ++ } ++ ++ /* ++ * Invalid parameters were provided during sanity check, ++ * expect command to fail. ++ */ ++ EXPECT_EQ(ret, -1); ++ ++ /* ++ * Page that will be removed is the second data page in the .data ++ * segment. This forms part of the local encl_buffer within the ++ * enclave. ++ */ ++ data_start = self->encl.encl_base + ++ encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ ++ /* ++ * Sanity check that page at @data_start is writable before ++ * removing it. ++ * ++ * Start by writing MAGIC to test page. ++ */ ++ put_addr_op.value = MAGIC; ++ put_addr_op.addr = data_start; ++ 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 that was just written to, confirming that data ++ * previously written (MAGIC) is present. ++ */ ++ get_addr_op.value = 0; ++ get_addr_op.addr = data_start; ++ 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); ++ ++ /* Start page removal by requesting change of page type to PT_TRIM */ ++ memset(&modt_ioc, 0, sizeof(modt_ioc)); ++ ++ modt_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ modt_ioc.length = PAGE_SIZE; ++ modt_ioc.page_type = SGX_PAGE_TYPE_TRIM; ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(modt_ioc.result, 0); ++ EXPECT_EQ(modt_ioc.count, 4096); ++ ++ /* Skip EACCEPT */ ++ ++ /* Send final ioctl() to complete page removal */ ++ memset(&remove_ioc, 0, sizeof(remove_ioc)); ++ ++ remove_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ remove_ioc.length = PAGE_SIZE; ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ /* Operation not permitted since EACCEPT was omitted. */ ++ EXPECT_EQ(ret, -1); ++ EXPECT_EQ(errno_save, EPERM); ++ EXPECT_EQ(remove_ioc.count, 0); ++} ++ + TEST_HARNESS_MAIN +-- +2.36.1 + diff --git a/0034-selftests-sgx-Test-invalid-access-to-removed-enclave.patch b/0034-selftests-sgx-Test-invalid-access-to-removed-enclave.patch new file mode 100644 index 000000000000..17d72bdc2ccf --- /dev/null +++ b/0034-selftests-sgx-Test-invalid-access-to-removed-enclave.patch @@ -0,0 +1,290 @@ +From 8dabc1d4d87c7e7aabcee17020b76e1ce9b1bb1a Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:09:05 -0700 +Subject: [PATCH 34/36] selftests/sgx: Test invalid access to removed enclave + page + +Removing a page from an initialized enclave involves three steps: +(1) the user requests changing the page type to SGX_PAGE_TYPE_TRIM +via the SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl(), (2) on success the +ENCLU[EACCEPT] instruction is run from within the enclave to accept +the page removal, (3) the user initiates the actual removal of the +page via the SGX_IOC_ENCLAVE_REMOVE_PAGES ioctl(). + +Test two possible invalid accesses during the page removal flow: +* Test the behavior when a request to remove the page by changing its + type to SGX_PAGE_TYPE_TRIM completes successfully but instead of + executing ENCLU[EACCEPT] from within the enclave the enclave attempts + to read from the page. Even though the page is accessible from the + page table entries its type is SGX_PAGE_TYPE_TRIM and thus not + accessible according to SGX. The expected behavior is a page fault + with the SGX flag set in the error code. +* Test the behavior when the page type is changed successfully and + ENCLU[EACCEPT] was run from within the enclave. The final ioctl(), + SGX_IOC_ENCLAVE_REMOVE_PAGES, is omitted and replaced with an + attempt to access the page. Even though the page is accessible + from the page table entries its type is SGX_PAGE_TYPE_TRIM and + thus not accessible according to SGX. The expected behavior is + a page fault with the SGX flag set in the error code. + +Acked-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + 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 3a82bae915d1..2c69045253b2 100644 +--- a/tools/testing/selftests/sgx/main.c ++++ b/tools/testing/selftests/sgx/main.c +@@ -1547,4 +1547,247 @@ TEST_F(enclave, remove_added_page_no_eaccept) + EXPECT_EQ(remove_ioc.count, 0); + } + ++/* ++ * Request enclave page removal but instead of correctly following with ++ * EACCEPT a read attempt to page is made from within the enclave. ++ */ ++TEST_F(enclave, remove_added_page_invalid_access) ++{ ++ struct encl_op_get_from_addr get_addr_op; ++ struct encl_op_put_to_addr put_addr_op; ++ struct sgx_enclave_modify_types ioc; ++ unsigned long data_start; ++ int ret, errno_save; ++ ++ 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; ++ ++ /* ++ * Hardware (SGX2) and kernel support is needed for this test. Start ++ * with check that test has a chance of succeeding. ++ */ ++ memset(&ioc, 0, sizeof(ioc)); ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc); ++ ++ if (ret == -1) { ++ if (errno == ENOTTY) ++ SKIP(return, ++ "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); ++ else if (errno == ENODEV) ++ SKIP(return, "System does not support SGX2"); ++ } ++ ++ /* ++ * Invalid parameters were provided during sanity check, ++ * expect command to fail. ++ */ ++ EXPECT_EQ(ret, -1); ++ ++ /* ++ * Page that will be removed is the second data page in the .data ++ * segment. This forms part of the local encl_buffer within the ++ * enclave. ++ */ ++ data_start = self->encl.encl_base + ++ encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ ++ /* ++ * Sanity check that page at @data_start is writable before ++ * removing it. ++ * ++ * Start by writing MAGIC to test page. ++ */ ++ put_addr_op.value = MAGIC; ++ put_addr_op.addr = data_start; ++ 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 that was just written to, confirming that data ++ * previously written (MAGIC) is present. ++ */ ++ get_addr_op.value = 0; ++ get_addr_op.addr = data_start; ++ 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); ++ ++ /* Start page removal by requesting change of page type to PT_TRIM. */ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ ioc.length = PAGE_SIZE; ++ ioc.page_type = SGX_PAGE_TYPE_TRIM; ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(ioc.result, 0); ++ EXPECT_EQ(ioc.count, 4096); ++ ++ /* ++ * Read from page that was just removed. ++ */ ++ get_addr_op.value = 0; ++ ++ EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); ++ ++ /* ++ * From kernel perspective the page is present but according to SGX the ++ * page should not be accessible so a #PF with SGX bit set is ++ * expected. ++ */ ++ ++ EXPECT_EQ(self->run.function, ERESUME); ++ EXPECT_EQ(self->run.exception_vector, 14); ++ EXPECT_EQ(self->run.exception_error_code, 0x8005); ++ EXPECT_EQ(self->run.exception_addr, data_start); ++} ++ ++/* ++ * Request enclave page removal and correctly follow with ++ * EACCEPT but do not follow with removal ioctl() but instead a read attempt ++ * to removed page is made from within the enclave. ++ */ ++TEST_F(enclave, remove_added_page_invalid_access_after_eaccept) ++{ ++ struct encl_op_get_from_addr get_addr_op; ++ struct encl_op_put_to_addr put_addr_op; ++ struct sgx_enclave_modify_types ioc; ++ struct encl_op_eaccept eaccept_op; ++ unsigned long data_start; ++ int ret, errno_save; ++ ++ 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; ++ ++ /* ++ * Hardware (SGX2) and kernel support is needed for this test. Start ++ * with check that test has a chance of succeeding. ++ */ ++ memset(&ioc, 0, sizeof(ioc)); ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc); ++ ++ if (ret == -1) { ++ if (errno == ENOTTY) ++ SKIP(return, ++ "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); ++ else if (errno == ENODEV) ++ SKIP(return, "System does not support SGX2"); ++ } ++ ++ /* ++ * Invalid parameters were provided during sanity check, ++ * expect command to fail. ++ */ ++ EXPECT_EQ(ret, -1); ++ ++ /* ++ * Page that will be removed is the second data page in the .data ++ * segment. This forms part of the local encl_buffer within the ++ * enclave. ++ */ ++ data_start = self->encl.encl_base + ++ encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ ++ /* ++ * Sanity check that page at @data_start is writable before ++ * removing it. ++ * ++ * Start by writing MAGIC to test page. ++ */ ++ put_addr_op.value = MAGIC; ++ put_addr_op.addr = data_start; ++ 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 that was just written to, confirming that data ++ * previously written (MAGIC) is present. ++ */ ++ get_addr_op.value = 0; ++ get_addr_op.addr = data_start; ++ 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); ++ ++ /* Start page removal by requesting change of page type to PT_TRIM. */ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ ioc.length = PAGE_SIZE; ++ ioc.page_type = SGX_PAGE_TYPE_TRIM; ++ ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(ioc.result, 0); ++ EXPECT_EQ(ioc.count, 4096); ++ ++ eaccept_op.epc_addr = (unsigned long)data_start; ++ eaccept_op.ret = 0; ++ eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED; ++ 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); ++ ++ /* Skip ioctl() to remove page. */ ++ ++ /* ++ * Read from page that was just removed. ++ */ ++ get_addr_op.value = 0; ++ ++ EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0); ++ ++ /* ++ * From kernel perspective the page is present but according to SGX the ++ * page should not be accessible so a #PF with SGX bit set is ++ * expected. ++ */ ++ ++ EXPECT_EQ(self->run.function, ERESUME); ++ EXPECT_EQ(self->run.exception_vector, 14); ++ EXPECT_EQ(self->run.exception_error_code, 0x8005); ++ EXPECT_EQ(self->run.exception_addr, data_start); ++} ++ + TEST_HARNESS_MAIN +-- +2.36.1 + diff --git a/0035-selftests-sgx-Test-reclaiming-of-untouched-page.patch b/0035-selftests-sgx-Test-reclaiming-of-untouched-page.patch new file mode 100644 index 000000000000..acc9b95fe5c4 --- /dev/null +++ b/0035-selftests-sgx-Test-reclaiming-of-untouched-page.patch @@ -0,0 +1,119 @@ +From dd6d57606c6704b5e53e71fd4501b4d96242d007 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:09:06 -0700 +Subject: [PATCH 35/36] selftests/sgx: Test reclaiming of untouched page + +Removing a page from an initialized enclave involves three steps: +(1) the user requests changing the page type to PT_TRIM via the + SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl() +(2) on success the ENCLU[EACCEPT] instruction is run from within + the enclave to accept the page removal +(3) the user initiates the actual removal of the page via the + SGX_IOC_ENCLAVE_REMOVE_PAGES ioctl(). + +Remove a page that has never been accessed. This means that when the +first ioctl() requesting page removal arrives, there will be no page +table entry, yet a valid page table entry needs to exist for the +ENCLU[EACCEPT] function to succeed. In this test it is verified that +a page table entry can still be installed for a page that is in the +process of being removed. + +Suggested-by: Haitao Huang <haitao.huang@intel.com> +Acked-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + tools/testing/selftests/sgx/main.c | 80 ++++++++++++++++++++++++++++++ + 1 file changed, 80 insertions(+) + +diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c +index 2c69045253b2..ba16671aef79 100644 +--- a/tools/testing/selftests/sgx/main.c ++++ b/tools/testing/selftests/sgx/main.c +@@ -1790,4 +1790,84 @@ TEST_F(enclave, remove_added_page_invalid_access_after_eaccept) + EXPECT_EQ(self->run.exception_addr, data_start); + } + ++TEST_F(enclave, remove_untouched_page) ++{ ++ struct sgx_enclave_remove_pages remove_ioc; ++ struct sgx_enclave_modify_types modt_ioc; ++ struct encl_op_eaccept eaccept_op; ++ unsigned long data_start; ++ int ret, errno_save; ++ ++ ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata)); ++ ++ /* ++ * Hardware (SGX2) and kernel support is needed for this test. Start ++ * with check that test has a chance of succeeding. ++ */ ++ memset(&modt_ioc, 0, sizeof(modt_ioc)); ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); ++ ++ if (ret == -1) { ++ if (errno == ENOTTY) ++ SKIP(return, ++ "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); ++ else if (errno == ENODEV) ++ SKIP(return, "System does not support SGX2"); ++ } ++ ++ /* ++ * Invalid parameters were provided during sanity check, ++ * expect command to fail. ++ */ ++ EXPECT_EQ(ret, -1); ++ ++ /* SGX2 is supported by kernel and hardware, test can proceed. */ ++ memset(&self->run, 0, sizeof(self->run)); ++ self->run.tcs = self->encl.encl_base; ++ ++ data_start = self->encl.encl_base + ++ encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ ++ memset(&modt_ioc, 0, sizeof(modt_ioc)); ++ ++ modt_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ modt_ioc.length = PAGE_SIZE; ++ modt_ioc.page_type = SGX_PAGE_TYPE_TRIM; ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(modt_ioc.result, 0); ++ EXPECT_EQ(modt_ioc.count, 4096); ++ ++ /* ++ * Enter enclave via TCS #1 and approve page removal by sending ++ * EACCEPT for removed page. ++ */ ++ ++ eaccept_op.epc_addr = data_start; ++ eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED; ++ 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); ++ ++ memset(&remove_ioc, 0, sizeof(remove_ioc)); ++ ++ remove_ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE; ++ remove_ioc.length = PAGE_SIZE; ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(remove_ioc.count, 4096); ++} ++ + TEST_HARNESS_MAIN +-- +2.36.1 + diff --git a/0036-selftests-sgx-Page-removal-stress-test.patch b/0036-selftests-sgx-Page-removal-stress-test.patch new file mode 100644 index 000000000000..de29fe7a8ecc --- /dev/null +++ b/0036-selftests-sgx-Page-removal-stress-test.patch @@ -0,0 +1,155 @@ +From 60d3fab7ef151f02110786f64633d70e0a0f8f14 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre <reinette.chatre@intel.com> +Date: Tue, 10 May 2022 11:09:07 -0700 +Subject: [PATCH 36/36] selftests/sgx: Page removal stress test + +Create enclave with additional heap that consumes all physical SGX +memory and then remove it. + +Depending on the available SGX memory this test could take a +significant time to run (several minutes) as it (1) creates the +enclave, (2) changes the type of every page to be trimmed, +(3) enters the enclave once per page to run EACCEPT, before +(4) the pages are finally removed. + +Acked-by: Jarkko Sakkinen <jarkko@kernel.org> +Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> +--- + tools/testing/selftests/sgx/main.c | 120 +++++++++++++++++++++++++++++ + 1 file changed, 120 insertions(+) + +diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c +index ba16671aef79..9820b3809c69 100644 +--- a/tools/testing/selftests/sgx/main.c ++++ b/tools/testing/selftests/sgx/main.c +@@ -378,7 +378,127 @@ TEST_F(enclave, unclobbered_vdso_oversubscribed) + EXPECT_EQ(get_op.value, MAGIC); + EXPECT_EEXIT(&self->run); + EXPECT_EQ(self->run.user_data, 0); ++} ++ ++TEST_F_TIMEOUT(enclave, unclobbered_vdso_oversubscribed_remove, 900) ++{ ++ struct sgx_enclave_remove_pages remove_ioc; ++ struct sgx_enclave_modify_types modt_ioc; ++ struct encl_op_get_from_buf get_op; ++ struct encl_op_eaccept eaccept_op; ++ struct encl_op_put_to_buf put_op; ++ struct encl_segment *heap; ++ unsigned long total_mem; ++ int ret, errno_save; ++ unsigned long addr; ++ unsigned long i; ++ ++ /* ++ * Create enclave with additional heap that is as big as all ++ * available physical SGX memory. ++ */ ++ total_mem = get_total_epc_mem(); ++ ASSERT_NE(total_mem, 0); ++ TH_LOG("Creating an enclave with %lu bytes heap may take a while ...", ++ total_mem); ++ ASSERT_TRUE(setup_test_encl(total_mem, &self->encl, _metadata)); ++ ++ /* ++ * Hardware (SGX2) and kernel support is needed for this test. Start ++ * with check that test has a chance of succeeding. ++ */ ++ memset(&modt_ioc, 0, sizeof(modt_ioc)); ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); ++ ++ if (ret == -1) { ++ if (errno == ENOTTY) ++ SKIP(return, ++ "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()"); ++ else if (errno == ENODEV) ++ SKIP(return, "System does not support SGX2"); ++ } ++ ++ /* ++ * Invalid parameters were provided during sanity check, ++ * expect command to fail. ++ */ ++ EXPECT_EQ(ret, -1); ++ ++ /* SGX2 is supported by kernel and hardware, test can proceed. */ ++ memset(&self->run, 0, sizeof(self->run)); ++ self->run.tcs = self->encl.encl_base; ++ ++ heap = &self->encl.segment_tbl[self->encl.nr_segments - 1]; ++ ++ put_op.header.type = ENCL_OP_PUT_TO_BUFFER; ++ put_op.value = MAGIC; ++ ++ EXPECT_EQ(ENCL_CALL(&put_op, &self->run, false), 0); ++ ++ EXPECT_EEXIT(&self->run); ++ EXPECT_EQ(self->run.user_data, 0); ++ ++ get_op.header.type = ENCL_OP_GET_FROM_BUFFER; ++ get_op.value = 0; ++ ++ EXPECT_EQ(ENCL_CALL(&get_op, &self->run, false), 0); ++ ++ EXPECT_EQ(get_op.value, MAGIC); ++ EXPECT_EEXIT(&self->run); ++ EXPECT_EQ(self->run.user_data, 0); + ++ /* Trim entire heap. */ ++ memset(&modt_ioc, 0, sizeof(modt_ioc)); ++ ++ modt_ioc.offset = heap->offset; ++ modt_ioc.length = heap->size; ++ modt_ioc.page_type = SGX_PAGE_TYPE_TRIM; ++ ++ TH_LOG("Changing type of %zd bytes to trimmed may take a while ...", ++ heap->size); ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(modt_ioc.result, 0); ++ EXPECT_EQ(modt_ioc.count, heap->size); ++ ++ /* EACCEPT all removed pages. */ ++ addr = self->encl.encl_base + heap->offset; ++ ++ eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED; ++ eaccept_op.header.type = ENCL_OP_EACCEPT; ++ ++ TH_LOG("Entering enclave to run EACCEPT for each page of %zd bytes may take a while ...", ++ heap->size); ++ for (i = 0; i < heap->size; i += 4096) { ++ eaccept_op.epc_addr = addr + i; ++ eaccept_op.ret = 0; ++ ++ EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0); ++ ++ EXPECT_EQ(self->run.exception_vector, 0); ++ EXPECT_EQ(self->run.exception_error_code, 0); ++ EXPECT_EQ(self->run.exception_addr, 0); ++ ASSERT_EQ(eaccept_op.ret, 0); ++ ASSERT_EQ(self->run.function, EEXIT); ++ } ++ ++ /* Complete page removal. */ ++ memset(&remove_ioc, 0, sizeof(remove_ioc)); ++ ++ remove_ioc.offset = heap->offset; ++ remove_ioc.length = heap->size; ++ ++ TH_LOG("Removing %zd bytes from enclave may take a while ...", ++ heap->size); ++ ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc); ++ errno_save = ret == -1 ? errno : 0; ++ ++ EXPECT_EQ(ret, 0); ++ EXPECT_EQ(errno_save, 0); ++ EXPECT_EQ(remove_ioc.count, heap->size); + } + + TEST_F(enclave, clobbered_vdso) +-- +2.36.1 + @@ -1,7 +1,7 @@ # Maintainer: Jarkko Sakkinen <jarkko.sakkinen@iki.fi> pkgbase=linux-sgx -pkgver=5.17.4.arch1 +pkgver=5.17.7.arch1 pkgrel=1 pkgdesc='Linux' _srctag=v${pkgver%.*}-${pkgver##*.} @@ -18,26 +18,42 @@ _srcname=archlinux-linux source=( "$_srcname::git+https://github.com/archlinux/linux?signed#tag=$_srctag" config # the main kernel config file - 0001-x86-sgx-Add-short-descriptions-to-ENCLS-wrappers.patch - 0002-x86-sgx-Add-wrapper-for-SGX2-EMODPR-function.patch - 0003-x86-sgx-Add-wrapper-for-SGX2-EMODT-function.patch - 0004-x86-sgx-Add-wrapper-for-SGX2-EAUG-function.patch - 0005-x86-sgx-Support-loading-enclave-page-without-VMA-per.patch - 0006-x86-sgx-Export-sgx_encl_ewb_cpumask.patch - 0007-x86-sgx-Rename-sgx_encl_ewb_cpumask-as-sgx_encl_cpum.patch - 0008-x86-sgx-Move-PTE-zap-code-to-new-sgx_zap_enclave_pte.patch - 0009-x86-sgx-Make-sgx_ipi_cb-available-internally.patch - 0010-x86-sgx-Create-utility-to-validate-user-provided-off.patch - 0011-x86-sgx-Keep-record-of-SGX-page-type.patch - 0012-x86-sgx-Export-sgx_encl_-grow-shrink.patch - 0013-x86-sgx-Export-sgx_encl_page_alloc.patch - 0014-x86-sgx-Support-VA-page-allocation-without-reclaimin.patch - 0015-x86-sgx-Support-restricting-of-enclave-page-permissi.patch - 0016-x86-sgx-Support-adding-of-pages-to-an-initialized-en.patch - 0017-x86-sgx-Tighten-accessible-memory-range-after-enclav.patch - 0018-x86-sgx-Support-modifying-SGX-page-type.patch - 0019-x86-sgx-Support-complete-page-removal.patch - 0020-x86-sgx-Free-up-EPC-pages-directly-to-support-large-.patch + 0001-x86-sgx-Disconnect-backing-page-references-from-dirt.patch + 0002-x86-sgx-Mark-PCMD-page-as-dirty-when-modifying-conte.patch + 0003-x86-sgx-Obtain-backing-storage-page-with-enclave-mut.patch + 0004-x86-sgx-Fix-race-between-reclaimer-and-page-fault-ha.patch + 0005-x86-sgx-Ensure-no-data-in-PCMD-page-after-truncate.patch + 0006-x86-sgx-Add-short-descriptions-to-ENCLS-wrappers.patch + 0007-x86-sgx-Add-wrapper-for-SGX2-EMODPR-function.patch + 0008-x86-sgx-Add-wrapper-for-SGX2-EMODT-function.patch + 0009-x86-sgx-Add-wrapper-for-SGX2-EAUG-function.patch + 0010-x86-sgx-Support-loading-enclave-page-without-VMA-per.patch + 0011-x86-sgx-Export-sgx_encl_ewb_cpumask.patch + 0012-x86-sgx-Rename-sgx_encl_ewb_cpumask-as-sgx_encl_cpum.patch + 0013-x86-sgx-Move-PTE-zap-code-to-new-sgx_zap_enclave_pte.patch + 0014-x86-sgx-Make-sgx_ipi_cb-available-internally.patch + 0015-x86-sgx-Create-utility-to-validate-user-provided-off.patch + 0016-x86-sgx-Keep-record-of-SGX-page-type.patch + 0017-x86-sgx-Export-sgx_encl_-grow-shrink.patch + 0018-x86-sgx-Export-sgx_encl_page_alloc.patch + 0019-x86-sgx-Support-VA-page-allocation-without-reclaimin.patch + 0020-x86-sgx-Support-restricting-of-enclave-page-permissi.patch + 0021-x86-sgx-Support-adding-of-pages-to-an-initialized-en.patch + 0022-x86-sgx-Tighten-accessible-memory-range-after-enclav.patch + 0023-x86-sgx-Support-modifying-SGX-page-type.patch + 0024-x86-sgx-Support-complete-page-removal.patch + 0025-x86-sgx-Free-up-EPC-pages-directly-to-support-large-.patch + 0026-Documentation-x86-Introduce-enclave-runtime-manageme.patch + 0027-selftests-sgx-Add-test-for-EPCM-permission-changes.patch + 0028-selftests-sgx-Add-test-for-TCS-page-permission-chang.patch + 0029-selftests-sgx-Test-two-different-SGX2-EAUG-flows.patch + 0030-selftests-sgx-Introduce-dynamic-entry-point.patch + 0031-selftests-sgx-Introduce-TCS-initialization-enclave-o.patch + 0032-selftests-sgx-Test-complete-changing-of-page-type-fl.patch + 0033-selftests-sgx-Test-faulty-enclave-behavior.patch + 0034-selftests-sgx-Test-invalid-access-to-removed-enclave.patch + 0035-selftests-sgx-Test-reclaiming-of-untouched-page.patch + 0036-selftests-sgx-Page-removal-stress-test.patch ) validpgpkeys=( 'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds @@ -46,7 +62,7 @@ validpgpkeys=( 'C7E7849466FE2358343588377258734B41C31549' # David Runge <dvzrv@archlinux.org> ) sha256sums=('SKIP' - '3f02a0f2fe820f678d15fb0efce04e3716bdc7590d452317bf1b0b63f3b31cd2') + 'fb37785c43d90085ab4e7d7cee522cb8232713b6c601d74cfc7234eeaeb1e6b5') export KBUILD_BUILD_HOST=archlinux export KBUILD_BUILD_USER=$pkgbase |