ARM Cortex-M TrustZone: Secure Function Execution from Non-Secure SVC Handler

The ARM Cortex-M architecture, particularly when implementing TrustZone security extensions, introduces a robust mechanism for isolating secure and non-secure states. This isolation ensures that secure functions, such as secure storage services, are protected from unauthorized access. However, the interaction between non-secure and secure states, especially when invoking secure functions from a non-secure SVC (Supervisor Call) handler, can lead to subtle issues. One such issue arises when attempting to execute a secure function from a non-secure SVC handler, where the execution context and exception handling mechanisms must be carefully managed to ensure correct behavior.

In the context of the Trusted Firmware-M (TF-M) implementation, secure functions are typically designed to be called from handler mode, not thread mode. This design choice is rooted in the need to maintain security boundaries and ensure that secure functions are only invoked under controlled conditions. However, when a non-secure application attempts to call a secure function via an SVC instruction, the execution flow transitions through several layers of abstraction, including the SVC handler, secure veneer functions, and ultimately the secure function itself. This transition raises questions about the execution context, particularly the exception number (exc_num) and how it influences the secure function call.

Exception Context and Secure Function Execution in TrustZone

The exception number (exc_num) plays a critical role in determining the execution context when a secure function is called from a non-secure state. In the ARM Cortex-M architecture, exceptions are numbered, and each exception type has a unique identifier. For example, the SVC exception is assigned the number 11 (EXC_NUM_SVCALL). When a non-secure application issues an SVC instruction to call a secure function, the processor transitions to handler mode, and the SVC handler is invoked. At this point, the __get_active_exc_num() function retrieves the current exception number, which, in this case, will be EXC_NUM_SVCALL.

The exc_num value is then passed through the call stack, including the secure veneer function (sst_veneer_get_handle) and the core partition request function (tfm_core_partition_request). This value is critical because it determines the execution path within the tfm_core_call_sfn function. Specifically, the tfm_core_call_sfn function checks whether the exc_num is equal to EXC_NUM_THREAD_MODE. If this condition is not met, the function skips the block of code intended for thread mode execution and proceeds to perform an exception return to the secure function context.

The key issue here is that the exc_num value is not EXC_NUM_THREAD_MODE when the call originates from a non-secure SVC handler. Instead, it is EXC_NUM_SVCALL, which means the execution path within tfm_core_call_sfn will bypass the thread mode logic and proceed directly to the exception return mechanism. This behavior is by design, as it ensures that secure functions are only executed in the appropriate context, but it can lead to confusion if the underlying mechanics are not well understood.

Implications of Exception Number Mismatch in Secure Function Calls

The mismatch between the expected exc_num value (EXC_NUM_THREAD_MODE) and the actual value (EXC_NUM_SVCALL) has significant implications for the execution of secure functions. When the tfm_core_call_sfn function is invoked, it checks the exc_num value to determine whether the call originated from thread mode or handler mode. If the call originated from thread mode, the function executes the secure function directly within the current context. However, if the call originated from handler mode, the function performs an exception return to the secure function context, effectively transferring control to the secure partition.

This behavior is particularly relevant in the context of TrustZone, where the security state of the processor must be carefully managed. The exception return mechanism ensures that the processor transitions to the secure state before executing the secure function, thereby maintaining the integrity of the security boundary. However, this also means that the secure function cannot be executed directly within the non-secure SVC handler context. Instead, the processor must perform a context switch to the secure state, which introduces additional overhead and complexity.

The tfm_core_exc_return_to_sfn function is responsible for performing this context switch. It prepares the processor for secure function execution by setting up the appropriate exception return value and transitioning to the secure state. Once the secure function has completed execution, the processor returns to the non-secure state, and control is transferred back to the non-secure SVC handler. This mechanism ensures that secure functions are executed in a controlled environment, but it also means that the execution flow is more complex than a direct function call.

Debugging and Resolving Secure Function Call Issues

To debug and resolve issues related to secure function calls from non-secure SVC handlers, it is essential to understand the underlying mechanics of exception handling and context switching in the ARM Cortex-M architecture. The following steps outline a systematic approach to diagnosing and resolving these issues:

  1. Verify Exception Number: The first step is to verify the exc_num value at each stage of the call stack. This can be done by adding debug statements or using a debugger to inspect the value of desc.exc_num in the tfm_core_partition_request function. If the value is not EXC_NUM_SVCALL, it indicates that the call did not originate from an SVC handler, and further investigation is required to determine the source of the issue.

  2. Check Exception Return Mechanism: The next step is to ensure that the exception return mechanism is functioning correctly. This involves verifying that the tfm_core_exc_return_to_sfn function is correctly setting up the exception return value and transitioning to the secure state. If the function is not being called, or if the exception return value is incorrect, it may indicate a problem with the call stack or the exception handling logic.

  3. Inspect Secure Function Execution: Once the exception return mechanism has been verified, the next step is to inspect the execution of the secure function itself. This involves ensuring that the secure function is being called with the correct arguments and that it is executing in the correct context. If the secure function is not being called, or if it is executing in the wrong context, it may indicate a problem with the secure veneer function or the core partition request logic.

  4. Review TrustZone Configuration: Finally, it is essential to review the TrustZone configuration to ensure that the security boundaries are correctly defined. This includes verifying that the secure and non-secure memory regions are correctly configured and that the secure functions are properly isolated from non-secure code. If the TrustZone configuration is incorrect, it may result in unexpected behavior when calling secure functions from non-secure code.

By following these steps, developers can systematically diagnose and resolve issues related to secure function calls from non-secure SVC handlers. Understanding the underlying mechanics of exception handling and context switching in the ARM Cortex-M architecture is critical to ensuring the correct behavior of secure functions in a TrustZone environment.

Detailed Analysis of Exception Handling in ARM Cortex-M TrustZone

To further understand the issue, it is necessary to delve into the details of exception handling in the ARM Cortex-M architecture, particularly in the context of TrustZone. The ARM Cortex-M architecture uses a vector table to manage exceptions, with each exception type assigned a unique entry in the table. When an exception occurs, the processor retrieves the address of the corresponding exception handler from the vector table and transfers control to that handler.

In the case of an SVC instruction, the processor retrieves the address of the SVC handler from the vector table and transitions to handler mode. The SVC handler is responsible for determining which secure function to call based on the SVC number and then invoking the appropriate secure veneer function. The secure veneer function, in turn, prepares the call stack and invokes the core partition request function (tfm_core_partition_request), which sets up the secure function call and transfers control to the secure state.

The tfm_core_partition_request function plays a critical role in this process. It sets up the secure function call by initializing a descriptor structure (tfm_sfn_req_s) with the secure function identifier, arguments, and exception number. The exception number is retrieved using the __get_active_exc_num() function, which returns the current exception number. In the case of an SVC call, this value will be EXC_NUM_SVCALL.

The descriptor structure is then passed to the tfm_core_sfn_request_function, which performs additional setup and invokes the tfm_core_call_sfn function. The tfm_core_call_sfn function checks the exc_num value to determine the execution path. If the exc_num is EXC_NUM_THREAD_MODE, the function executes the secure function directly within the current context. However, if the exc_num is not EXC_NUM_THREAD_MODE, the function performs an exception return to the secure function context.

This exception return mechanism is critical to maintaining the security boundary between the non-secure and secure states. By transitioning to the secure state before executing the secure function, the processor ensures that the secure function is executed in a controlled environment, isolated from non-secure code. However, this also means that the execution flow is more complex than a direct function call, and it requires careful management of the exception handling and context switching mechanisms.

Practical Considerations for Secure Function Calls in TrustZone

When implementing secure function calls in a TrustZone environment, several practical considerations must be taken into account. These considerations include the design of the secure veneer functions, the management of the exception handling mechanism, and the configuration of the TrustZone security boundaries.

  1. Secure Veneer Functions: The secure veneer functions act as a bridge between the non-secure and secure states. They are responsible for validating the secure function call, setting up the call stack, and transferring control to the secure state. The design of these functions must ensure that they correctly handle the transition between security states and that they properly manage the exception handling mechanism.

  2. Exception Handling Mechanism: The exception handling mechanism must be carefully managed to ensure that secure functions are executed in the correct context. This includes ensuring that the exc_num value is correctly retrieved and passed through the call stack, and that the exception return mechanism is correctly implemented. Any errors in the exception handling mechanism can result in unexpected behavior, such as secure functions being executed in the wrong context or not being executed at all.

  3. TrustZone Configuration: The TrustZone configuration must be carefully reviewed to ensure that the security boundaries are correctly defined. This includes verifying that the secure and non-secure memory regions are correctly configured and that the secure functions are properly isolated from non-secure code. Any misconfiguration of the TrustZone security boundaries can result in security vulnerabilities or unexpected behavior when calling secure functions from non-secure code.

By taking these practical considerations into account, developers can ensure that secure function calls in a TrustZone environment are implemented correctly and that the security boundaries are maintained. This requires a deep understanding of the ARM Cortex-M architecture, particularly in the context of TrustZone, and a systematic approach to debugging and resolving issues related to secure function calls.

Conclusion

The execution of secure functions from non-secure SVC handlers in an ARM Cortex-M TrustZone environment involves a complex interplay of exception handling, context switching, and security boundary management. The exc_num value plays a critical role in determining the execution path, and any mismatch between the expected and actual values can lead to unexpected behavior. By understanding the underlying mechanics of exception handling and context switching, and by following a systematic approach to debugging and resolving issues, developers can ensure that secure function calls are implemented correctly and that the security boundaries are maintained. This requires a deep understanding of the ARM Cortex-M architecture, particularly in the context of TrustZone, and a meticulous approach to system design and implementation.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *