Skip to content

Commit

Permalink
Basic fault mitigation routines
Browse files Browse the repository at this point in the history
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
jenswi-linaro authored and jforissier committed Nov 25, 2022
1 parent 593b94e commit 7e75ca5
Show file tree
Hide file tree
Showing 5 changed files with 848 additions and 0 deletions.
3 changes: 3 additions & 0 deletions core/include/kernel/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ struct thread_specific_data {
bool stackcheck_recursion;
#endif
unsigned int syscall_recursion;
#ifdef CFG_FAULT_MITIGATION
struct ftmn_func_arg *ftmn_arg;
#endif
};

void thread_init_canaries(void);
Expand Down
153 changes: 153 additions & 0 deletions lib/libutils/ext/fault_mitigation.c
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;
}

0 comments on commit 7e75ca5

Please sign in to comment.