From 3855e5a53e26905f9fe36b9456434f7ff5141ffb Mon Sep 17 00:00:00 2001 From: Lucas Prates Date: Wed, 24 Apr 2024 16:24:33 +0100 Subject: [PATCH] Add new requirements to code generation of CMSE Entry function and Non-secure calls This addresses the vulnerability described in CVE-2024-0151. Patch by Victor Campos. Co-authored-by: Victor Campos --- cmse/cmse.md | 125 +++++++++++++++++++++++++++++++++++++++++++-------- main/acle.md | 2 + 2 files changed, 108 insertions(+), 19 deletions(-) diff --git a/cmse/cmse.md b/cmse/cmse.md index 64459ce8..68e283c3 100644 --- a/cmse/cmse.md +++ b/cmse/cmse.md @@ -1,11 +1,11 @@ --- title: ArmĀ®v8-M Security Extensions
Requirements on Development Tools -version: 1.3 -date-of-issue: 04 August 2023 +version: 1.4 +date-of-issue: 05 April 2024 set-quote-highlight: true # LaTeX specific variables -copyright-text: Copyright 2019, 2021-2023 Arm Limited and/or its affiliates . -draftversion: false +copyright-text: Copyright 2019, 2021-2024 Arm Limited and/or its affiliates . +draftversion: true # Jekyll specific variables header_counter: true toc: true @@ -155,6 +155,13 @@ Copyright 2019, 2021-2023 Arm Limited and/or its affiliates **Entry function's caller stack frame**](stack-frame-entry.svg) -### Return from an entry function +Calls from Non-secure state follow the [[AAPCS]](#AAPCS), which states that the +caller is responsible for zero- or sign-extending arguments of integral +Fundamental Data Types smaller than a word to 4 bytes. An Entry function must +not assume that callers follow this rule, that is, it cannot presume that +integral parameters will have been zero- or sign-extended to 4 bytes. For +example, an attacker might create code that passes arguments out of their +declared type's range in an attempt to cause out-of-bounds memory accesses. +> A compiler generating code for an entry function must, for each parameter +> that is an integral Fundamental Data Type smaller than a word, narrow the +> parameter to a value within its declared type's range. + +A possible implementation is shown below: + +```c +__attribute__((cmse_nonsecure_entry)) +int func(int *array, unsigned short idx) { + return array[idx]; +} +``` + +```c +__acle_se_func: +func: +@ narrow 'idx' to 16 bits before first use +uxth r1, r1 +ldr.w r0, [r0, r1, lsl #2] +... +bxns lr +``` + +We recommend that function parameters with integral types smaller than 4 +bytes should be avoided. This guidance extends to underlying types of `enum` +used as parameters. + +### Return from an entry function + + > An entry function must use the BXNS instruction to return to its > non-secure caller. @@ -1153,7 +1196,7 @@ To prevent information leakage when an entry function returns, you must clear th registers that contain secret information ([Information leakage](#information-leakage)). - + > The code sequence directly preceding the `BXNS` instruction that transitions > to non-secure code must: @@ -1186,7 +1229,7 @@ difficult. An entry function can be called from secure or non-secure state. Software needs to distinguish between these cases. - + > The following intrinsic function must be provided if bit 1 of macro > `__ARM_FEATURE_CMSE` is set: @@ -1212,12 +1255,12 @@ only happen via function pointers. This is a consequence of separating secure and non-secure code into separate executable files as described in [Executable files](#executable-files). - + > A non-secure function type must be declared using the function attribute > `__attribute__((cmse_nonsecure_call))`. - + > A non-secure function type must only be used as a base type of a pointer. @@ -1226,7 +1269,7 @@ executable file only contains secure function definitions. ### Performing a call - + > A function call through a pointer with a non-secure function type as its > base type must switch to the non-secure state. @@ -1245,7 +1288,7 @@ that contain values that are used after the non-secure function call must be restored after the call returns. Secure code cannot depend on the non-secure state to restore these registers. - + > The code sequence directly preceding the `BLXNS` instruction that > transitions to non-secure code must: @@ -1263,7 +1306,7 @@ the non-secure state to restore these registers. A toolchain could provide you with the means to specify that some types of variables never hold secret information. - + > When the non-secure function call returns, caller- and callee-saved > registers saved before the call must be restored. This includes bits [27:0] @@ -1290,7 +1333,7 @@ usage is required according to [[AAPCS]](#AAPCS), the non-secure state expects the arguments on the non-secure stack and writes the return value to non-secure memory. - + > To avoid using the non-secure stack, a toolchain may constrain the > following, for a non-secure function type: @@ -1299,7 +1342,7 @@ memory. > * The type of each parameter. > * The return type. - + > A compiler compiling a call to a non-secure function must do either of the > following: @@ -1335,6 +1378,50 @@ The stack usage during a non-secure function call is shown in figure ![**Caller's stack frame of a non-secure function call**](stack-frame-non-secure.svg) +The return of values from Non-secure function calls follows the +[[AAPCS]](#AAPCS), which states that the callee is responsible for zero- or +sign-extending return values of integral Fundamental Data Types smaller than a +word to 4 bytes. A Secure function must not assume that Non-secure callees +follow this rule, that is, it cannot presume that integral returned values will +have been zero- or sign-extended to 4 bytes. For example, an attacker might +create code that returns values out of their declared type's range in an +attempt to cause out-of-bounds memory accesses. + + +> A compiler generating code for a Non-secure function call must, for each +> returned value that is an integral Fundamental Data Type smaller than a word, +> narrow the returned value to a value within its declared type's range. + +A possible implementation is shown below: + +```c +__attribute__((cmse_nonsecure_call)) +unsigned short (*nonsecurefunc)(void); + +void securefunc(int *array) { + unsigned short idx = nonsecurefunc(); + print(array[idx]); +} +``` + +```c +securefunc: +... +@ r1 has the address of 'nonsecurefunc' +@ r2 has 'array' +@ non-secure function call +blxns r1 +@ narrow 'idx' (returned value in r0) to a 16-bit value +uxth r0, r0 +ldr.w r0, [r2, r0, lsl #2] +bl print +... +``` + +We recommend that function return values with integral types smaller than 4 +bytes should be avoided. This guidance extends to underlying types of `enum` +used as return values. + ## Non-secure function pointer A function pointer that has its LSB unset is a non-secure function @@ -1399,7 +1486,7 @@ void call_callback(void) { This is just an optimisation technique and hence it is not required for the correct usage of non-secure function pointers. - + > The following intrinsics are defined if bit 1 of macro > `__ARM_FEATURE_CMSE` is set: @@ -1428,12 +1515,12 @@ A non-secure callable function is a function that is expected to be placed in an NSC region. Its functionality is identical to an entry function, but instead of a secure gateway veneer the function starts with the `SG` instruction. - + > A non-secure callable function must be declared by using the attribute > `__attribute__((cmse_nonsecure_callable))` on a function declaration. - + > A non-secure callable function is identical to an entry function except that: > @@ -1449,7 +1536,7 @@ Toolchain support is needed to prevent inadvertent secure gateways from occurring ([Inadverted secure gataway](#inadvertent-secure-gateway)). - + > A toolchain must provide a way for the programmer to guarantee that a > non-secure callable function does not contain an inadvertent `SG` instruction @@ -1465,7 +1552,7 @@ non-secure state, but cannot be called by the non-secure state. An example use would be to provide tail-calls from an entry function to non-secure returning functions. - + > A non-secure returning function must be declared by using the attribute > `__attribute__((cmse_nonsecure_return))` on a function declaration. diff --git a/main/acle.md b/main/acle.md index 380e5a32..595840d8 100644 --- a/main/acle.md +++ b/main/acle.md @@ -389,6 +389,8 @@ Armv8.4-A [[ARMARMv84]](#ARMARMv84). Support is added for the Dot Product intrin #### Changes for next release +* Added new content for the handling of arguments in CMSE Entry functions and + return values of CMSE Non-secure calls in order to address security issues. ### References