Memory Access Check of Trusted Firmware-M in Multi-Core Topology
- Author
David Hu
- Organization
Arm Limited
- Contact
Introduction
TF-M memory access check function tfm_has_access_to_region()
checks whether an access has proper
permission to read or write the target memory region.
On single Armv8-M core platform based on Trustzone, TF-M memory access check implementation relies
on Armv8-M Security Extension (CMSE) intrinsic cmse_check_address_range()
.
The secure core may not implement CMSE on multi-core platforms. Even if CMSE is
implemented on a multi-core platform, additional check on system-level security
and memory access management units are still necessary since CMSE intrinsics and
TT instructions are only aware of MPU/SAU/IDAU inside the secure core.
As a result, TF-M in multi-core topology requires a dedicated access check process which can work without CMSE support. This document discuss about the design of the memory access check in multi-core topology.
Overall Design
Memory Access Check Policy
The policies vary in diverse Isolation Levels.
When TF-M works in Isolation Level 1, the access check in multi-core topology checks
Memory region is valid according to system settings
Non-secure client call request should not access secure memory.
Secure services should not directly access non-secure memory. According to PSA Firmware Framework, Secure services should call Secure Partition APIs to ask TF-M SPM to fetch non-secure input/output buffer for them.
Whether read/write attribute match between access and memory region
When TF-M works in Isolation Level 2, the access check in multi-core topology checks:
Memory region is valid according to system settings
Non-secure client call request should not access secure memory.
Secure services should not directly access non-secure memory. According to PSA Firmware Framework, Secure services should call Secure Partition APIs to ask TF-M SPM to fetch non-secure input/outputs buffer for them.
Whether read/write attribute match between access and memory region
Unprivileged secure access should not access privileged secure memory region
The check policy in Isolation Level 3 will be defined according to TF-M future implementation.
The above policies will be adjusted according to TF-M implementation and PSA specs.
General Check Process in TF-M Core
In multi-core topology, tfm_has_access_to_region()
is still invoked to keep an uniform interface
to TF-M SPM. The function implementation should be placed in multi-core topology specific files
separated from Trustzone-based access check.
Multi-core platform specific tfm_hal_memory_check()
can invoke tfm_has_access_to_region()
to
implement the entire memory access check routine.
During the check process, tfm_has_access_to_region()
compares the access permission with memory
region attributes and determines whether the access is allowed to access the region according to
policy described in Memory Access Check Policy above.
tfm_has_access_to_region()
invokes 3 HAL APIs to retrieve attributes of target memory region.
tfm_hal_get_mem_security_attr()
retrieves the security attributes of the target memory region.tfm_hal_get_secure_access_attr()
retrieves secure access attributes of the target memory region.tfm_hal_get_ns_access_attr()
retrieves non-secure access attributes of the target memory region.
All three functions are implemented by multi-core platform support. The definitions are specified in the section HAL APIs below.
The pseudo code of tfm_has_access_to_region()
is shown below.
1int32_t tfm_has_access_to_region(const void *p, size_t s, uint8_t flags)
2{
3 struct security_attr_info_t security_attr;
4 struct mem_attr_info_t mem_attr;
5
6 /* Validate input parameters */
7 if (Validation failed) {
8 return error;
9 }
10
11 /* The memory access check should be executed inside TF-M PSA RoT */
12 if (Not in privileged level) {
13 abort;
14 }
15
16 /* Set initial value */
17 security_attr_init(&security_attr);
18
19 /* Retrieve security attributes of memory region */
20 tfm_hal_get_mem_security_attr(p, s, &security_attr);
21
22 /* Compare according to current Isolation Level */
23 if (Input flags mismatch security attributes) {
24 return error;
25 }
26
27 /* Set initial value */
28 mem_attr_init(&mem_attr);
29
30 if (The target memory region is in secure memory space) {
31 /* Retrieve access attributes of secure memory region */
32 tfm_hal_get_secure_access_attr(p, s, &mem_attr);
33
34 if (Not in Isolation Level 1) {
35 /* Secure memory protection unit(s) must be enabled in Isolation Level 2 and 3 */
36 if (Protection unit not enabled) {
37 abort;
38 }
39 }
40 } else {
41 /* Retrieve access attributes of non-secure memory region. */
42 tfm_hal_get_ns_access_attr(p, s, &mem_attr);
43 }
44
45 /* Compare according to current Isolation Level and non-secure/secure access. */
46 if (Input flags match memory attributes) {
47 return success;
48 }
49
50 return error;
51}
Note
It cannot be guaranteed that TF-M provides a comprehensive memory access check on non-secure memory for NSPE client call. If non-secure memory protection or isolation is required in a multi-core system, NSPE software should implement and execute the check functionalities in NSPE, rather than relying on TF-M access check.
For example, all the access from NSPE client calls to non-secure memory are classified as unprivileged in current TF-M implementation. Multi-core access check may skip the privileged/unprivileged permission check for non-secure access.
If a multi-core system enforces the privileged/unprivileged isolation and protection of non-secure area, NSPE software should execute the corresponding check functionalities before submitting the NSPE client call request to SPE.
Data Types and APIs
Data Types
Access Permission Flags
The following flags are defined to indicate the access permission attributes. Each flag is mapped to the corresponding CMSE macro. Please refer to ARMv8-M Security Extensions: Requirements on Development Tools for details of each CMSE macro.
MEM_CHECK_MPU_READWRITE
Mapped to CMSE macro CMSE_MPU_READWRITE
to indicate that the access requires
both read and write permission to the target memory region.
#define MEM_CHECK_MPU_READWRITE (1 << 0x0)
MEM_CHECK_MPU_UNPRIV
Mapped to CMSE macro CMSE_MPU_UNPRIV
to indicate that it is an unprivileged
access.
#define MEM_CHECK_MPU_UNPRIV (1 << 0x2)
MEM_CHECK_MPU_READ
Mapped to CMSE macro CMSE_MPU_READ
. It indicates that it is a read-only
access to target memory region.
#define MEM_CHECK_MPU_READ (1 << 0x3)
MEM_CHECK_NONSECURE
Mapped to CSME macro CMSE_NONSECURE
to indicate that it is a access from
non-secure client call request.
If this flag is unset, it indicates the access is required from SPE.
#define MEM_CHECK_AU_NONSECURE (1 << 0x1)
#define MEM_CHECK_MPU_NONSECURE (1 << 0x4)
#define MEM_CHECK_NONSECURE (MEM_CHECK_AU_NONSECURE | \
MEM_CHECK_MPU_NONSECURE)
Security Attributes Information
The structure security_attr_info_t
contains the security attributes
information of the target memory region.
tfm_hal_get_mem_security_attr()
implementation should fill the structure
fields according to the platform specific secure isolation setting.
struct security_attr_info_t {
bool is_valid;
bool is_secure;
};
is_valid
indicates whether the target memory region is valid according to
platform resource assignment and security isolation configurations.is_secure
indicates the target memory region is secure or non-secure. The
value is only valid when is_valid
is true
.Memory Attributes Information
The structure mem_attr_info_t
contains the memory access attributes
information of the target memory region.
tfm_hal_get_secure_access_attr()
and tfm_hal_get_ns_access_attr()
implementations should
fill the structure fields according to the memory protection settings.
struct mem_attr_info_t {
bool is_mpu_enabled;
bool is_valid;
bool is_xn;
bool is_priv_rd_allow;
bool is_priv_wr_allow;
bool is_unpriv_rd_allow;
bool is_unpriv_wr_allow;
};
is_mpu_enabled
indicates whether the MPU and other management unit are
enabled and work normally.is_valid
indicates whether the target memory region is valid according to
platform resource assignment and memory protection configurations.is_xn
indicates whether the target memory region is Execute Never. This
field is only valid when is_valid
is true
.is_priv_rd_allow
and is_priv_wr_allow
indicates whether the target
memory region allows privileged read/write. Both the fields are valid only
when is_valid
is true
.is_unpriv_rd_allow
and is_unpriv_wr_allow
indicates whether the target
memory region allows unprivileged read/write. Both the fields are valid only
when is_valid
is true
.HAL APIs
tfm_hal_get_mem_security_attr()
tfm_hal_get_mem_security_attr()
retrieves the current active security configuration information
and fills the security_attr_info_t
.
void tfm_hal_get_mem_security_attr(const void *p, size_t s,
struct security_attr_info_t *p_attr);
Parameters |
|
|
Base address of the target memory region |
|
Size of the target memory region |
|
Pointer to the |
Return |
|
|
None |
The implementation should be decoupled from TF-M current isolation level or access check policy.
All the fields in security_attr_info_t
shall be explicitly set in
tfm_hal_get_mem_security_attr()
.
If the target memory region crosses boundaries of different security regions or levels in security
isolation configuration, tfm_hal_get_mem_security_attr()
should determine whether the memory
region violates current security isolation.
It is recommended to mark the target memory region as invalid in such case, even if the adjoining
regions or levels have the same security configuration.
If the target memory region is not explicitly specified in memory security configuration,
tfm_hal_get_mem_security_attr()
can return the following values according to actual use case:
Either set
is_valid = false
Or set
is_valid = true
and setis_secure
according to platform specific policy.
tfm_hal_get_secure_access_attr()
tfm_hal_get_secure_access_attr()
retrieves the secure memory protection configuration
information and fills the mem_attr_info_t
.
void tfm_hal_get_secure_access_attr(const void *p, size_t s,
struct mem_attr_info_t *p_attr);
Parameters |
|
|
Base address of the target memory region |
|
Size of the target memory region |
|
Pointer to the |
Return |
|
|
None |
The implementation should be decoupled from TF-M current isolation level or access check policy.
All the fields in mem_attr_info_t
shall be explicitly set in
tfm_hal_get_secure_access_attr()
, according to current active memory protection configuration.
It is recommended to retrieve the attributes from secure MPU and other hardware memory protection
unit(s). The implementation can also be simplified by checking static system-level memory layout.
If the target memory region is not specified in current active secure memory protection
configuration, tfm_hal_get_secure_access_attr()
can select the following values according to
actual use case.
Either directly set
is_valid
tofalse
Or set
is_valid
totrue
and set other fields according to other memory assignment information, such as static system-level memory layout.
If secure memory protection unit(s) is disabled and the target memory region is a valid area
according to platform resource assignment, tfm_hal_get_secure_access_attr()
must set
is_mpu_enabled
to false
and set other fields according to current system-level memory
layout.
tfm_hal_get_ns_access_attr()
tfm_hal_get_ns_access_attr()
retrieves the non-secure memory protection configuration
information and fills the mem_attr_info_t
.
void tfm_hal_get_ns_access_attr(const void *p, size_t s,
struct mem_attr_info_t *p_attr);
Parameters |
|
|
Base address of the target memory region |
|
Size of the target memory region |
|
Pointer to the |
Return |
|
|
None |
The implementation should be decoupled from TF-M current isolation level or access check policy.
Since non-secure core runs asynchronously, the non-secure MPU setting may be modified by NSPE OS and
therefore the attributes of the target memory region can be unavailable during
tfm_hal_get_ns_access_attr()
execution in TF-M.
When the target memory region is not specified in non-secure MPU, tfm_hal_get_ns_access_attr()
can set the fields according to other memory setting information, such as static system-level memory
layout.
If non-secure memory protection unit(s) is disabled and the target memory region is a valid area
according to platform resource assignment, tfm_hal_get_ns_access_attr()
can set the following
fields in mem_attr_info_t
to default values:
is_mpu_enabled = false
is_valid = true
is_xn = true
is_priv_rd_allow = true
is_unpriv_rd_allow = true
is_priv_wr_allow
and is_unpriv_wr_allow
can be set according to current system-level memory
layout, such as whether it is in code section or data section.
General retrieval functions
TF-M implements 3 general retrieval functions to retrieve memory region security attributes or memory protection configurations, based on static system-level memory layout. Platform specific HAL functions can invoke those 3 general functions to simplify implementations.
tfm_get_mem_region_security_attr()
retrieves general security attributes from static system-level memory layout.tfm_get_secure_mem_region_attr()
retrieves general secure memory protection configurations from static system-level memory layout.tfm_get_ns_mem_region_attr()
retrieves general non-secure memory protection configurations from static system-level memory layout.
If a multi-core platform’s memory layout may vary in runtime, it shall not rely on these 3 functions to retrieve static configurations. These 3 functions run through memory layout table to check against each memory section one by one, with pure software implementation. It might cost more time compared to hardware-based memory access check.
tfm_get_mem_region_security_attr()
tfm_get_mem_region_security_attr()
retrieves security attributes of target memory region
according to the static system-level memory layout and fills the security_attr_info_t
.
void tfm_get_mem_region_security_attr(const void *p, size_t s,
struct security_attr_info_t *p_attr);
Parameters |
|
|
Base address of the target memory region |
|
Size of the target memory region |
|
Pointer to the |
Return |
|
|
None |
tfm_get_secure_mem_region_attr()
tfm_get_secure_mem_region_attr()
retrieves general secure memory protection configuration
information of the target memory region according to the static system-level memory layout and fills
the mem_attr_info_t
.
void tfm_get_secure_mem_region_attr(const void *p, size_t s,
struct mem_attr_info_t *p_attr);
Parameters |
|
|
Base address of the target memory region |
|
Size of the target memory region |
|
Pointer to the |
Return |
|
|
None |
tfm_get_ns_mem_region_attr()
tfm_get_ns_mem_region_attr()
retrieves general non-secure memory protection configuration
information of the target memory region according to the static system-level memory layout and fills
the mem_attr_info_t
.
void tfm_get_ns_mem_region_attr(const void *p, size_t s,
struct mem_attr_info_t *p_attr);
Parameters |
|
|
Base address of the target memory region |
|
Size of the target memory region |
|
Pointer to the |
Return |
|
|
None |
Copyright (c) 2019-2023, Arm Limited. All rights reserved.