Skip to content

Commit

Permalink
Add new requirements to code generation of CMSE Entry function and No…
Browse files Browse the repository at this point in the history
…n-secure calls

This addresses the vulnerability described in CVE-2024-0151.

Patch by Victor Campos.

Co-authored-by: Victor Campos <[email protected]>
  • Loading branch information
pratlucas and vhscampos committed Apr 24, 2024
1 parent f947de6 commit 3855e5a
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 19 deletions.
125 changes: 106 additions & 19 deletions cmse/cmse.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
title: Arm®v8-M Security Extensions <br /> 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 <[email protected]>.
draftversion: false
copyright-text: Copyright 2019, 2021-2024 Arm Limited and/or its affiliates <[email protected]>.
draftversion: true
# Jekyll specific variables
header_counter: true
toc: true
Expand Down Expand Up @@ -155,6 +155,13 @@ Copyright 2019, 2021-2023 Arm Limited and/or its affiliates <open-source-office@
[Non-secure function pointers](#non-secure-function-pointer).
* Fixed typos.

#### Changes for next release

* Added [Requirement #47](#requirement-47) to address a security issue in the
handling of arguments to CMSE Entry functions.
* Added [Requirement #58](#requirement-58) to address a security issue in the
handling of return values from CMSE Non-secure calls.

## References

This document refers to the following documents.
Expand Down Expand Up @@ -1138,9 +1145,45 @@ caller stack frame](#figure5).
![<span id="figure5" class="citation-label">**Entry function's caller stack frame**</span>](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.
<span id="requirement-47" class="requirement-box"></span>
> 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
<span id="requirement-48" class="requirement-box"></span>
> An entry function must use the BXNS instruction to return to its
> non-secure caller.
Expand All @@ -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)).
<span id="requirement-48" class="requirement-box"></span>
<span id="requirement-49" class="requirement-box"></span>
> The code sequence directly preceding the `BXNS` instruction that transitions
> to non-secure code must:
Expand Down Expand Up @@ -1186,7 +1229,7 @@ difficult.
An entry function can be called from secure or non-secure state. Software needs
to distinguish between these cases.
<span id="requirement-49" class="requirement-box"></span>
<span id="requirement-50" class="requirement-box"></span>
> The following intrinsic function must be provided if bit 1 of macro
> `__ARM_FEATURE_CMSE` is set:
Expand All @@ -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).
<span id="requirement-50" class="requirement-box"></span>
<span id="requirement-51" class="requirement-box"></span>
> A non-secure function type must be declared using the function attribute
> `__attribute__((cmse_nonsecure_call))`.
<span id="requirement-51" class="requirement-box"></span>
<span id="requirement-52" class="requirement-box"></span>
> A non-secure function type must only be used as a base type of a pointer.
Expand All @@ -1226,7 +1269,7 @@ executable file only contains secure function definitions.
### Performing a call
<span id="requirement-52" class="requirement-box"></span>
<span id="requirement-53" class="requirement-box"></span>
> A function call through a pointer with a non-secure function type as its
> base type must switch to the non-secure state.
Expand All @@ -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.
<span id="requirement-53" class="requirement-box"></span>
<span id="requirement-54" class="requirement-box"></span>
> The code sequence directly preceding the `BLXNS` instruction that
> transitions to non-secure code must:
Expand All @@ -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.
<span id="requirement-54" class="requirement-box"></span>
<span id="requirement-55" class="requirement-box"></span>
> When the non-secure function call returns, caller- and callee-saved
> registers saved before the call must be restored. This includes bits [27:0]
Expand All @@ -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.
<span id="requirement-55" class="requirement-box"></span>
<span id="requirement-56" class="requirement-box"></span>
> To avoid using the non-secure stack, a toolchain may constrain the
> following, for a non-secure function type:
Expand All @@ -1299,7 +1342,7 @@ memory.
> * The type of each parameter.
> * The return type.
<span id="requirement-56" class="requirement-box"></span>
<span id="requirement-57" class="requirement-box"></span>
> A compiler compiling a call to a non-secure function must do either of the
> following:
Expand Down Expand Up @@ -1335,6 +1378,50 @@ The stack usage during a non-secure function call is shown in figure
![<span id="figure6" class="citation-label">**Caller's stack frame of a non-secure function call**</span>](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.
<span id="requirement-58" class="requirement-box"></span>
> 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
Expand Down Expand Up @@ -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.
<span id="requirement-57" class="requirement-box"></span>
<span id="requirement-59" class="requirement-box"></span>
> The following intrinsics are defined if bit 1 of macro
> `__ARM_FEATURE_CMSE` is set:
Expand Down Expand Up @@ -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.
<span id="requirement-58" class="requirement-box"></span>
<span id="requirement-60" class="requirement-box"></span>
> A non-secure callable function must be declared by using the attribute
> `__attribute__((cmse_nonsecure_callable))` on a function declaration.
<span id="requirement-59" class="requirement-box"></span>
<span id="requirement-61" class="requirement-box"></span>
> A non-secure callable function is identical to an entry function except that:
>
Expand All @@ -1449,7 +1536,7 @@ Toolchain support is needed to prevent inadvertent secure gateways
from occurring ([Inadverted secure
gataway](#inadvertent-secure-gateway)).
<span id="requirement-60" class="requirement-box"></span>
<span id="requirement-62" class="requirement-box"></span>
> A toolchain must provide a way for the programmer to guarantee that a
> non-secure callable function does not contain an inadvertent `SG` instruction
Expand All @@ -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.
<span id="requirement-61" class="requirement-box"></span>
<span id="requirement-63" class="requirement-box"></span>
> A non-secure returning function must be declared by using the attribute
> `__attribute__((cmse_nonsecure_return))` on a function declaration.
Expand Down
2 changes: 2 additions & 0 deletions main/acle.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 3855e5a

Please sign in to comment.