lkml.org 
[lkml]   [2022]   [Mar]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC PATCH v2.1 27/30] selftests/sgx: Test invalid access to removed enclave page
    Date
    From: Reinette Chatre <reinette.chatre@intel.com>

    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_TYPE 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.

    Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
    ---
    tools/testing/selftests/sgx/main.c | 247 +++++++++++++++++++++++++++++
    1 file changed, 247 insertions(+)

    diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c
    index 82902dab96bc..d132e7d32454 100644
    --- a/tools/testing/selftests/sgx/main.c
    +++ b/tools/testing/selftests/sgx/main.c
    @@ -1569,4 +1569,251 @@ 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_modt ioc;
    + struct sgx_secinfo secinfo;
    + 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_TYPE, &ioc);
    +
    + if (ret == -1) {
    + if (errno == ENOTTY)
    + SKIP(return, "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPE 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));
    + memset(&secinfo, 0, sizeof(secinfo));
    +
    + secinfo.flags = SGX_PAGE_TYPE_TRIM << 8;
    + ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;
    + ioc.length = PAGE_SIZE;
    + ioc.secinfo = (unsigned long)&secinfo;
    +
    + ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPE, &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 encl_op_eaccept eaccept_op;
    + struct sgx_enclave_modt ioc;
    + struct sgx_secinfo secinfo;
    + 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_TYPE, &ioc);
    +
    + if (ret == -1) {
    + if (errno == ENOTTY)
    + SKIP(return, "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPE 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));
    + memset(&secinfo, 0, sizeof(secinfo));
    +
    + secinfo.flags = SGX_PAGE_TYPE_TRIM << 8;
    + ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;
    + ioc.length = PAGE_SIZE;
    + ioc.secinfo = (unsigned long)&secinfo;
    +
    + ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPE, &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.35.1
    \
     
     \ /
      Last update: 2022-03-04 10:39    [W:4.252 / U:0.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site