Skip to content

Commit 35c7e6d

Browse files
rchatrehansendc
authored andcommitted
selftests/sgx: Test invalid access to removed enclave page
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_TYPES 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> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Acked-by: Jarkko Sakkinen <jarkko@kernel.org> Link: https://lkml.kernel.org/r/189a86c25d6d62da7cfdd08ee97abc1a06fcc179.1652137848.git.reinette.chatre@intel.com
1 parent 50b822e commit 35c7e6d

File tree

1 file changed

+243
-0
lines changed
  • tools/testing/selftests/sgx

1 file changed

+243
-0
lines changed

tools/testing/selftests/sgx/main.c

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,4 +1547,247 @@ TEST_F(enclave, remove_added_page_no_eaccept)
15471547
EXPECT_EQ(remove_ioc.count, 0);
15481548
}
15491549

1550+
/*
1551+
* Request enclave page removal but instead of correctly following with
1552+
* EACCEPT a read attempt to page is made from within the enclave.
1553+
*/
1554+
TEST_F(enclave, remove_added_page_invalid_access)
1555+
{
1556+
struct encl_op_get_from_addr get_addr_op;
1557+
struct encl_op_put_to_addr put_addr_op;
1558+
struct sgx_enclave_modify_types ioc;
1559+
unsigned long data_start;
1560+
int ret, errno_save;
1561+
1562+
ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
1563+
1564+
memset(&self->run, 0, sizeof(self->run));
1565+
self->run.tcs = self->encl.encl_base;
1566+
1567+
/*
1568+
* Hardware (SGX2) and kernel support is needed for this test. Start
1569+
* with check that test has a chance of succeeding.
1570+
*/
1571+
memset(&ioc, 0, sizeof(ioc));
1572+
ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);
1573+
1574+
if (ret == -1) {
1575+
if (errno == ENOTTY)
1576+
SKIP(return,
1577+
"Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");
1578+
else if (errno == ENODEV)
1579+
SKIP(return, "System does not support SGX2");
1580+
}
1581+
1582+
/*
1583+
* Invalid parameters were provided during sanity check,
1584+
* expect command to fail.
1585+
*/
1586+
EXPECT_EQ(ret, -1);
1587+
1588+
/*
1589+
* Page that will be removed is the second data page in the .data
1590+
* segment. This forms part of the local encl_buffer within the
1591+
* enclave.
1592+
*/
1593+
data_start = self->encl.encl_base +
1594+
encl_get_data_offset(&self->encl) + PAGE_SIZE;
1595+
1596+
/*
1597+
* Sanity check that page at @data_start is writable before
1598+
* removing it.
1599+
*
1600+
* Start by writing MAGIC to test page.
1601+
*/
1602+
put_addr_op.value = MAGIC;
1603+
put_addr_op.addr = data_start;
1604+
put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
1605+
1606+
EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
1607+
1608+
EXPECT_EEXIT(&self->run);
1609+
EXPECT_EQ(self->run.exception_vector, 0);
1610+
EXPECT_EQ(self->run.exception_error_code, 0);
1611+
EXPECT_EQ(self->run.exception_addr, 0);
1612+
1613+
/*
1614+
* Read memory that was just written to, confirming that data
1615+
* previously written (MAGIC) is present.
1616+
*/
1617+
get_addr_op.value = 0;
1618+
get_addr_op.addr = data_start;
1619+
get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
1620+
1621+
EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1622+
1623+
EXPECT_EQ(get_addr_op.value, MAGIC);
1624+
EXPECT_EEXIT(&self->run);
1625+
EXPECT_EQ(self->run.exception_vector, 0);
1626+
EXPECT_EQ(self->run.exception_error_code, 0);
1627+
EXPECT_EQ(self->run.exception_addr, 0);
1628+
1629+
/* Start page removal by requesting change of page type to PT_TRIM. */
1630+
memset(&ioc, 0, sizeof(ioc));
1631+
1632+
ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;
1633+
ioc.length = PAGE_SIZE;
1634+
ioc.page_type = SGX_PAGE_TYPE_TRIM;
1635+
1636+
ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);
1637+
errno_save = ret == -1 ? errno : 0;
1638+
1639+
EXPECT_EQ(ret, 0);
1640+
EXPECT_EQ(errno_save, 0);
1641+
EXPECT_EQ(ioc.result, 0);
1642+
EXPECT_EQ(ioc.count, 4096);
1643+
1644+
/*
1645+
* Read from page that was just removed.
1646+
*/
1647+
get_addr_op.value = 0;
1648+
1649+
EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1650+
1651+
/*
1652+
* From kernel perspective the page is present but according to SGX the
1653+
* page should not be accessible so a #PF with SGX bit set is
1654+
* expected.
1655+
*/
1656+
1657+
EXPECT_EQ(self->run.function, ERESUME);
1658+
EXPECT_EQ(self->run.exception_vector, 14);
1659+
EXPECT_EQ(self->run.exception_error_code, 0x8005);
1660+
EXPECT_EQ(self->run.exception_addr, data_start);
1661+
}
1662+
1663+
/*
1664+
* Request enclave page removal and correctly follow with
1665+
* EACCEPT but do not follow with removal ioctl() but instead a read attempt
1666+
* to removed page is made from within the enclave.
1667+
*/
1668+
TEST_F(enclave, remove_added_page_invalid_access_after_eaccept)
1669+
{
1670+
struct encl_op_get_from_addr get_addr_op;
1671+
struct encl_op_put_to_addr put_addr_op;
1672+
struct sgx_enclave_modify_types ioc;
1673+
struct encl_op_eaccept eaccept_op;
1674+
unsigned long data_start;
1675+
int ret, errno_save;
1676+
1677+
ASSERT_TRUE(setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata));
1678+
1679+
memset(&self->run, 0, sizeof(self->run));
1680+
self->run.tcs = self->encl.encl_base;
1681+
1682+
/*
1683+
* Hardware (SGX2) and kernel support is needed for this test. Start
1684+
* with check that test has a chance of succeeding.
1685+
*/
1686+
memset(&ioc, 0, sizeof(ioc));
1687+
ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);
1688+
1689+
if (ret == -1) {
1690+
if (errno == ENOTTY)
1691+
SKIP(return,
1692+
"Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()");
1693+
else if (errno == ENODEV)
1694+
SKIP(return, "System does not support SGX2");
1695+
}
1696+
1697+
/*
1698+
* Invalid parameters were provided during sanity check,
1699+
* expect command to fail.
1700+
*/
1701+
EXPECT_EQ(ret, -1);
1702+
1703+
/*
1704+
* Page that will be removed is the second data page in the .data
1705+
* segment. This forms part of the local encl_buffer within the
1706+
* enclave.
1707+
*/
1708+
data_start = self->encl.encl_base +
1709+
encl_get_data_offset(&self->encl) + PAGE_SIZE;
1710+
1711+
/*
1712+
* Sanity check that page at @data_start is writable before
1713+
* removing it.
1714+
*
1715+
* Start by writing MAGIC to test page.
1716+
*/
1717+
put_addr_op.value = MAGIC;
1718+
put_addr_op.addr = data_start;
1719+
put_addr_op.header.type = ENCL_OP_PUT_TO_ADDRESS;
1720+
1721+
EXPECT_EQ(ENCL_CALL(&put_addr_op, &self->run, true), 0);
1722+
1723+
EXPECT_EEXIT(&self->run);
1724+
EXPECT_EQ(self->run.exception_vector, 0);
1725+
EXPECT_EQ(self->run.exception_error_code, 0);
1726+
EXPECT_EQ(self->run.exception_addr, 0);
1727+
1728+
/*
1729+
* Read memory that was just written to, confirming that data
1730+
* previously written (MAGIC) is present.
1731+
*/
1732+
get_addr_op.value = 0;
1733+
get_addr_op.addr = data_start;
1734+
get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS;
1735+
1736+
EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1737+
1738+
EXPECT_EQ(get_addr_op.value, MAGIC);
1739+
EXPECT_EEXIT(&self->run);
1740+
EXPECT_EQ(self->run.exception_vector, 0);
1741+
EXPECT_EQ(self->run.exception_error_code, 0);
1742+
EXPECT_EQ(self->run.exception_addr, 0);
1743+
1744+
/* Start page removal by requesting change of page type to PT_TRIM. */
1745+
memset(&ioc, 0, sizeof(ioc));
1746+
1747+
ioc.offset = encl_get_data_offset(&self->encl) + PAGE_SIZE;
1748+
ioc.length = PAGE_SIZE;
1749+
ioc.page_type = SGX_PAGE_TYPE_TRIM;
1750+
1751+
ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &ioc);
1752+
errno_save = ret == -1 ? errno : 0;
1753+
1754+
EXPECT_EQ(ret, 0);
1755+
EXPECT_EQ(errno_save, 0);
1756+
EXPECT_EQ(ioc.result, 0);
1757+
EXPECT_EQ(ioc.count, 4096);
1758+
1759+
eaccept_op.epc_addr = (unsigned long)data_start;
1760+
eaccept_op.ret = 0;
1761+
eaccept_op.flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED;
1762+
eaccept_op.header.type = ENCL_OP_EACCEPT;
1763+
1764+
EXPECT_EQ(ENCL_CALL(&eaccept_op, &self->run, true), 0);
1765+
1766+
EXPECT_EEXIT(&self->run);
1767+
EXPECT_EQ(self->run.exception_vector, 0);
1768+
EXPECT_EQ(self->run.exception_error_code, 0);
1769+
EXPECT_EQ(self->run.exception_addr, 0);
1770+
EXPECT_EQ(eaccept_op.ret, 0);
1771+
1772+
/* Skip ioctl() to remove page. */
1773+
1774+
/*
1775+
* Read from page that was just removed.
1776+
*/
1777+
get_addr_op.value = 0;
1778+
1779+
EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, true), 0);
1780+
1781+
/*
1782+
* From kernel perspective the page is present but according to SGX the
1783+
* page should not be accessible so a #PF with SGX bit set is
1784+
* expected.
1785+
*/
1786+
1787+
EXPECT_EQ(self->run.function, ERESUME);
1788+
EXPECT_EQ(self->run.exception_vector, 14);
1789+
EXPECT_EQ(self->run.exception_error_code, 0x8005);
1790+
EXPECT_EQ(self->run.exception_addr, data_start);
1791+
}
1792+
15501793
TEST_HARNESS_MAIN

0 commit comments

Comments
 (0)