lkml.org 
[lkml]   [2021]   [Dec]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 22/25] selftests/sgx: Test invalid access to removed enclave page
    Date
    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_PAGE_MODT 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_PAGE_REMOVE 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_PAGE_REMOVE, 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.

    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 f71f943099fb..3bee8fa557fd 100644
    --- a/tools/testing/selftests/sgx/main.c
    +++ b/tools/testing/selftests/sgx/main.c
    @@ -1606,4 +1606,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;
    + unsigned long data_start;
    + struct sgx_page_modt 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;
    +
    + /*
    + * Hardware (SGX2) and OS 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_PAGE_MODT, &ioc);
    +
    + if (ret == -1) {
    + if (errno == ENOTTY)
    + SKIP(return, "Kernel does not support test SGX_IOC_PAGE_MODT 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. Only change two test
    + * parameters, rest are same as previous test.
    + */
    + 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.type = SGX_PAGE_TYPE_TRIM;
    +
    + ret = ioctl(self->encl.fd, SGX_IOC_PAGE_MODT, &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 OS 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 encl_op_eaccept eaccept_op;
    + unsigned long data_start;
    + struct sgx_page_modt 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;
    +
    + /*
    + * Hardware (SGX2) and OS 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_PAGE_MODT, &ioc);
    +
    + if (ret == -1) {
    + if (errno == ENOTTY)
    + SKIP(return, "Kernel does not support test SGX_IOC_PAGE_MODT 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. Only change two test
    + * parameters, rest are same as previous test.
    + */
    + 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.type = SGX_PAGE_TYPE_TRIM;
    +
    + ret = ioctl(self->encl.fd, SGX_IOC_PAGE_MODT, &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 OS 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.25.1
    \
     
     \ /
      Last update: 2021-12-01 20:25    [W:2.754 / U:0.044 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site