• Reinette Chatre's avatar
    x86/sgx: Obtain backing storage page with enclave mutex held · 0e4e729a
    Reinette Chatre authored
    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: 1728ab54 ("x86/sgx: Add a page reclaimer")
    Reported-by: default avatarHaitao Huang <haitao.huang@intel.com>
    Signed-off-by: default avatarReinette Chatre <reinette.chatre@intel.com>
    Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
    Reviewed-by: default avatarJarkko Sakkinen <jarkko@kernel.org>
    Tested-by: default avatarJarkko Sakkinen <jarkko@kernel.org>
    Tested-by: default avatarHaitao Huang <haitao.huang@intel.com>
    Link: https://lkml.kernel.org/r/fa2e04c561a8555bfe1f4e7adc37d60efc77387b.1652389823.git.reinette.chatre@intel.com
    0e4e729a
main.c 24.7 KB