diff options
author | Olivier Deprez <olivier.deprez@arm.com> | 2021-04-22 14:39:54 +0200 |
---|---|---|
committer | Olivier Deprez <olivier.deprez@arm.com> | 2022-03-01 18:51:43 +0100 |
commit | 20b9b1784f209811a05db71f8503980c97f4634a (patch) | |
tree | 8c5da473df4f3cab66eeb9c12ed7c45f62a7d635 | |
parent | 572ee4fde07faf8c208ebfd1bcaf745a93db003d (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.h | 2 | ||||
-rw-r--r-- | spm/cactus/aarch64/cactus_exceptions.S | 27 | ||||
-rw-r--r-- | spm/cactus/cactus.mk | 1 | ||||
-rw-r--r-- | spm/cactus/cactus_main.c | 7 | ||||
-rw-r--r-- | spm/cactus/cactus_tests/cactus_test_memory_sharing.c | 32 | ||||
-rw-r--r-- | tftf/tests/runtime_services/secure_service/spm_common.c | 2 | ||||
-rw-r--r-- | tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c | 107 | ||||
-rw-r--r-- | tftf/tests/tests-spm.mk | 6 | ||||
-rw-r--r-- | tftf/tests/tests-spm.xml | 8 |
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" > |