Skip to content

Commit 6bd4296

Browse files
rchatrehansendc
authored andcommitted
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: [email protected] Fixes: 1728ab5 ("x86/sgx: Add a page reclaimer") Suggested-by: Dave Hansen <[email protected]> Signed-off-by: Reinette Chatre <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Reviewed-by: Jarkko Sakkinen <[email protected]> Tested-by: Haitao Huang <[email protected]> Link: https://lore.kernel.org/linux-sgx/[email protected]/ Link: https://lkml.kernel.org/r/fa9f98986923f43e72ef4c6702a50b2a0b3c42e3.1652389823.git.reinette.chatre@intel.com
1 parent 42226c9 commit 6bd4296

File tree

3 files changed

+7
-11
lines changed

3 files changed

+7
-11
lines changed

arch/x86/kernel/cpu/sgx/encl.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ static int __sgx_encl_eldu(struct sgx_encl_page *encl_page,
9494
kunmap_atomic(pcmd_page);
9595
kunmap_atomic((void *)(unsigned long)pginfo.contents);
9696

97-
sgx_encl_put_backing(&b, false);
97+
sgx_encl_put_backing(&b);
9898

9999
sgx_encl_truncate_backing_page(encl, page_index);
100100

@@ -645,15 +645,9 @@ int sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index,
645645
/**
646646
* sgx_encl_put_backing() - Unpin the backing storage
647647
* @backing: data for accessing backing storage for the page
648-
* @do_write: mark pages dirty
649648
*/
650-
void sgx_encl_put_backing(struct sgx_backing *backing, bool do_write)
649+
void sgx_encl_put_backing(struct sgx_backing *backing)
651650
{
652-
if (do_write) {
653-
set_page_dirty(backing->pcmd);
654-
set_page_dirty(backing->contents);
655-
}
656-
657651
put_page(backing->pcmd);
658652
put_page(backing->contents);
659653
}

arch/x86/kernel/cpu/sgx/encl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ void sgx_encl_release(struct kref *ref);
107107
int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm);
108108
int sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index,
109109
struct sgx_backing *backing);
110-
void sgx_encl_put_backing(struct sgx_backing *backing, bool do_write);
110+
void sgx_encl_put_backing(struct sgx_backing *backing);
111111
int sgx_encl_test_and_clear_young(struct mm_struct *mm,
112112
struct sgx_encl_page *page);
113113

arch/x86/kernel/cpu/sgx/main.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ static int __sgx_encl_ewb(struct sgx_epc_page *epc_page, void *va_slot,
191191
backing->pcmd_offset;
192192

193193
ret = __ewb(&pginfo, sgx_get_epc_virt_addr(epc_page), va_slot);
194+
set_page_dirty(backing->pcmd);
195+
set_page_dirty(backing->contents);
194196

195197
kunmap_atomic((void *)(unsigned long)(pginfo.metadata -
196198
backing->pcmd_offset));
@@ -320,7 +322,7 @@ static void sgx_reclaimer_write(struct sgx_epc_page *epc_page,
320322
sgx_encl_free_epc_page(encl->secs.epc_page);
321323
encl->secs.epc_page = NULL;
322324

323-
sgx_encl_put_backing(&secs_backing, true);
325+
sgx_encl_put_backing(&secs_backing);
324326
}
325327

326328
out:
@@ -411,7 +413,7 @@ static void sgx_reclaim_pages(void)
411413

412414
encl_page = epc_page->owner;
413415
sgx_reclaimer_write(epc_page, &backing[i]);
414-
sgx_encl_put_backing(&backing[i], true);
416+
sgx_encl_put_backing(&backing[i]);
415417

416418
kref_put(&encl_page->encl->refcount, sgx_encl_release);
417419
epc_page->flags &= ~SGX_EPC_PAGE_RECLAIMER_TRACKED;

0 commit comments

Comments
 (0)