-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds basic fault mitigation routines designed to help protecting from fault injection attacks on the hardware. This is by no means bullet proof, but it should at least improve the situation. These routines focus on verifying that a function has been called and that the returned value matches the result from the function. This is done by having a handshake between the caller and the callee where also the return value is transmitted in a separate channel. Acked-by: Jerome Forissier <jerome.forissier@linaro.org> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
- Loading branch information
1 parent
593b94e
commit 7e75ca5
Showing
5 changed files
with
848 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// SPDX-License-Identifier: BSD-2-Clause | ||
/* | ||
* Copyright (c) 2022, Linaro Limited | ||
*/ | ||
|
||
#include <compiler.h> | ||
#include <fault_mitigation.h> | ||
|
||
#ifndef __KERNEL__ | ||
struct ftmn_func_arg *__ftmn_global_func_arg; | ||
#endif | ||
|
||
/* | ||
* These functions can be implemented in assembly if needed. They would | ||
* provide the same API but an implementation more resilient to fault | ||
* injections. | ||
* | ||
* For now there is no need since it's enough with the single redundancy | ||
* provided just by having these function implemented separately from where | ||
* they are used. | ||
*/ | ||
|
||
unsigned long __weak ___ftmn_return_res(struct ftmn_check *check, | ||
unsigned long steps, unsigned long res) | ||
{ | ||
if (check->steps != steps) | ||
FTMN_PANIC(); | ||
if ((check->res ^ FTMN_DEFAULT_HASH) != res) | ||
FTMN_PANIC(); | ||
return res; | ||
} | ||
|
||
void __weak ___ftmn_expect_state(struct ftmn_check *check, enum ftmn_incr incr, | ||
unsigned long steps, unsigned long res) | ||
{ | ||
if ((check->res ^ FTMN_DEFAULT_HASH) != res) | ||
FTMN_PANIC(); | ||
if (check->steps != steps) | ||
FTMN_PANIC(); | ||
check->steps += incr; | ||
} | ||
|
||
void __weak ___ftmn_callee_done(struct ftmn_func_arg *arg, | ||
unsigned long my_hash, | ||
unsigned long res) | ||
{ | ||
arg->hash ^= my_hash; | ||
arg->res = arg->hash ^ res; | ||
} | ||
|
||
void __weak ___ftmn_callee_done_not_zero(struct ftmn_func_arg *arg, | ||
unsigned long my_hash, | ||
unsigned long res) | ||
{ | ||
if (res == 0) | ||
FTMN_PANIC(); | ||
arg->hash ^= my_hash; | ||
arg->res = arg->hash ^ res; | ||
} | ||
|
||
void __weak ___ftmn_callee_done_memcmp(struct ftmn_func_arg *arg, | ||
unsigned long my_hash, int res, | ||
ftmn_memcmp_t my_memcmp, | ||
const void *p1, const void *p2, | ||
size_t nb) | ||
{ | ||
int res2 = 0; | ||
|
||
if (!nb) | ||
FTMN_PANIC(); | ||
|
||
res2 = my_memcmp(p1, p2, nb); | ||
if (res2 != res) | ||
FTMN_PANIC(); | ||
|
||
arg->hash ^= my_hash; | ||
arg->res = arg->hash ^ res; | ||
} | ||
|
||
void __weak ___ftmn_callee_done_check(struct ftmn_func_arg *arg, | ||
unsigned long my_hash, | ||
struct ftmn_check *check, | ||
enum ftmn_incr incr, unsigned long steps, | ||
unsigned long res) | ||
{ | ||
if ((check->res ^ FTMN_DEFAULT_HASH) != res) | ||
FTMN_PANIC(); | ||
if (check->steps != steps) | ||
FTMN_PANIC(); | ||
|
||
check->steps += incr; | ||
if (arg) { | ||
arg->hash ^= my_hash; | ||
arg->res = check->res ^ FTMN_DEFAULT_HASH ^ arg->hash; | ||
} | ||
|
||
} | ||
|
||
void ___ftmn_callee_update_not_zero(struct ftmn_func_arg *arg, | ||
unsigned long res) | ||
{ | ||
if (!res) | ||
FTMN_PANIC(); | ||
arg->res = arg->hash ^ res; | ||
} | ||
|
||
|
||
void __weak ___ftmn_copy_linked_call_res(struct ftmn_check *check, | ||
enum ftmn_incr incr, | ||
struct ftmn_func_arg *arg, | ||
unsigned long res) | ||
{ | ||
if ((arg->res ^ arg->hash) != res) | ||
FTMN_PANIC(); | ||
check->res = res ^ FTMN_DEFAULT_HASH; | ||
check->steps += incr; | ||
} | ||
|
||
void __weak ___ftmn_set_check_res(struct ftmn_check *check, enum ftmn_incr incr, | ||
unsigned long res) | ||
{ | ||
check->steps += incr; | ||
check->res = res ^ FTMN_DEFAULT_HASH; | ||
} | ||
|
||
void __weak ___ftmn_set_check_res_not_zero(struct ftmn_check *check, | ||
enum ftmn_incr incr, | ||
unsigned long res) | ||
{ | ||
if (!res) | ||
FTMN_PANIC(); | ||
check->steps += incr; | ||
check->res = res ^ FTMN_DEFAULT_HASH; | ||
} | ||
|
||
void __weak ___ftmn_set_check_res_memcmp(struct ftmn_check *check, | ||
enum ftmn_incr incr, int res, | ||
ftmn_memcmp_t my_memcmp, | ||
const void *p1, const void *p2, | ||
size_t nb) | ||
{ | ||
int res2 = 0; | ||
|
||
if (!nb) | ||
FTMN_PANIC(); | ||
|
||
res2 = my_memcmp(p1, p2, nb); | ||
if (res2 != res) | ||
FTMN_PANIC(); | ||
|
||
check->steps += incr; | ||
check->res = FTMN_DEFAULT_HASH ^ res; | ||
} |
Oops, something went wrong.