20. Non-Secure Interrupt Handling

Author

Mate Toth-Pal

Organization

Arm Limited

Contact

Mate Toth-Pal <mate.toth-pal@arm.com>

Status

Accepted

20.1. Terms

Term

Meaning

AIRCR

Application Interrupt and Reset Control Register

AIRCR.PRIS

PRIoritize Secure exceptions

ISR

Interrupt Service Routine

NS

Non-Secure

NSPM

Non-Secure Partition Manager

SAU

Security Attribution Unit

SPM

Secure Partition Manager

TF-M

Trusted Firmware-M

20.2. Introduction

In the current design it is possible to use Non-secure interrupts, however the Non-secure interrupts cannot pre-empt Secure service execution. TF-M core achieves this by making the following configurations:

  1. AIRCR.PRIS is set to 1 during TF-M core initialisation. This de-prioritizes Non-secure exceptions compared to Secure exceptions, so that they cannot interrupt Secure Handler mode. the AIRCR.PRIS bit remains set during TF-M run. The bit is set in the function

static void tfm_arch_set_secure_exception_priorities(void);

Note

Setting AIRCR.PRIS in itself doesn’t prevent NS interrupts to pre-empt Secure Thread mode when it runs on normal priority i.e., 256.

  1. On Secure service entry PRIMASK_NS is set, to boost the Non-secure execution priority so that all NS interrupts are masked. This is done in the TFM_NS_EXC_DISABLE() macro called from

static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)

Note

‘2.’ is only in Library model.

In the below chapters a design is proposed to enable Non-secure interrupts to pre-empt Secure Thread mode.

20.3. Limitations of the proposed design

20.3.1. Library model

The proposed design keeps the Secure lock in place, which means Non-secure code can do a single Secure service call, all further calls to Secure services will be rejected until the first Secure service call returns.

20.3.2. IPC model

The PSA client API can only be entered once. All the functions in the client API (psa_framework_version, psa_version, psa_connect, psa_call, psa_close) are part of the same critical section.

20.3.3. Non-secure software

The Non-secure API functions that wraps the Secure service veneers (either Library or IPC model) should continue to use the NS locking mechanism currently implemented by calling tfm_ns_lock_dispatch(...).

If any of the Non-secure software decides to bypass the locking mechanism, then concurrent access of veneer functions is detected by TF-M, and NS software execution is halted.

Note

This makes denial of service attack possible by a malicious NS application

20.4. Enabling NS interrupts to pre-empt Secure execution

To enable NS interrupts, 2) described in chapter ‘Current design’ must be turned off. (For details see implementation notes)

When a Non-secure interrupt is triggered during Secure code execution, and the ISR have to be executed based on the priority settings, the hardware saves the current execution context on the current Secure stack, and clears the general purpose registers, to prevents data leakage. After that the NS ISR starts execution.

When the Non-secure ISR returns with the EXC_RETURN value provided to it in the link register, the context is fetched from the Secure stack, and the Secure code continues execution.

If TF-M is used with a single threaded NS software, the mechanisms provided by the HW is enough to maintain the consistency of the system, and keep the secrets.

However if the NS software is allowed to change execution context during an interrupt (e.g an NS operating system schedules another thread during a SysTick interrupt), then the Secure code can return execution to an NS thread, with the context of a different thread. So extra measures needs to be introduced in TF-M to prevent this.

20.4.1. For IPC model

In the current implementation there is no locking mechanism on the Secure side that would prevent the Non-secure code to enter psa_client functions multiple times. (For the Library model the tfm_secure_lock global variable is used for this purpose). Note, that the tfm_ns_lock_dispatch(...) function that is used by the NS service API implementations to prevent Secure services to be called simultaneously can be bypassed by a malicious Non-secure application, so a Secure side locking mechanism have to be implemented.

When an NS client calls a PSA client API function, the client ID of the calling NS context have to be saved, and execution can only return to NS if the current scheduled NS thread is the one that did the call.

20.4.2. For Library model

As currently there is no scheduling in the Library model, the calls follow each other just like in an ordinary function call scheme. Then when the original Secure service that was called from the NS code is about to return, it has to check for the current NS client ID, and only return if it is the same as the one saved on Secure service entry from NS. If the ID’s don’t match, the Secure side waits so that NS OS can do context switch.

20.4.3. Common measures

20.4.3.1. Exception priorities

The priority of the Secure SVC and the Secure faults must be higher than any Secure exception in the system.

Note

The priority of PendSV Is set to be the lowest priority Secure interrupt, but still higher than the maximum possible NS execution priority when AIRCR.PRIS is set.

20.4.3.2. NSPM

If the Non-secure software allows the use of multiple threads, it needs to use the NSPM feature of TF-M. It is expected, that all the NS context that use Secure services have a unique client ID, and the other contexts, that don’t use Secure service need to have a client ID that doesn’t match with any of the client IDs of the Secure service calling contexts.

In other words, for all the cs(0), cs(1), …, cs(n) NS contexts that use Secure services and for all cn(0), cn(1), …, cn(m) NS contexts that don’t use Secure service (where n > 0, m >= 0):

  • cs(i).client_id != cs(j).client_id (where 0 <= i < j <= n)

  • cs(i).client_id != cn(j).client_id (where 0 <= i <= n and 0 <= j <= m)

20.4.3.3. Entering from Non-secure to Secure

The Secure code can be entered through the following gateways:

  1. NSPM related functions (TZ_<operation>(...), tfm_register_client_id(...))

    These functions are expected to be called from Handler mode. The execution priority, after the execution crosses the security boundary will be the same as it was during NS execution. This means a malicious Non-secure application, can set up Non-secure interrupt priorities in a way that it can enter one or more of the NSPM APIs simultaneously.

    This might leave the NSPM database in an inconsistent state, however if the attacker has influence over the interrupt priorities, they can gain no additional privilege by this.

    Note

    The NS software is able to consume the main stack of the Secure software. The Main Secure stack have to be protected by MSPLIM, to prevent stack overflow. However a denial of service attack is still possible.

  2. PSA Client API, Library model service veneers

    When a veneer is called from Non-secure, the Secure code have to check whether the veneer is only entered by a single NS thread. This can be done by checking the veneer stack usage. It can only contain the locals of the veneer implementation. If the veneer has been entered from multiple NS threads, there is at least one extra context stack frame that was created by the hardware when the veneer execution had been interrupted by the NS systick.

20.5. Implementation notes

20.5.1. IPC model

20.5.1.1. Save NS client ID on Secure service veneer entry

As long as the Secure lock is in place, a single client ID have to be stored, so it can be done in a global variable.

The caller client ID can be saved in the function void tfm_psa_ipc_request_handler(uint32_t svc_ctx[]) depending on the return value of the PSA API function. (Doesn’t execute any Secure service code, only sets signals, and triggers scheduling. If the return value is success, that means a scheduling is to happen, and a secure service is about to be entered.)

20.5.1.2. Check client ID on Secure service return

The saved client ID can be compared with the current client ID in the function tfm_core_ns_ipc_request, after the SVC return. Before doing the comparison, BASEPRI_NS must be set to 1.

The original BASEPRI_NS value can be stored in a global variable (because of the single context).

If the client ID’s don’t match, BASEPRI_NS must be reset, WFI to be issued, and start the checking sequence from the beginning.

20.5.2. Library model

20.5.2.1. Save NS client ID on Secure veneer entry

As long as the Secure lock is in place, only a single client ID have to be stored, so it can be done in a global variable.

The caller client ID can be saved in the function uint32_t tfm_core_partition_request_svc_handler(uint32_t *svc_args, uint32_t excReturn).

20.5.2.2. Check client ID on SP return

The saved client ID can be compared with the current client ID in the function tfm_core_partition_request, after the tfm_core_sfn_request return.

If the client ID’s don’t match, WFI to be issued, and the checking sequence have to be started from the beginning.

20.5.3. Common

20.5.3.1. Enforce single NS entry to Secure

On Secure service entry (from the SVC implementation) check that (pseudocode)

svc_handler()
{
    /* If there are multiple context stacked in veneer stack, hang NSPE */
    expected_sp_top = veneer_stack_addr -
                        sizeof(svc_state_context) + sizeof(locals);
    if (__get_PSP() != expected_sp_top) {
        /* Multiple frames are existing, panic */
        panic();
    }
}

20.6. Testing

20.6.1. Basic scenario

Basic testing of the feature is possible, by adding a new scenario to the existing IRQ test. The flow of the test would be something like this:

IRQ_TEST_1

prepare test scenario

Do nothing

CORE_TEST_2

prepare test scenario

Do nothing

NS

prepare test scenario

Initialise and start timer

IRQ_TEST_1

execute test scenario

Do nothing

CORE_TEST_2

execute test scenario

Busy wait until NS interrupt is acknowledged (a flag in non Secure data is set) set flag CORE_TEST_2 waits on

NS

execute test scenario

Do nothing

The test is successful if NS execute test scenario returns.

20.6.2. Advanced scenarios

Testing advanced scenarios (that involves NS scheduling during secure execution, NS interrupting Secure interrupt, Secure interrupting NS interrupt) would require more advanced test framework and are not covered in this proposal.

Copyright (c) 2019-2020, Arm Limited. All rights reserved.