summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Deprez <olivier.deprez@arm.com>2021-04-22 14:39:54 +0200
committerOlivier Deprez <olivier.deprez@arm.com>2022-03-01 18:51:43 +0100
commit20b9b1784f209811a05db71f8503980c97f4634a (patch)
tree8c5da473df4f3cab66eeb9c12ed7c45f62a7d635
parent572ee4fde07faf8c208ebfd1bcaf745a93db003d (diff)
test(cactus): prevent realm region access from swd
This change adds TFTF and cactus tests to check a realm region cannot be accessed from secure world. A non-secure buffer is delegated to realm PAS and shared to a secure partition through FF-A memory sharing operations. The SP retrieves the region from the SPM, maps it and attempts a write access. The PE is expected to trigger a GPF data abort caught by a custom exception handler. Exception is trapped at S-EL1 within the secure partition because Hafnium configures HCR_EL2.GPF=0 (and SCR_EL3.GPF=0). Signed-off-by: Olivier Deprez <olivier.deprez@arm.com> Change-Id: I8f855f394d0490b3584e60ceba4f3d2a20197495
-rw-r--r--include/runtime_services/spm_common.h2
-rw-r--r--spm/cactus/aarch64/cactus_exceptions.S27
-rw-r--r--spm/cactus/cactus.mk1
-rw-r--r--spm/cactus/cactus_main.c7
-rw-r--r--spm/cactus/cactus_tests/cactus_test_memory_sharing.c32
-rw-r--r--tftf/tests/runtime_services/secure_service/spm_common.c2
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c107
-rw-r--r--tftf/tests/tests-spm.mk6
-rw-r--r--tftf/tests/tests-spm.xml8
9 files changed, 171 insertions, 21 deletions
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index 398d01a..f187ed7 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -129,7 +129,7 @@ unsigned int get_ffa_feature_test_target(const struct ffa_features_test **test_t
bool memory_retrieve(struct mailbox_buffers *mb,
struct ffa_memory_region **retrieved, uint64_t handle,
ffa_id_t sender, ffa_id_t receiver,
- uint32_t mem_func, ffa_memory_region_flags_t flags);
+ ffa_memory_region_flags_t flags);
/**
* Helper to conduct a memory relinquish. The caller is usually the receiver,
diff --git a/spm/cactus/aarch64/cactus_exceptions.S b/spm/cactus/aarch64/cactus_exceptions.S
index 6aec16d..9b024f8 100644
--- a/spm/cactus/aarch64/cactus_exceptions.S
+++ b/spm/cactus/aarch64/cactus_exceptions.S
@@ -31,14 +31,16 @@ unhandled_exception serr_sp0
/*
* Current EL with SPx : 0x200 - 0x400.
*/
-unhandled_exception sync_spx
+vector_entry sync_spx
+ b sync_exception_vector_entry
+end_vector_entry sync_spx
vector_entry irq_spx
- b irq_vector_entry
+ b interrupt_vector_entry
end_vector_entry irq_spx
vector_entry fiq_spx
- b fiq_vector_entry
+ b interrupt_vector_entry
end_vector_entry fiq_spx
unhandled_exception serr_spx
@@ -98,23 +100,30 @@ unhandled_exception serr_a32
ldp x0, x1, [sp, #0x0]
.endm
-func irq_vector_entry
+func sync_exception_vector_entry
sub sp, sp, #0x100
save_gp_regs
- bl cactus_interrupt_handler
- restore_gp_regs
+ mov x19, sp
+ bl tftf_sync_exception_handler
+ cbnz x0, 0f
+ mov x0, x19
+ /* Save original stack pointer value on the stack */
+ add x1, x0, #0x100
+ str x1, [x0, #0xf8]
+ b print_exception
+0: restore_gp_regs
add sp, sp, #0x100
eret
-endfunc irq_vector_entry
+endfunc sync_exception_vector_entry
-func fiq_vector_entry
+func interrupt_vector_entry
sub sp, sp, #0x100
save_gp_regs
bl cactus_interrupt_handler
restore_gp_regs
add sp, sp, #0x100
eret
-endfunc fiq_vector_entry
+endfunc interrupt_vector_entry
func crash_dump
/* Save general-purpose registers on the stack. */
diff --git a/spm/cactus/cactus.mk b/spm/cactus/cactus.mk
index 4109579..8970b29 100644
--- a/spm/cactus/cactus.mk
+++ b/spm/cactus/cactus.mk
@@ -68,6 +68,7 @@ CACTUS_SOURCES += drivers/arm/pl011/${ARCH}/pl011_console.S \
lib/smc/${ARCH}/asm_smc.S \
lib/smc/${ARCH}/smc.c \
lib/smc/${ARCH}/hvc.c \
+ lib/exceptions/${ARCH}/sync.c \
lib/locks/${ARCH}/spinlock.S \
lib/utils/mp_printf.c \
${XLAT_TABLES_LIB_SRCS}
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index c80abd9..58186d1 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -181,13 +181,6 @@ static void register_secondary_entrypoint(void)
tftf_smc(&args);
}
-int tftf_irq_handler_dispatcher(void)
-{
- ERROR("%s\n", __func__);
-
- return 0;
-}
-
void __dead2 cactus_main(bool primary_cold_boot)
{
assert(IS_IN_EL1() != 0);
diff --git a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
index 69d62dd..051208e 100644
--- a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
+++ b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
@@ -14,6 +14,27 @@
#include <sp_helpers.h>
#include <xlat_tables_defs.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <sync.h>
+
+static volatile uint32_t data_abort_gpf_triggered;
+
+static bool data_abort_gpf_handler(void)
+{
+ uint64_t esr_el1 = read_esr_el1();
+
+ VERBOSE("%s count %u esr_el1 %llx elr_el1 %llx\n",
+ __func__, data_abort_gpf_triggered, esr_el1,
+ read_elr_el1());
+
+ /* Expect a data abort because of a GPF. */
+ if ((EC_BITS(esr_el1) == EC_DABORT_CUR_EL) &&
+ ((ISS_BITS(esr_el1) & ISS_DFSC_MASK) == DFSC_GPF_DABORT)) {
+ data_abort_gpf_triggered++;
+ return true;
+ }
+
+ return false;
+}
/**
* Each Cactus SP has a memory region dedicated to memory sharing tests
@@ -51,7 +72,7 @@ CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
cactus_mem_send_get_retrv_flags(*args);
uint32_t words_to_write = cactus_mem_send_words_to_write(*args);
- expect(memory_retrieve(mb, &m, handle, source, vm_id, mem_func,
+ expect(memory_retrieve(mb, &m, handle, source, vm_id,
retrv_flags), true);
composite = ffa_memory_region_get_composite(m, 0);
@@ -104,12 +125,17 @@ CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
}
}
+ data_abort_gpf_triggered = 0;
+ register_custom_sync_exception_handler(data_abort_gpf_handler);
+
/* Write mem_func to retrieved memory region for validation purposes. */
VERBOSE("Writing: %x\n", mem_func);
for (unsigned int i = 0U; i < words_to_write; i++) {
ptr[i] = mem_func;
}
+ unregister_custom_sync_exception_handler();
+
/*
* A FFA_MEM_DONATE changes the ownership of the page, as such no
* relinquish is needed.
@@ -120,7 +146,7 @@ CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
composite->constituents[0].page_count * PAGE_SIZE);
if (ret != 0) {
- ERROR("Failed first mmap_add_dynamic_region!\n");
+ ERROR("Failed to unmap received memory region(%d)!\n", ret);
return cactus_error_resp(vm_id, source,
CACTUS_ERROR_TEST);
}
@@ -139,7 +165,7 @@ CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
}
return cactus_success_resp(vm_id,
- source, 0);
+ source, data_abort_gpf_triggered);
}
CACTUS_CMD_HANDLER(req_mem_send_cmd, CACTUS_REQ_MEM_SEND_CMD)
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index aa1d2ed..fa4d1bc 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -351,7 +351,7 @@ unsigned int get_ffa_feature_test_target(
bool memory_retrieve(struct mailbox_buffers *mb,
struct ffa_memory_region **retrieved, uint64_t handle,
ffa_id_t sender, ffa_id_t receiver,
- uint32_t mem_func, ffa_memory_region_flags_t flags)
+ ffa_memory_region_flags_t flags)
{
smc_ret_values ret;
uint32_t fragment_size;
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
new file mode 100644
index 0000000..f68a527
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <cactus_test_cmds.h>
+#include <debug.h>
+#include <ffa_endpoints.h>
+#include <ffa_svc.h>
+#include <irq.h>
+#include <platform.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+#include <smccc.h>
+#include <spm_common.h>
+#include <test_helpers.h>
+
+#define SENDER HYP_ID
+#define RECEIVER SP_ID(1)
+
+static __aligned(PAGE_SIZE) uint64_t share_page[PAGE_SIZE / sizeof(uint64_t)];
+
+static const struct ffa_uuid expected_sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+};
+
+/**
+ * @Test_Aim@ Check a realm region cannot be accessed from a secure partition.
+ *
+ * This test shares a TFTF allocated buffer with a secure partition through
+ * FF-A memory sharing operation. The buffer is initially marked NS in the GPT
+ * and transitioned to realm after sharing. Then, the SP is invoked to retrieve
+ * the region (map it to its S2 translation regime), and maps it to its secure
+ * S1 translation regime. It then attempts a read access which results in the
+ * PE triggering a GPF caught by a custom synchronous abort handler.
+ *
+ */
+test_result_t rl_memory_cannot_be_accessed_in_s(void)
+{
+ struct ffa_memory_region_constituent constituents[] = {
+ {
+ (void *)share_page, 1, 0
+ }
+ };
+ const uint32_t constituents_count = sizeof(constituents) /
+ sizeof(struct ffa_memory_region_constituent);
+ ffa_memory_handle_t handle;
+ struct mailbox_buffers mb;
+ smc_ret_values ret;
+ u_register_t retmm;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ handle = memory_init_and_send((struct ffa_memory_region *)mb.send,
+ PAGE_SIZE, SENDER, RECEIVER,
+ constituents, constituents_count,
+ FFA_MEM_SHARE_SMC32, &ret);
+
+ if (handle == FFA_MEMORY_HANDLE_INVALID) {
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("TFTF - Handle: %llx Address: %p\n",
+ handle, constituents[0].address);
+
+ /* Delegate the shared page to Realm. */
+ retmm = realm_granule_delegate((u_register_t)&share_page);
+ if (retmm != 0UL) {
+ ERROR("Granule delegate failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Retrieve the shared page and attempt accessing it. */
+ ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_SHARE_SMC32,
+ handle, 0, 1);
+
+ /* Undelegate the shared page. */
+ retmm = realm_granule_undelegate((u_register_t)&share_page);
+ if (retmm != 0UL) {
+ ERROR("Granule undelegate failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ if (is_ffa_call_error(ffa_mem_reclaim(handle, 0))) {
+ ERROR("Memory reclaim failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Expect success response with value 1 hinting an exception
+ * triggered while the SP accessed the region.
+ */
+ if (!(cactus_get_response(ret) == CACTUS_SUCCESS &&
+ cactus_error_code(ret) == 1)) {
+ ERROR("Exceptions test failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-spm.mk b/tftf/tests/tests-spm.mk
index 79cfb61..941758c 100644
--- a/tftf/tests/tests-spm.mk
+++ b/tftf/tests/tests-spm.mk
@@ -16,4 +16,10 @@ TESTS_SOURCES += \
test_ffa_notifications.c \
test_spm_cpu_features.c \
test_spm_smmu.c \
+ test_ffa_exceptions.c \
+ )
+
+TESTS_SOURCES += \
+ $(addprefix tftf/tests/runtime_services/realm_payload/, \
+ realm_payload_test_helpers.c \
)
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index cc79ea0..9a78c8a 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -44,6 +44,14 @@
function="test_ffa_partition_info" />
</testsuite>
+ <testsuite name="SP exceptions"
+ description="SP exceptions" >
+
+ <testcase name="Access from a SP to a Realm region"
+ function="rl_memory_cannot_be_accessed_in_s" />
+
+ </testsuite>
+
<testsuite name="FF-A Direct messaging"
description="Test FF-A Direct messaging" >