Secure Code Writing to Non-Secure Memory Without Retention
In ARMv8-M architectures, a common issue arises when secure code attempts to write values to non-secure memory, only to find that the written values are not retained when accessed by non-secure code. This problem is particularly prevalent in systems where secure and non-secure states coexist, such as in TrustZone implementations. The secure state is designed to handle sensitive operations and data, while the non-secure state handles less critical tasks. However, the interaction between these two states can lead to unexpected behavior, especially when dealing with memory access permissions and coherency.
The core of the issue lies in the memory protection mechanisms inherent to ARMv8-M architectures. When secure code writes to non-secure memory, the memory protection unit (MPU) and the security attribution unit (SAU) play crucial roles in determining whether the write operation is permitted and whether the written data will be visible to the non-secure state. If these units are not configured correctly, or if the secure code does not adhere to the necessary guidelines, the written data may not be retained or may not be accessible to the non-secure code.
This issue is further complicated by the fact that the secure state must not only have permission to access the non-secure memory but also ensure that the non-secure state has the necessary permissions to access the same memory region. This dual-permission requirement is a fundamental aspect of ARMv8-M security architecture, designed to prevent unauthorized access and ensure data integrity across secure and non-secure domains.
Memory Protection Misconfiguration and Permission Violations
One of the primary causes of secure code failing to retain written values in non-secure memory is the misconfiguration of the Memory Protection Unit (MPU) and the Security Attribution Unit (SAU). These units are responsible for defining the memory regions and their associated permissions, including whether a region is secure or non-secure, and what operations (read, write, execute) are allowed from each state.
In ARMv8-M architectures, the MPU and SAU work together to enforce memory access policies. The MPU defines the memory regions and their attributes, such as cacheability, shareability, and access permissions. The SAU, on the other hand, assigns security attributes to these regions, determining whether they are secure or non-secure. If the MPU and SAU are not configured correctly, the secure code may not have the necessary permissions to write to non-secure memory, or the non-secure code may not have the necessary permissions to read from the same memory region.
Another potential cause is the violation of the dual-permission requirement. In ARMv8-M architectures, secure code can only access non-secure memory if the non-secure state also has permission to access the same memory region. This requirement is in place to prevent secure code from inadvertently or maliciously accessing memory that the non-secure state cannot access. If the secure code attempts to write to a non-secure memory region that the non-secure state does not have permission to access, the write operation may fail, or the written data may not be retained.
Additionally, the issue may be exacerbated by the use of address translation mechanisms, such as the Memory Management Unit (MMU). In systems where address translation is enabled, the secure code must ensure that the virtual address used to access non-secure memory maps to a physical address that is both accessible and has the correct permissions. If the address translation is not configured correctly, the secure code may end up writing to a different memory region than intended, leading to data retention issues.
Configuring MPU and SAU for Secure-Non-Secure Memory Access
To resolve the issue of secure code failing to retain written values in non-secure memory, it is essential to properly configure the MPU and SAU to ensure that both secure and non-secure states have the necessary permissions to access the target memory region. This involves defining the memory regions and their attributes in the MPU, assigning the correct security attributes in the SAU, and ensuring that the address translation mechanisms (if used) are configured correctly.
The first step is to define the memory regions in the MPU. Each region should be assigned a base address, a size, and a set of attributes, including access permissions (read, write, execute) and memory type (normal, device, strongly-ordered). For non-secure memory regions that need to be accessed by secure code, the access permissions should allow both secure and non-secure write operations. This ensures that the secure code can write to the memory region, and the non-secure code can read from it.
Next, the SAU must be configured to assign the correct security attributes to the memory regions defined in the MPU. The SAU should be configured to mark the target memory region as non-secure, allowing both secure and non-secure states to access it. It is important to note that the SAU configuration must be consistent with the MPU configuration; if the MPU defines a region as non-secure, the SAU must also mark it as non-secure.
In systems where address translation is enabled, the secure code must ensure that the virtual address used to access non-secure memory maps to a physical address that is both accessible and has the correct permissions. This involves configuring the MMU to map the virtual address to the correct physical address and ensuring that the memory region associated with the physical address has the necessary permissions in both the MPU and SAU.
Once the MPU, SAU, and MMU (if applicable) are configured correctly, the secure code can safely write to non-secure memory, and the written values will be retained and accessible to the non-secure code. It is also recommended to use data synchronization barriers (DSBs) and instruction synchronization barriers (ISBs) to ensure that the memory access operations are completed before proceeding to the next instruction. This helps to prevent race conditions and ensures that the memory is in a consistent state when accessed by the non-secure code.
In conclusion, the issue of secure code failing to retain written values in non-secure memory in ARMv8-M architectures is primarily caused by misconfigurations of the MPU and SAU, violations of the dual-permission requirement, and incorrect address translation. By properly configuring the MPU, SAU, and MMU (if applicable), and ensuring that both secure and non-secure states have the necessary permissions to access the target memory region, this issue can be resolved, and the secure code can successfully write to non-secure memory with the written values retained and accessible to the non-secure code.