Make the test enclave aware of its protected virtual address range to allow untrusted pointer argument range checks. Add a linker symbol for __enclave_base at the start of the enclave binary. Similar to real-world enclave runtimes, rely on the untrusted loader to fill in __enclave_size (measured as part of MRENCLAVE), as the final size of the enclave image is determined during loading. Signed-off-by: Jo Van Bulck <jo.vanbulck@xxxxxxxxxxxxxx> --- tools/testing/selftests/sgx/load.c | 3 +- tools/testing/selftests/sgx/main.c | 29 +++++++++++++++++++ tools/testing/selftests/sgx/test_encl.lds | 1 + .../selftests/sgx/test_encl_bootstrap.S | 17 +++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/sgx/load.c b/tools/testing/selftests/sgx/load.c index 94bdeac1c..968a656a3 100644 --- a/tools/testing/selftests/sgx/load.c +++ b/tools/testing/selftests/sgx/load.c @@ -60,7 +60,8 @@ static bool encl_map_bin(const char *path, struct encl *encl) goto err; } - bin = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + /* NOTE: map read|write to allow __enclave_size to be filled in */ + bin = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (bin == MAP_FAILED) { perror("enclave executable mmap()"); goto err; diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c index d3c7a39f4..bad963c79 100644 --- a/tools/testing/selftests/sgx/main.c +++ b/tools/testing/selftests/sgx/main.c @@ -182,6 +182,7 @@ static bool setup_test_encl(unsigned long heap_size, struct encl *encl, FILE *maps_file; unsigned int i; void *addr; + uint64_t encl_size_addr; if (!encl_load("test_encl.elf", encl, heap_size)) { encl_delete(encl); @@ -189,6 +190,16 @@ static bool setup_test_encl(unsigned long heap_size, struct encl *encl, return false; } + /* + * Fill in the expected symbol location with the final size of the + * constructed enclave image. + */ + encl_size_addr = encl_get_entry(encl, "__enclave_size"); + if (encl_size_addr) { + encl_size_addr += (uint64_t) encl->src; + *((uint64_t *) encl_size_addr) = encl->encl_size; + } + if (!encl_measure(encl)) goto err; @@ -307,6 +318,24 @@ TEST_F(enclave, unclobbered_vdso) EXPECT_EQ(self->run.user_data, 0); } +TEST_F(enclave, init_size) +{ + struct encl_op_get_from_addr get_addr_op; + + 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; + + /* __enclave_size is initialized by loader in measured enclave image */ + get_addr_op.value = 0; + get_addr_op.addr = self->encl.encl_base + encl_get_entry(&self->encl, "__enclave_size"); + get_addr_op.header.type = ENCL_OP_GET_FROM_ADDRESS; + EXPECT_EQ(ENCL_CALL(&get_addr_op, &self->run, false), 0); + EXPECT_EEXIT(&self->run); + EXPECT_EQ(get_addr_op.value, self->encl.encl_size); +} + TEST_F(enclave, poison_args) { struct encl_op_header nop_op; diff --git a/tools/testing/selftests/sgx/test_encl.lds b/tools/testing/selftests/sgx/test_encl.lds index a1ec64f7d..ca659db2a 100644 --- a/tools/testing/selftests/sgx/test_encl.lds +++ b/tools/testing/selftests/sgx/test_encl.lds @@ -10,6 +10,7 @@ PHDRS SECTIONS { . = 0; + __enclave_base = .; .tcs : { *(.tcs*) } : tcs diff --git a/tools/testing/selftests/sgx/test_encl_bootstrap.S b/tools/testing/selftests/sgx/test_encl_bootstrap.S index 3b69fea61..444a075c0 100644 --- a/tools/testing/selftests/sgx/test_encl_bootstrap.S +++ b/tools/testing/selftests/sgx/test_encl_bootstrap.S @@ -98,6 +98,23 @@ encl_entry_core: mov $4, %rax enclu + .global get_enclave_base +get_enclave_base: + lea __enclave_base(%rip), %rax + ret + + .global get_enclave_size +get_enclave_size: + mov __enclave_size(%rip), %rax + ret + + # The following 8 bytes (measured as part of MRENCLAVE) will be + # filled in by the untrusted loader with the total size of the + # loaded enclave. + .global __enclave_size +__enclave_size: + .quad 0x0 + .section ".data", "aw" encl_ssa_tcs1: -- 2.34.1