Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new requirements to code generation of CMSE Entry function and Non-secure calls #319

Merged
merged 2 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
vhscampos marked this conversation as resolved.
Show resolved Hide resolved
> parameter to a value within its declared type's range.
vhscampos marked this conversation as resolved.
Show resolved Hide resolved

A possible implementation is shown below:

```c
__attribute__((cmse_nonsecure_entry))
int func(int *array, unsigned short idx) {
vhscampos marked this conversation as resolved.
Show resolved Hide resolved
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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for this recommendation? Are there other potential problems with small types, or is this because there are existing compilers which don't follow these rules?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latter. There are a lot of older compilers out there that won't or can't be updated.

bytes should be avoided. This guidance extends to underlying types of `enum`
vhscampos marked this conversation as resolved.
Show resolved Hide resolved
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
Loading