Commit 5047f032 authored by Michael Grand's avatar Michael Grand Committed by David Brown
Browse files

fih: Hardening of fault injection countermeasures



Returned values are now hardcoded. Indeed, while it is not
strictly needed (few return values different from SUCCESS
or FAILURE) complexity added by encoding return values might
cause the software to be vulnerable to fault attacks.

Return type changed from fih_int to fih_ret to make
the whole thing much simpler and therefore more robust
to fault attacks. In addition, its easier to predict
compiler behavior.

Affectation of sentive variables has been hardened using macro
FIH_SET (affectation + check wether write access has been properly
done). FIH_DECLARE() is added to ease the declaration of sentive
variables.

Equality tests fih_eq() and fih_not_eq() are now macros because
inlining produce more complex code (and weaker) than macros.
In addition fih_not_eq is modified to be the negation of fih_eq
which was not the case until now.

when FIH_NOT_EQ is used , FIH_SET(fih_rc, FIH_FAILURE) has been added
in some part of the code.

variable image_mask (bootutil_priv.h) is now volatile because a
double IF test is made on it.

some others parts of the code have been hardenned (eg. loop on images)

Signed-off-by: default avatarMichael Grand <m.grand@trustngo.tech>
parent 78d50b2f
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -235,14 +235,14 @@ bs_list(char *buf, int len)
                flash_area_read(fap, 0, &hdr, sizeof(hdr));
            }

            fih_int fih_rc = FIH_FAILURE;
            FIH_DECLARE(fih_rc, FIH_FAILURE);

            if (hdr.ih_magic == IMAGE_MAGIC)
            {
                BOOT_HOOK_CALL_FIH(boot_image_check_hook,
                                   fih_int_encode(BOOT_HOOK_REGULAR),
                                   FIH_BOOT_HOOK_REGULAR,
                                   fih_rc, image_index, slot);
                if (fih_eq(fih_rc, BOOT_HOOK_REGULAR))
                if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR))
                {
#ifdef MCUBOOT_ENC_IMAGES
                    if (slot == 0 && IS_ENCRYPTED(&hdr)) {
@@ -262,7 +262,7 @@ bs_list(char *buf, int len)

            flash_area_close(fap);

            if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
            if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
                continue;
            }

+2 −2
Original line number Diff line number Diff line
@@ -80,9 +80,9 @@ int boot_read_image_header_hook(int img_index, int slot,
 * 
 * @retval FIH_SUCCESS: image is valid, skip direct validation
 *         FIH_FAILURE: image is invalid, skip direct validation
 *         fih encoded BOOT_HOOK_REGULAR: follow the normal execution path.
 *         FIH_BOOT_HOOK_REGULAR: follow the normal execution path.
 */
fih_int boot_image_check_hook(int img_index, int slot);
fih_ret boot_image_check_hook(int img_index, int slot);

/** Hook for implement image update
 *
+4 −4
Original line number Diff line number Diff line
@@ -78,18 +78,18 @@ struct image_trailer {
};

/* you must have pre-allocated all the entries within this structure */
fih_int boot_go(struct boot_rsp *rsp);
fih_int boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id);
fih_ret boot_go(struct boot_rsp *rsp);
fih_ret boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id);

struct boot_loader_state;
void boot_state_clear(struct boot_loader_state *state);
fih_int context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp);
fih_ret context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp);

#define SPLIT_GO_OK                 (0)
#define SPLIT_GO_NON_MATCHING       (-1)
#define SPLIT_GO_ERR                (-2)

fih_int split_go(int loader_slot, int split_slot, void **entry);
fih_ret split_go(int loader_slot, int split_slot, void **entry);

#ifdef __cplusplus
}
+23 −30
Original line number Diff line number Diff line
@@ -43,9 +43,9 @@
 *
 * The basic call pattern is:
 *
 * fih_int fih_rc = FIH_FAILURE;
 * FIH_DECLARE(fih_rc, FIH_FAILURE);
 * FIH_CALL(vulnerable_function, fih_rc, arg1, arg2);
 * if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
 * if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
 *     FIH_PANIC;
 * }
 *
@@ -93,9 +93,13 @@ extern "C" {
#ifndef MCUBOOT_FIH_PROFILE_OFF
#define FIH_POSITIVE_VALUE 0x1AAAAAAA
#define FIH_NEGATIVE_VALUE 0x15555555
#define FIH_CONST1 0x1FCDEA88
#define FIH_CONST2 0x19C1F6E1
#else
#define FIH_POSITIVE_VALUE 0
#define FIH_NEGATIVE_VALUE -1
#define FIH_CONST1 1
#define FIH_CONST2 1
#endif

/* A volatile mask is used to prevent compiler optimization - the mask is xored
@@ -115,15 +119,19 @@ typedef volatile struct {
    volatile int val;
    volatile int msk;
} fih_int;
typedef volatile int fih_ret;

#else

typedef int fih_int;
typedef int fih_ret;

#endif /* FIH_ENABLE_DOUBLE_VARS */

extern fih_int FIH_SUCCESS;
extern fih_int FIH_FAILURE;
extern fih_ret FIH_SUCCESS;
extern fih_ret FIH_FAILURE;
extern fih_ret FIH_NO_BOOTABLE_IMAGE;
extern fih_ret FIH_BOOT_HOOK_REGULAR;

#ifdef FIH_ENABLE_GLOBAL_FAIL
/* Global failure handler - more resistant to unlooping. noinline and used are
@@ -206,21 +214,9 @@ fih_int fih_int_encode(int x)
}

/* Standard equality. If A == B then 1, else 0 */
__attribute__((always_inline)) inline
int fih_eq(fih_int x, fih_int y)
{
    fih_int_validate(x);
    fih_int_validate(y);
    return (x.val == y.val) && fih_delay() && (x.msk == y.msk);
}

__attribute__((always_inline)) inline
int fih_not_eq(fih_int x, fih_int y)
{
    fih_int_validate(x);
    fih_int_validate(y);
    return (x.val != y.val) && fih_delay() && (x.msk != y.msk);
}
#define FIH_EQ(x, y) ((x == y) && fih_delay() && !(y != x))
#define FIH_NOT_EQ(x, y) ((x != y) || !fih_delay() || !(y == x))
#define FIH_SET(x, y) x = y; if(fih_delay() && (x != y)) FIH_PANIC

#else

@@ -246,25 +242,22 @@ fih_int fih_int_encode(int x)
    return x;
}

__attribute__((always_inline)) inline
int fih_eq(fih_int x, fih_int y)
{
    return x == y;
}
#define FIH_EQ(x, y) (x == y)
#define FIH_NOT_EQ(x, y) (x != y)
#define FIH_SET(x, y) x = y

__attribute__((always_inline)) inline
int fih_not_eq(fih_int x, fih_int y)
{
    return x != y;
}
#endif /* FIH_ENABLE_DOUBLE_VARS */

#define FIH_DECLARE(var, val) \
    fih_ret var; \
    FIH_SET(var, val);

/* C has a common return pattern where 0 is a correct value and all others are
 * errors. This function converts 0 to FIH_SUCCESS and any other number to a
 * value that is not FIH_SUCCESS
 */
__attribute__((always_inline)) inline
fih_int fih_int_encode_zero_equality(int x)
fih_ret fih_ret_encode_zero_equality(int x)
{
    if (x) {
        return FIH_FAILURE;
+1 −1
Original line number Diff line number Diff line
@@ -159,7 +159,7 @@ _Static_assert(sizeof(struct image_header) == IMAGE_HEADER_SIZE,
               "struct image_header not required size");

struct enc_key_data;
fih_int bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
fih_ret bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
                              struct image_header *hdr,
                              const struct flash_area *fap,
                              uint8_t *tmp_buf, uint32_t tmp_buf_sz,
Loading