Skip to content

Commit 0a43fea

Browse files
committed
minor tweaks
1 parent ddef450 commit 0a43fea

File tree

1 file changed

+12
-10
lines changed

1 file changed

+12
-10
lines changed

text/0000-cmse-calling-conventions.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ Trustzone is growing in availability and use. More and more of the new medium an
2727

2828
The cmse calling conventions are part of the *Cortex-M Security Extension* that are available on thumbv8 systems. They are used together with Trustzone (hardware isolation) to create more secure embedded applications. Arm defines the toolchain requirements in [ARMv8-M Security Extensions: Requirements on Development Tools - Engineering Specification](https://developer.arm.com/documentation/ecm0359818/latest/), but of course this specification needs to be interpreted in a Rust context.
2929

30-
The main idea of Trustzone is to split an embedded application into two executables. The secure executable has access to secrets (e.g. encryption keys), and must be careful not to leak those secrets. The non-secure executable cannot access these secrets or any memory that is marked as secure: the system will hardfault if it tries to dereference a pointer to memory that it does not have access to. In this way a whole class of security issues is simply impossible in the non-secure app.
30+
The main idea of Trustzone is to split an embedded application into two executables. The secure executable has access to secrets (e.g. encryption keys), and must be careful not to leak those secrets. The non-secure executable cannot access these secrets or any memory that is marked as secure: the system will raise a SecureFault when a program dereferences a pointer to memory that it does not have access to. In this way a whole class of security issues is simply impossible in the non-secure app.
3131

3232
The cmse calling conventions facilitate interactions between the secure and non-secure executables. To ensure that secrets do not leak, these calling conventions impose some custom restrictions on top of the system's standard AAPCS calling convention.
3333

34-
The `cmse-nonsecure-entry` calling convention is used in the secure executable to define entry points that the non-secure executable can call. The use of this calling convention hooks into the tooling (LLVM and the linker) to generate a shim that switches the security mode, and an import library (an object file with only declarations, not actual instructions) that can be linked into the non-secure executable.
34+
The `cmse-nonsecure-entry` calling convention is used in the secure executable to define entry points that the non-secure executable can call. The use of this calling convention hooks into the tooling (LLVM and the linker) to generate a shim (what rust calls a shim, arm calls a *veneer*) that switches the security mode, and an import library (an object file with only declarations, not actual instructions) that can be linked into the non-secure executable.
3535

3636
The `cmse-nonsecure-call` calling convention is used in the other direction, when the secure executable wants to call into the non-secure executable. This calling convention can only occur on function pointers, not on definitions or extern blocks. The secure executable can acquire a non-secure function pointer via shared memory or a non-secure callback can be passed to an entry function.
3737

@@ -44,9 +44,9 @@ The `cmse-nonsecure-call` and `cmse-nonsecure-entry` ABIs are only accepted on `
4444

4545
The foundation of the cmse ABIs is the platform's standard AAPCS calling convention. On `thumbv8m` targets `extern "aapcs"` is the default C ABI and equivalent to `extern "C"`.
4646

47-
The `cmse-nonsecure-call` ABI can only be used on function pointers. Using it in for a function definition or extern block emits an error. It is sound to cast such a function to `extern "aapcs"`, but calling the function will cause a HardFault. Casting an `extern "aapcs"` function pointer to a `cmse-nonsecure-call` is valid, but will cause a HardFault if the function's definition is not in non-secure memory.
47+
The `cmse-nonsecure-call` ABI can only be used on function pointers. Using it in for a function definition or extern block emits an error. It is sound to cast such a function to `extern "aapcs"`, but calling the function will cause a SecureFault. Casting an `extern "aapcs"` function pointer to a `cmse-nonsecure-call` is valid, but will cause a SecureFault if the function's definition is not in non-secure memory.
4848

49-
The `cmse-nonsecure-entry` ABI is allowed on function definitions, extern blocks and function pointers. It is sound and valid (in some cases even encouraged) to cast such a function to `extern "aapcs"`. Calling the function is valid and will behave as expected. Casting an `extern "aapcs"` function pointer to `cmse-nonsecure-entry` is valid, but will not change the security mode.
49+
The `cmse-nonsecure-entry` ABI is allowed on function definitions, extern blocks and function pointers. It is sound and valid (in some cases even encouraged) to cast such a function to `extern "aapcs"`. Calling the function is valid and will behave as expected in both the secure and non-secure applications. Casting an `extern "aapcs"` function pointer to `cmse-nonsecure-entry` is valid, but will not change the security mode, so calling such a function that was defined in the secure application will SecureFault when called in the non-secure application.
5050

5151
### Argument passing
5252

@@ -102,22 +102,22 @@ LL | extern "cmse-nonsecure-entry" fn return_impl_trait(_: impl Copy) -> impl Co
102102
The `cmse-nonsecure-call` calling convention can only be used on function pointers, which already disallows generics. For `cmse-nonsecure-entry`, it is standard to add a `#[no_mangle]` or similar attribute, which also disallows generics. Explicitly disallowing generics enables the layout calculation that is required for good error messages for signatures that use too many registers.
103103
### No C-variadics (currently)
104104

105-
Currently both ABIs disallow the use of c-variadics. For `cmse-nonsecure-entry`, the toolchain actually does not support c-variadic signatures (likely because of how they interact with veneers, though the specification does not say that explicitly).
105+
Currently both ABIs disallow the use of c-variadics. For `cmse-nonsecure-entry`, the toolchain actually does not support c-variadic signatures (likely because of how they interact with shim that switches to secure mode), though the specification does not say that explicitly).
106106

107107
- clang rejects c-variadic entry functions: https://godbolt.org/z/MaPjzGcE1
108108
- but accepts c-variadic nonsecure calls: https://godbolt.org/z/5rdK58ar4
109109

110-
For `cmse-nonsecure-call`, we may stabilize c-variadics at some point in the future.
110+
For `cmse-nonsecure-call`, we may support and stabilize c-variadics at some point in the future.
111111

112112
### Support for `const fn`
113113

114114
No special support for calling cmse functions is needed.
115115

116-
Evaluating entry functions during constant evaluation is valid. The context switch from non-secure to secure mode is handled by the veneer, which is not visible to rust code. Clearing of registers is not relevant for constant evaluation.
116+
Evaluating entry functions during constant evaluation is valid. The context switch from non-secure to secure mode is handled by the shim that switches to secure mode, which is not visible to rust code. Clearing of registers is not relevant for constant evaluation.
117117

118118
The `cmse-nonsecure-call` calling convention can only be used on function pointers, which cannot be evaluated during constant evaluation.
119119

120-
Miri is not a register machine, so the clearing of registers is not relevant. The context switching also does not need to be considered. Miri will continue to execute where actual hardware hits a hardfault, but this is similar to a standard rust process trying to read memory that the kernel has protected.
120+
Miri is not a register machine, so the clearing of registers is not relevant. The context switching also does not need to be considered, because a Miri input program cannot use FFI and therefore cannot cross the secure boundary. Any attempt to do so would rely on a transmute or similar and would for that reason be unsound.
121121
### Warn on partially uninitialized values crossing the secure boundary
122122

123123
Unions and types with padding or niches can contain uninitialized memory, and this uninitialized memory can contain stale secure information. Clang warns when union values cross the security boundary (see https://godbolt.org/z/vq9xnrnEs), and rust does the same.
@@ -134,6 +134,8 @@ LL | f4: extern "cmse-nonsecure-call" fn(MaybeUninit<u64>),
134134

135135
Like clang, the lint is emitted at the use site. That means that in the case where passing such a value is deliberate, each use site can be annotated with `#[allow(cmse_uninitialized_leak)]`. In most cases this lint should be considered an error, and an alternative way of returning/passing the value should be found that does not run the risk of leaking secure information.
136136

137+
Unlike clang, the rust lint also warns on other instances where a value may be (partially) uninitialized based on its type. For instance, clang does not warn when a struct crossing the secure boundary contains padding (e.g. https://godbolt.org/z/rcM65YG1s).
138+
137139
The lint is implemented in https://github.com/rust-lang/rust/pull/147697, and checks whether transmuting a type `T` to `[u8; size_of::<T>]` is valid. The transmute is only valid when all bytes of `T` are guaranteed to be initialized.
138140

139141
```rust
@@ -291,9 +293,9 @@ One potential method is to extend the`repr` attribute with an option that adds f
291293
#[repr(C, align(8), initialized)]
292294
struct Foo {
293295
a: u8,
294-
_padding0: [u8; 1],
296+
// implicit _padding0: [u8; 1],
295297
b: u16,
296-
_padding1: [u8; 4],
298+
// implicit _padding1: [u8; 4],
297299
}
298300
```
299301

0 commit comments

Comments
 (0)