lkml.org 
[lkml]   [2020]   [Nov]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v40 22/24] x86/sgx: Add ptrace() support for the SGX driver
    Date
    Enclave memory is normally inaccessible from outside the enclave.  This
    makes enclaves hard to debug. However, enclaves can be put in a debug mode
    when they are being built. In debug enclaves data *can* be read and/or
    written by using the ENCLS[EDBGRD] and ENCLS[EDBGWR] functions.

    This is obviously only for debugging and destroys all the protections
    afforded to normal enclaves. But, enclaves know their own debug status and
    can adjust their behavior appropriately.

    Add a vm_ops->access() implementation which can be used to read and write
    memory inside debug enclaves. This is typically used via ptrace() APIs.

    Cc: linux-mm@kvack.org
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Cc: Matthew Wilcox <willy@infradead.org>
    Acked-by: Jethro Beekman <jethro@fortanix.com>
    Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
    ---
    Changes from v39:
    * Check only for SGX_ENCL_DEBUG in sgx_vma_access(), so that a debug
    enclave's memory can read and written at any phase of its life-cycle.

    arch/x86/kernel/cpu/sgx/encl.c | 111 +++++++++++++++++++++++++++++++++
    1 file changed, 111 insertions(+)

    diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c
    index 328d5f61f1cc..5551c7d36483 100644
    --- a/arch/x86/kernel/cpu/sgx/encl.c
    +++ b/arch/x86/kernel/cpu/sgx/encl.c
    @@ -282,10 +282,121 @@ static int sgx_vma_mprotect(struct vm_area_struct *vma,
    return mprotect_fixup(vma, pprev, start, end, newflags);
    }

    +static int sgx_encl_debug_read(struct sgx_encl *encl, struct sgx_encl_page *page,
    + unsigned long addr, void *data)
    +{
    + unsigned long offset = addr & ~PAGE_MASK;
    + int ret;
    +
    +
    + ret = __edbgrd(sgx_get_epc_virt_addr(page->epc_page) + offset, data);
    + if (ret)
    + return -EIO;
    +
    + return 0;
    +}
    +
    +static int sgx_encl_debug_write(struct sgx_encl *encl, struct sgx_encl_page *page,
    + unsigned long addr, void *data)
    +{
    + unsigned long offset = addr & ~PAGE_MASK;
    + int ret;
    +
    + ret = __edbgwr(sgx_get_epc_virt_addr(page->epc_page) + offset, data);
    + if (ret)
    + return -EIO;
    +
    + return 0;
    +}
    +
    +/*
    + * Load an enclave page to EPC if required, and take encl->lock.
    + */
    +static struct sgx_encl_page *sgx_encl_reserve_page(struct sgx_encl *encl,
    + unsigned long addr,
    + unsigned long vm_flags)
    +{
    + struct sgx_encl_page *entry;
    +
    + for ( ; ; ) {
    + mutex_lock(&encl->lock);
    +
    + entry = sgx_encl_load_page(encl, addr, vm_flags);
    + if (PTR_ERR(entry) != -EBUSY)
    + break;
    +
    + mutex_unlock(&encl->lock);
    + }
    +
    + if (IS_ERR(entry))
    + mutex_unlock(&encl->lock);
    +
    + return entry;
    +}
    +
    +static int sgx_vma_access(struct vm_area_struct *vma, unsigned long addr,
    + void *buf, int len, int write)
    +{
    + struct sgx_encl *encl = vma->vm_private_data;
    + struct sgx_encl_page *entry = NULL;
    + char data[sizeof(unsigned long)];
    + unsigned long align;
    + int offset;
    + int cnt;
    + int ret = 0;
    + int i;
    +
    + /*
    + * If process was forked, VMA is still there but vm_private_data is set
    + * to NULL.
    + */
    + if (!encl)
    + return -EFAULT;
    +
    + if (!test_bit(SGX_ENCL_DEBUG, &encl->flags))
    + return -EFAULT;
    +
    + for (i = 0; i < len; i += cnt) {
    + entry = sgx_encl_reserve_page(encl, (addr + i) & PAGE_MASK,
    + vma->vm_flags);
    + if (IS_ERR(entry)) {
    + ret = PTR_ERR(entry);
    + break;
    + }
    +
    + align = ALIGN_DOWN(addr + i, sizeof(unsigned long));
    + offset = (addr + i) & (sizeof(unsigned long) - 1);
    + cnt = sizeof(unsigned long) - offset;
    + cnt = min(cnt, len - i);
    +
    + ret = sgx_encl_debug_read(encl, entry, align, data);
    + if (ret)
    + goto out;
    +
    + if (write) {
    + memcpy(data + offset, buf + i, cnt);
    + ret = sgx_encl_debug_write(encl, entry, align, data);
    + if (ret)
    + goto out;
    + } else {
    + memcpy(buf + i, data + offset, cnt);
    + }
    +
    +out:
    + mutex_unlock(&encl->lock);
    +
    + if (ret)
    + break;
    + }
    +
    + return ret < 0 ? ret : i;
    +}
    +
    const struct vm_operations_struct sgx_vm_ops = {
    .fault = sgx_vma_fault,
    .mprotect = sgx_vma_mprotect,
    .open = sgx_vma_open,
    + .access = sgx_vma_access,
    };

    /**
    --
    2.27.0
    \
     
     \ /
      Last update: 2020-11-04 15:57    [W:4.112 / U:0.228 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site