diff options
-rw-r--r-- | docs/components/secure-partition-manager.rst | 62 | ||||
-rw-r--r-- | docs/threat_model/threat_model_spm.rst | 186 | ||||
-rw-r--r-- | plat/arm/board/tc/include/tc_plat.h | 5 | ||||
-rw-r--r-- | plat/arm/board/tc/nv_counter_test.c | 14 | ||||
-rw-r--r-- | plat/arm/board/tc/platform.mk | 38 | ||||
-rw-r--r-- | plat/arm/board/tc/rss_ap_tests.c | 35 | ||||
-rw-r--r-- | plat/arm/board/tc/tc_bl31_setup.c | 28 |
7 files changed, 326 insertions, 42 deletions
diff --git a/docs/components/secure-partition-manager.rst b/docs/components/secure-partition-manager.rst index 8dc1c6136..dbbae61cc 100644 --- a/docs/components/secure-partition-manager.rst +++ b/docs/components/secure-partition-manager.rst @@ -1029,6 +1029,68 @@ permits SPMD to SPMC communication and either way. This is used in particular to convey power management messages. +Memory Sharing +-------------- + +Hafnium implements the following memory sharing interfaces: + + - ``FFA_MEM_SHARE`` - for shared access between lender and borrower. + - ``FFA_MEM_LEND`` - borrower to obtain exclusive access, though lender + retains ownership of the memory. + - ``FFA_MEM_DONATE`` - lender permanently relinquishes ownership of memory + to the borrower. + +The ``FFA_MEM_RETRIEVE_REQ`` interface is for the borrower to request the +memory to be mapped into its address space: for S-EL1 partitions the SPM updates +their stage 2 translation regime; for S-EL0 partitions the SPM updates their +stage 1 translation regime. On a successful call, the SPMC responds back with +``FFA_MEM_RETRIEVE_RESP``. + +The ``FFA_MEM_RELINQUISH`` interface is for when the borrower is done with using +a memory region. + +The ``FFA_MEM_RECLAIM`` interface is for the owner of the memory to reestablish +its ownership and exclusive access to the memory shared. + +The memory transaction descriptors are transmitted via RX/TX buffers. In +situations where the size of the memory transaction descriptor exceeds the +size of the RX/TX buffers, Hafnium provides support for fragmented transmission +of the full transaction descriptor. The ``FFA_MEM_FRAG_RX`` and ``FFA_MEM_FRAG_TX`` +interfaces are for receiving and transmitting the next fragment, respectively. + +If lender and borrower(s) are SPs, all memory sharing operations are supported. + +Hafnium also supports memory sharing operations between the normal world and the +secure world. If there is an SP involved, the SPMC allocates data to track the +state of the operation. + +The SPMC is also the designated allocator for the memory handle. The hypervisor +or OS kernel has the possibility to rely on the SPMC to maintain the state +of the operation, thus saving memory. +A lender SP can only donate NS memory to a borrower from the normal world. + +The SPMC supports the hypervisor retrieve request, as defined by the FF-A +v1.1 EAC0 specification, in section 16.4.3. The intent is to aid with operations +that the hypervisor must do for a VM retriever. For example, when handling +an FFA_MEM_RECLAIM, if the hypervisor relies on SPMC to keep the state +of the operation, the hypervisor retrieve request can be used to obtain +that state information, do the necessary validations, and update stage 2 +memory translation. + +Hafnium also supports memory lend and share targetting multiple borrowers. +This is the case for a lender SP to multiple SPs, and for a lender VM to +multiple endpoints (from both secure world and normal world). If there is +at least one borrower VM, the hypervisor is in charge of managing its +stage 2 translation on a successful memory retrieve. +The semantics of ``FFA_MEM_DONATE`` implies ownership transmission, +which should target only one partition. + +The memory share interfaces are backwards compatible with memory transaction +descriptors from FF-A v1.0. These get translated to FF-A v1.1 descriptors for +Hafnium's internal processing of the operation. If the FF-A version of a +borrower is v1.0, Hafnium provides FF-A v1.0 compliant memory transaction +descriptors on memory retrieve response. + PE MMU configuration -------------------- diff --git a/docs/threat_model/threat_model_spm.rst b/docs/threat_model/threat_model_spm.rst index 98dbf768d..9458a9fea 100644 --- a/docs/threat_model/threat_model_spm.rst +++ b/docs/threat_model/threat_model_spm.rst @@ -35,7 +35,7 @@ The scope for this threat model is: - The TF-A implementation for the S-EL2 SPMC based on the Hafnium hypervisor running in the secure world of TrustZone (at S-EL2 exception level). The threat model is not related to the normal world Hypervisor or VMs. - The S-EL1 SPMC solution is not covered. + The S-EL1 and EL3 SPMC solutions are not covered. - The implementation complies with the FF-A v1.0 specification, and a few features of FF-A v1.1 specification. - Secure partitions are statically provisioned at boot time. @@ -235,8 +235,8 @@ element of the data flow diagram. +------------------------+------------------+-----------------+---------------+ | ``Total Risk Rating`` | High (16) | High (16) | | +------------------------+------------------+-----------------+---------------+ -| ``Mitigations`` | In context of FF-A v1.0 this is the case of sharing| -| | the RX/TX buffer pair and usage in the | +| ``Mitigations`` | In context of FF-A v1.0 and v1.1 this is the case | +| | of sharing the RX/TX buffer pair and usage in the | | | PARTITION_INFO_GET or mem sharing primitives. | | | The SPMC must copy the contents of the TX buffer | | | to an internal temporary buffer before processing | @@ -1151,11 +1151,189 @@ element of the data flow diagram. | | interrupted. | +------------------------+----------------------------------------------------+ ++------------------------+----------------------------------------------------+ +| ID | 25 | ++========================+====================================================+ +| ``Threat`` | **A rogue FF-A endpoint can use memory sharing | +| | calls to exhaust SPMC resources.** | +| | For each on-going operation that involves an SP, | +| | the SPMC allocates resources to track its state. | +| | If the operation is never concluded, the resources | +| | are never freed. | +| | In the worst scenario, multiple operations that | +| | never conclude may exhaust the SPMC resources to a | +| | point in which renders memory sharing operations | +| | impossible. This could affect other, non-harmful | +| | FF-A endpoints, from legitimately using memory | +| | share functionality. The intent might even be | +| | to cause the SPMC to consume excessive CPU cycles, | +| | attempting to make it deny its service to the NWd. | ++------------------------+----------------------------------------------------+ +| ``Diagram Elements`` | DF1, DF2 | ++------------------------+----------------------------------------------------+ +| ``Affected TF-A | SPMC, SPMD | +| Components`` | | ++------------------------+----------------------------------------------------+ +| ``Assets`` | SPMC state | ++------------------------+----------------------------------------------------+ +| ``Threat Agent`` | NS-Endpoint, S-Endpoint | ++------------------------+----------------------------------------------------+ +| ``Threat Type`` | Denial of Service | ++------------------------+------------------+-----------------+---------------+ +| ``Application`` | ``Server`` | ``Mobile`` | | ++------------------------+------------------+-----------------+---------------+ +| ``Impact`` | High (4) | Medium (3) | | ++------------------------+------------------+-----------------+---------------+ +| ``Likelihood`` | High (4) | Medium (3) | | ++------------------------+------------------+-----------------+---------------+ +| ``Total Risk Rating`` | High (16) | Medium (9) | | ++------------------------+------------------+-----------------+---------------+ +| ``Mitigations`` | The TF-A SPMC uses a statically allocated pool of | +| | memory to keep track of on-going memory sharing | +| | operations. After a possible attack, this could | +| | fail due to insufficient memory, and return an | +| | error to the caller. At this point, any other | +| | endpoint that requires use of memory sharing for | +| | its operation could get itself in an unusable | +| | state. | +| | Regarding CPU cycles starving threat, the SPMC | +| | doesn't provide any mitigation for this, as any | +| | FF-A endpoint, at the virtual FF-A instance is | +| | allowed to invoke memory share/lend/donate. | ++------------------------+----------------------------------------------------+ + ++------------------------+----------------------------------------------------+ +| ID | 26 | ++========================+====================================================+ +| ``Threat`` | **A borrower may interfere with lender's | +| | operation, if it terminates due to a fatal error | +| | condition without releasing the memory | +| | shared/lent.** | +| | Such scenario may render the lender inoperable. | ++------------------------+----------------------------------------------------+ +| ``Diagram Elements`` | DF1, DF2 | ++------------------------+----------------------------------------------------+ +| ``Affected TF-A | SPMC | +| Components`` | | ++------------------------+----------------------------------------------------+ +| ``Assets`` | SP state | ++------------------------+----------------------------------------------------+ +| ``Threat Agent`` | NS-Endpoint, S-Endpoint | ++------------------------+----------------------------------------------------+ +| ``Threat Type`` | Denial of Service | ++------------------------+------------------+-----------------+---------------+ +| ``Application`` | ``Server`` | ``Mobile`` | | ++------------------------+------------------+-----------------+---------------+ +| ``Impact`` | High (4) | Low (2) | | ++------------------------+------------------+-----------------+---------------+ +| ``Likelihood`` | Medium (3) | Medium (3) | | ++------------------------+------------------+-----------------+---------------+ +| ``Total Risk Rating`` | High (12) | Medium(6) | | ++------------------------+------------------+-----------------+---------------+ +| ``Mitigations`` | The TF-A SPMC does not provide mitigation for such | +| | scenario. The FF-A endpoints must attempt to | +| | relinquish memory shared/lent themselves in | +| | case of failure. The memory used to track the | +| | operation in the SPMC will also remain usuable. | ++------------------------+----------------------------------------------------+ + ++------------------------+----------------------------------------------------+ +| ID | 27 | ++========================+====================================================+ +| ``Threat`` | **A rogue FF-A endpoint may attempt to tamper with | +| | the content of the memory shared/lent, whilst | +| | being accessed by other FF-A endpoints.** | +| | It might attempt to do so: using one of the clear | +| | flags, when either retrieving or relinquishing | +| | access to the memory via the respective FF-A | +| | calls; or directly accessing memory without | +| | respecting the synchronization protocol between | +| | all involved endpoints. | ++------------------------+----------------------------------------------------+ +| ``Diagram Elements`` | DF1, DF2 | ++------------------------+----------------------------------------------------+ +| ``Affected TF-A | SPMC, FF-A endpoint | +| Components`` | | ++------------------------+----------------------------------------------------+ +| ``Assets`` | SP state | ++------------------------+----------------------------------------------------+ +| ``Threat Agent`` | NS-Endpoint, S-Endpoint | ++------------------------+----------------------------------------------------+ +| ``Threat Type`` | Denial of Service, Tampering | ++------------------------+------------------+-----------------+---------------+ +| ``Application`` | ``Server`` | ``Mobile`` | | ++------------------------+------------------+-----------------+---------------+ +| ``Impact`` | Low (2) | Low (2) | | ++------------------------+------------------+-----------------+---------------+ +| ``Likelihood`` | Medium (3) | Medium (3) | | ++------------------------+------------------+-----------------+---------------+ +| ``Total Risk Rating`` | Medium (6) | Medium(6) | | ++------------------------+------------------+-----------------+---------------+ +| ``Mitigations`` | The first case defined in the threat, the TF-A | +| | SPMC mitigates it, by ensuring a memory is cleared | +| | only when all borrowers have relinquished access | +| | to the memory, in a scenario involving multiple | +| | borrowers. Also, if the receiver is granted RO, | +| | permissions, the SPMC will reject any request | +| | to clear memory on behalf of the borrower, by | +| | returning an error to the respective FF-A call. | +| | The second case defined in the threat can't be | +| | mitigated by the SPMC. It is up to the NS/S FF-A | +| | endpoints to establish a robust protocol for using | +| | the shared memory. | ++------------------------+----------------------------------------------------+ + ++------------------------+----------------------------------------------------+ +| ID | 28 | ++========================+====================================================+ +| ``Threat`` | **A rogue FF-A endpoint may attempt to share | +| | memory that is not in its translation regime, or | +| | attempt to specify attributes more permissive than | +| | those it possesses at a given time.** | +| | Both ways could be an attempt for escalating its | +| | privileges. | ++------------------------+----------------------------------------------------+ +| ``Diagram Elements`` | DF1, DF2 | ++------------------------+----------------------------------------------------+ +| ``Affected TF-A | SPMC, FF-A endpoint | +| Components`` | | ++------------------------+----------------------------------------------------+ +| ``Assets`` | SP state | ++------------------------+----------------------------------------------------+ +| ``Threat Agent`` | NS-Endpoint, S-Endpoint | ++------------------------+----------------------------------------------------+ +| ``Threat Type`` | Denial of Service, Tampering | ++------------------------+------------------+-----------------+---------------+ +| ``Application`` | ``Server`` | ``Mobile`` | | ++------------------------+------------------+-----------------+---------------+ +| ``Impact`` | High (4) | Low (2) | | ++------------------------+------------------+-----------------+---------------+ +| ``Likelihood`` | Medium (3) | Low (2) | | ++------------------------+------------------+-----------------+---------------+ +| ``Total Risk Rating`` | High (12) | Low (2) | | ++------------------------+------------------+-----------------+---------------+ +| ``Mitigations`` | The TF-A SPMC mitigates this threat by performing | +| | sanity checks to the provided memory region | +| | descriptor. | +| | For operations at the virtual FF-A instance, and | +| | once the full memory descriptor is provided, | +| | the SPMC validates that the memory is part of the | +| | caller's translation regime. The SPMC also checks | +| | that the memory attributes provided are within | +| | those the owner possesses, in terms of | +| | permissiveness. If more permissive attributes are | +| | specified, the SPMC returns an error | +| | FFA_INVALID_PARAMETERS. The permissiveness rules | +| | are enforced in any call to share/lend or donate | +| | the memory, and in retrieve requests. | ++------------------------+----------------------------------------------------+ + -------------- -*Copyright (c) 2021-2022, Arm Limited. All rights reserved.* +*Copyright (c) 2021-2023, Arm Limited. All rights reserved.* .. _Arm Firmware Framework for Arm A-profile: https://developer.arm.com/docs/den0077/latest .. _Secure Partition Manager: ../components/secure-partition-manager.html .. _Generic TF-A threat model: ./threat_model.html#threat-analysis .. _FF-A ACS: https://github.com/ARM-software/ff-a-acs/releases + diff --git a/plat/arm/board/tc/include/tc_plat.h b/plat/arm/board/tc/include/tc_plat.h index 195366e48..117fbb430 100644 --- a/plat/arm/board/tc/include/tc_plat.h +++ b/plat/arm/board/tc/include/tc_plat.h @@ -10,10 +10,11 @@ void tc_bl31_common_platform_setup(void); #ifdef PLATFORM_TEST_TFM_TESTSUITE -void run_platform_tests(void); +int run_platform_tests(void); #endif + #ifdef PLATFORM_TEST_NV_COUNTERS -void nv_counter_test(void); +int nv_counter_test(void); #endif #endif /* TC_PLAT_H */ diff --git a/plat/arm/board/tc/nv_counter_test.c b/plat/arm/board/tc/nv_counter_test.c index 76c99159a..f9e001ea8 100644 --- a/plat/arm/board/tc/nv_counter_test.c +++ b/plat/arm/board/tc/nv_counter_test.c @@ -13,7 +13,7 @@ #include <platform_def.h> -void nv_counter_test(void) +int nv_counter_test(void) { psa_status_t status; uint32_t old_val; @@ -23,7 +23,7 @@ void nv_counter_test(void) status = rss_comms_init(PLAT_RSS_AP_SND_MHU_BASE, PLAT_RSS_AP_RCV_MHU_BASE); if (status != PSA_SUCCESS) { printf("Failed to initialize RSS communication channel\n"); - plat_error_handler(-1); + return -1; } for (id = 0; id < 3; id++) { @@ -31,28 +31,30 @@ void nv_counter_test(void) if (status != PSA_SUCCESS) { printf("Failed during first id=(%d) rss_platform_nv_counter_read\n", id); - plat_error_handler(-1); + return -1; } status = rss_platform_nv_counter_increment(id); if (status != PSA_SUCCESS) { printf("Failed during id=(%d) rss_platform_nv_counter_increment\n", id); - plat_error_handler(-1); + return -1; } status = rss_platform_nv_counter_read(id, sizeof(new_val), (uint8_t *)&new_val); if (status != PSA_SUCCESS) { printf("Failed during second id=(%d) rss_platform_nv_counter_read\n", id); - plat_error_handler(-1); + return -1; } if (old_val + 1 != new_val) { printf("Failed nv_counter_test: old_val (%d) + 1 != new_val (%d)\n", old_val, new_val); - plat_error_handler(-1); + return -1; } } printf("Passed nv_counter_test\n"); + + return 0; } diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk index 98c2e0ed6..c29537c7e 100644 --- a/plat/arm/board/tc/platform.mk +++ b/plat/arm/board/tc/platform.mk @@ -196,28 +196,32 @@ PLAT_INCLUDES += -Iinclude/lib/psa endif -ifeq (${PLATFORM_TEST},rss-nv-counters) - include drivers/arm/rss/rss_comms.mk +ifneq (${PLATFORM_TEST},) + $(eval $(call add_define,PLATFORM_TESTS)) + + ifeq (${PLATFORM_TEST},rss-nv-counters) + include drivers/arm/rss/rss_comms.mk - # Test code. - BL31_SOURCES += plat/arm/board/tc/nv_counter_test.c + # Test code. + BL31_SOURCES += plat/arm/board/tc/nv_counter_test.c - # Code under testing. - BL31_SOURCES += lib/psa/rss_platform.c \ + # Code under testing. + BL31_SOURCES += lib/psa/rss_platform.c \ drivers/arm/rss/rss_comms.c \ ${RSS_COMMS_SOURCES} - PLAT_INCLUDES += -Iinclude/lib/psa - - $(eval $(call add_define,PLATFORM_TEST_NV_COUNTERS)) -else ifeq (${PLATFORM_TEST},tfm-testsuite) - # Add this include as first, before arm_common.mk. This is necessary - # because arm_common.mk builds Mbed TLS, and platform_test.mk can - # change the list of Mbed TLS files that are to be compiled - # (LIBMBEDTLS_SRCS). - include plat/arm/board/tc/platform_test.mk -else ifneq (${PLATFORM_TEST},) - $(error "Unsupported PLATFORM_TEST value") + PLAT_INCLUDES += -Iinclude/lib/psa + + $(eval $(call add_define,PLATFORM_TEST_NV_COUNTERS)) + else ifeq (${PLATFORM_TEST},tfm-testsuite) + # Add this include as first, before arm_common.mk. This is necessary + # because arm_common.mk builds Mbed TLS, and platform_test.mk can + # change the list of Mbed TLS files that are to be compiled + # (LIBMBEDTLS_SRCS). + include plat/arm/board/tc/platform_test.mk + else + $(error "Unsupported PLATFORM_TEST value") + endif endif diff --git a/plat/arm/board/tc/rss_ap_tests.c b/plat/arm/board/tc/rss_ap_tests.c index b62043ece..8c40271ba 100644 --- a/plat/arm/board/tc/rss_ap_tests.c +++ b/plat/arm/board/tc/rss_ap_tests.c @@ -19,21 +19,28 @@ static struct test_suite_t test_suites[] = { {.freg = register_testsuite_measured_boot}, }; -static void run_tests(void) +/* + * Return 0 if we could run all tests. + * Note that this does not mean that all tests passed - only that they all run. + * One should then look at each individual test result inside the + * test_suites[].val field. + */ +static int run_tests(void) { enum test_suite_err_t ret; psa_status_t status; size_t i; + /* Initialize test environment. */ rss_comms_init(PLAT_RSS_AP_SND_MHU_BASE, PLAT_RSS_AP_RCV_MHU_BASE); mbedtls_init(); status = psa_crypto_init(); if (status != PSA_SUCCESS) { printf("\n\npsa_crypto_init failed (status = %d)\n", status); - assert(false); - plat_error_handler(-1); + return -1; } + /* Run all tests. */ for (i = 0; i < ARRAY_SIZE(test_suites); ++i) { struct test_suite_t *suite = &(test_suites[i]); @@ -41,22 +48,33 @@ static void run_tests(void) ret = run_testsuite(suite); if (ret != TEST_SUITE_ERR_NO_ERROR) { printf("\n\nError during executing testsuite '%s'.\n", suite->name); - assert(false); - plat_error_handler(-1); + return -1; } } printf("\nAll tests are run.\n"); + + return 0; } void run_platform_tests(void) { size_t i; + int ret; + int failures = 0; - run_tests(); + ret = run_tests(); + if (ret != 0) { + /* For some reason, we could not run all tests. */ + return ret; + } printf("\n\n"); - /* Print a summary of all the tests that had been run. */ + /* + * Print a summary of all the tests that had been run. + * Also count the number of tests failure and report that back to the + * caller. + */ printf("SUMMARY:\n"); for (i = 0; i < ARRAY_SIZE(test_suites); ++i) { @@ -67,6 +85,7 @@ void run_platform_tests(void) printf(" %s PASSED.\n", suite->name); break; case TEST_FAILED: + failures++; printf(" %s FAILED.\n", suite->name); break; case TEST_SKIPPED: @@ -79,4 +98,6 @@ void run_platform_tests(void) } printf("\n\n"); + + return failures; } diff --git a/plat/arm/board/tc/tc_bl31_setup.c b/plat/arm/board/tc/tc_bl31_setup.c index 6afbd9931..ca3a03279 100644 --- a/plat/arm/board/tc/tc_bl31_setup.c +++ b/plat/arm/board/tc/tc_bl31_setup.c @@ -50,18 +50,34 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, fconf_populate("FW_CONFIG", arg1); } -void tc_bl31_common_platform_setup(void) +#ifdef PLATFORM_TESTS +static __dead2 void tc_run_platform_tests(void) { - arm_bl31_platform_setup(); + int tests_failed; + + printf("\nStarting platform tests...\n"); -#if defined(PLATFORM_TEST_NV_COUNTERS) || defined(PLATFORM_TEST_TFM_TESTSUITE) #ifdef PLATFORM_TEST_NV_COUNTERS - nv_counter_test(); + tests_failed = nv_counter_test(); #elif PLATFORM_TEST_TFM_TESTSUITE - run_platform_tests(); + tests_failed = run_platform_tests(); #endif - /* Suspend booting */ + + printf("Platform tests %s.\n", + (tests_failed != 0) ? "failed" : "succeeded"); + + /* Suspend booting, no matter the tests outcome. */ + printf("Suspend booting...\n"); plat_error_handler(-1); +} +#endif + +void tc_bl31_common_platform_setup(void) +{ + arm_bl31_platform_setup(); + +#ifdef PLATFORM_TESTS + tc_run_platform_tests(); #endif } |