1*7e75ca54SJens Wiklander /* SPDX-License-Identifier: BSD-2-Clause */ 2*7e75ca54SJens Wiklander /* 3*7e75ca54SJens Wiklander * Copyright (c) 2022, Linaro Limited 4*7e75ca54SJens Wiklander */ 5*7e75ca54SJens Wiklander #ifndef __FAULT_MITIGATION_H 6*7e75ca54SJens Wiklander #define __FAULT_MITIGATION_H 7*7e75ca54SJens Wiklander 8*7e75ca54SJens Wiklander #include <assert.h> 9*7e75ca54SJens Wiklander #include <config.h> 10*7e75ca54SJens Wiklander #include <string.h> 11*7e75ca54SJens Wiklander #include <util.h> 12*7e75ca54SJens Wiklander 13*7e75ca54SJens Wiklander #ifdef __KERNEL__ 14*7e75ca54SJens Wiklander #include <kernel/panic.h> 15*7e75ca54SJens Wiklander #include <kernel/thread.h> 16*7e75ca54SJens Wiklander #else 17*7e75ca54SJens Wiklander #include <tee_api.h> 18*7e75ca54SJens Wiklander #endif 19*7e75ca54SJens Wiklander 20*7e75ca54SJens Wiklander /* 21*7e75ca54SJens Wiklander * Fault migitigation helpers to make successful Hardware Fault Attacks 22*7e75ca54SJens Wiklander * harder to achieve. The paper [1] by Riscure gives background to the 23*7e75ca54SJens Wiklander * problem. 24*7e75ca54SJens Wiklander * 25*7e75ca54SJens Wiklander * These helpers aim to make it hard for a single glitch attack to succeed 26*7e75ca54SJens Wiklander * while the protected function or one of the ftmn_*() functions are 27*7e75ca54SJens Wiklander * executed. 28*7e75ca54SJens Wiklander * 29*7e75ca54SJens Wiklander * To have something to work with we assume that a single glitch may affect 30*7e75ca54SJens Wiklander * a few instructions in sequence to do nothing or to corrupt the content 31*7e75ca54SJens Wiklander * of a few registers. 32*7e75ca54SJens Wiklander * 33*7e75ca54SJens Wiklander * Using the terminology from [1] we are implementing the following patterns: 34*7e75ca54SJens Wiklander * 3 FAULT.VALUE.CHECK 35*7e75ca54SJens Wiklander * 5 FAULT.DECISION.CHECK 36*7e75ca54SJens Wiklander * 9 FAULT.FLOW.CONTROL 37*7e75ca54SJens Wiklander * 38*7e75ca54SJens Wiklander * Additionally are the following patterns also acknowledged with a few 39*7e75ca54SJens Wiklander * comments: 40*7e75ca54SJens Wiklander * 1. FAULT.CONSTANT.CODING 41*7e75ca54SJens Wiklander * Zero is normally a success code in OP-TEE so special functions are 42*7e75ca54SJens Wiklander * added to record anything but a zero result. 43*7e75ca54SJens Wiklander * 8. FAULT.NESTED.CHECK 44*7e75ca54SJens Wiklander * The linked calls performed by for instance FTMN_CALL_FUNC() addresses 45*7e75ca54SJens Wiklander * this by relying on the called function to update a state in 46*7e75ca54SJens Wiklander * struct ftmn_func_arg which is checked when the function has returned. 47*7e75ca54SJens Wiklander * 11. FAULT.PENALTY 48*7e75ca54SJens Wiklander * This is implicit since we're normally trying to protect things post 49*7e75ca54SJens Wiklander * boot and booting takes quite some time. 50*7e75ca54SJens Wiklander * 51*7e75ca54SJens Wiklander * [1] https://web.archive.org/web/20220616035354/https://www.riscure.com/uploads/2020/05/Riscure_Whitepaper_Fault_Mitigation_Patterns_final.pdf 52*7e75ca54SJens Wiklander */ 53*7e75ca54SJens Wiklander 54*7e75ca54SJens Wiklander #include <stdint.h> 55*7e75ca54SJens Wiklander #include <stdbool.h> 56*7e75ca54SJens Wiklander 57*7e75ca54SJens Wiklander /* 58*7e75ca54SJens Wiklander * struct ftmn_check - track current checked state 59*7e75ca54SJens Wiklander * @steps: accumulated checkpoints 60*7e75ca54SJens Wiklander * @res: last stored result or return value 61*7e75ca54SJens Wiklander * 62*7e75ca54SJens Wiklander * While a function is executed it can update its state as a way of keeping 63*7e75ca54SJens Wiklander * track of important passages inside the function. When the function 64*7e75ca54SJens Wiklander * returns with for instance ftmn_return_res() it is checked that the 65*7e75ca54SJens Wiklander * accumulated state matches the expected state. 66*7e75ca54SJens Wiklander * 67*7e75ca54SJens Wiklander * @res is xored with FTMN_DEFAULT_HASH in order to retrieve the saved 68*7e75ca54SJens Wiklander * result or return value. 69*7e75ca54SJens Wiklander */ 70*7e75ca54SJens Wiklander struct ftmn_check { 71*7e75ca54SJens Wiklander unsigned long steps; 72*7e75ca54SJens Wiklander unsigned long res; 73*7e75ca54SJens Wiklander }; 74*7e75ca54SJens Wiklander 75*7e75ca54SJens Wiklander /* 76*7e75ca54SJens Wiklander * struct ftmn_func_arg - track a called function 77*7e75ca54SJens Wiklander * @hash: xor bitmask 78*7e75ca54SJens Wiklander * @res: stored result xored with @hash 79*7e75ca54SJens Wiklander * 80*7e75ca54SJens Wiklander * When the call of a function is tracked @hash is initialized to hash of 81*7e75ca54SJens Wiklander * caller xored with hash of called function. Before the called function 82*7e75ca54SJens Wiklander * updates @res it first xors @hash with its own hash, which is supposed to 83*7e75ca54SJens Wiklander * restore @hash to the hash of the calling function. This allows the 84*7e75ca54SJens Wiklander * calling function to confirm that the correct function has been called. 85*7e75ca54SJens Wiklander */ 86*7e75ca54SJens Wiklander struct ftmn_func_arg { 87*7e75ca54SJens Wiklander unsigned long hash; 88*7e75ca54SJens Wiklander unsigned long res; 89*7e75ca54SJens Wiklander }; 90*7e75ca54SJens Wiklander 91*7e75ca54SJens Wiklander /* 92*7e75ca54SJens Wiklander * struct ftmn - link a tracked call chain 93*7e75ca54SJens Wiklander * @check: local checked state 94*7e75ca54SJens Wiklander * @arg: argument for the next called tracked function 95*7e75ca54SJens Wiklander * @saved_arg: pointer to an optional argument passed to this function 96*7e75ca54SJens Wiklander * @arg_pp: cached return value from __ftmn_get_tsd_func_arg_pp() 97*7e75ca54SJens Wiklander * @my_hash: the hash of the calling function 98*7e75ca54SJens Wiklander * @called_hash:the hash of the called function 99*7e75ca54SJens Wiklander * 100*7e75ca54SJens Wiklander * In order to maintain the linked call chain of tracked functions the 101*7e75ca54SJens Wiklander * struct ftmn_func_arg passed to this function is saved in @saved_arg 102*7e75ca54SJens Wiklander * before updating the argument pointer with @arg. 103*7e75ca54SJens Wiklander */ 104*7e75ca54SJens Wiklander struct ftmn { 105*7e75ca54SJens Wiklander struct ftmn_check check; 106*7e75ca54SJens Wiklander struct ftmn_func_arg arg; 107*7e75ca54SJens Wiklander struct ftmn_func_arg *saved_arg; 108*7e75ca54SJens Wiklander struct ftmn_func_arg **arg_pp; 109*7e75ca54SJens Wiklander unsigned long my_hash; 110*7e75ca54SJens Wiklander unsigned long called_hash; 111*7e75ca54SJens Wiklander }; 112*7e75ca54SJens Wiklander 113*7e75ca54SJens Wiklander /* 114*7e75ca54SJens Wiklander * enum ftmn_incr - increase counter values 115*7e75ca54SJens Wiklander * 116*7e75ca54SJens Wiklander * Prime numbers to be used when increasing the accumulated state. 117*7e75ca54SJens Wiklander * Different increase counters can be used to keep apart different 118*7e75ca54SJens Wiklander * checkpoints. 119*7e75ca54SJens Wiklander */ 120*7e75ca54SJens Wiklander enum ftmn_incr { 121*7e75ca54SJens Wiklander FTMN_INCR0 = 7873, 122*7e75ca54SJens Wiklander FTMN_INCR1 = 7877, 123*7e75ca54SJens Wiklander FTMN_INCR2 = 7879, 124*7e75ca54SJens Wiklander FTMN_INCR3 = 7883, 125*7e75ca54SJens Wiklander FTMN_INCR4 = 7901, 126*7e75ca54SJens Wiklander FTMN_INCR5 = 7907, 127*7e75ca54SJens Wiklander FTMN_INCR_RESERVED = 7919, 128*7e75ca54SJens Wiklander }; 129*7e75ca54SJens Wiklander 130*7e75ca54SJens Wiklander typedef int (*ftmn_memcmp_t)(const void *p1, const void *p2, size_t nb); 131*7e75ca54SJens Wiklander 132*7e75ca54SJens Wiklander /* The default hash used when xoring the result in struct ftmn_check */ 133*7e75ca54SJens Wiklander #ifdef __ILP32__ 134*7e75ca54SJens Wiklander #define FTMN_DEFAULT_HASH 0x9c478bf6UL 135*7e75ca54SJens Wiklander #else 136*7e75ca54SJens Wiklander #define FTMN_DEFAULT_HASH 0xc478bf63e9500cb5UL 137*7e75ca54SJens Wiklander #endif 138*7e75ca54SJens Wiklander 139*7e75ca54SJens Wiklander /* 140*7e75ca54SJens Wiklander * FTMN_PANIC() - FTMN specific panic function 141*7e75ca54SJens Wiklander * 142*7e75ca54SJens Wiklander * This function is called whenever the FTMN function detects an 143*7e75ca54SJens Wiklander * inconsistency. An inconsistency is able to occur if the system is 144*7e75ca54SJens Wiklander * subject to a fault injection attack, in this case doing a panic() isn't 145*7e75ca54SJens Wiklander * an extreme measure. 146*7e75ca54SJens Wiklander */ 147*7e75ca54SJens Wiklander #ifdef __KERNEL__ 148*7e75ca54SJens Wiklander #define FTMN_PANIC() panic(); 149*7e75ca54SJens Wiklander #else 150*7e75ca54SJens Wiklander #define FTMN_PANIC() TEE_Panic(0); 151*7e75ca54SJens Wiklander #endif 152*7e75ca54SJens Wiklander 153*7e75ca54SJens Wiklander #define __FTMN_MAX_FUNC_NAME_LEN 256 154*7e75ca54SJens Wiklander 155*7e75ca54SJens Wiklander #define __FTMN_FUNC_BYTE(f, o, l) ((o) < (l) ? (uint8_t)(f)[(o)] : 0) 156*7e75ca54SJens Wiklander 157*7e75ca54SJens Wiklander #define __FTMN_GET_FUNC_U64(f, o, l) \ 158*7e75ca54SJens Wiklander (SHIFT_U64(__FTMN_FUNC_BYTE((f), (o), (l)), 0) | \ 159*7e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 1, (l)), 8) | \ 160*7e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 2, (l)), 16) | \ 161*7e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 3, (l)), 24) | \ 162*7e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 4, (l)), 32) | \ 163*7e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 5, (l)), 40) | \ 164*7e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 6, (l)), 48) | \ 165*7e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 7, (l)), 56)) 166*7e75ca54SJens Wiklander 167*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH32(f, o, l) \ 168*7e75ca54SJens Wiklander (__FTMN_GET_FUNC_U64((f), (o), (l)) ^ \ 169*7e75ca54SJens Wiklander __FTMN_GET_FUNC_U64((f), (o) + 8, (l))) 170*7e75ca54SJens Wiklander 171*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH16(f, o, l) \ 172*7e75ca54SJens Wiklander (__FTMN_FUNC_HASH32((f), (o), (l)) ^ \ 173*7e75ca54SJens Wiklander __FTMN_FUNC_HASH32((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 16, (l))) 174*7e75ca54SJens Wiklander 175*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH8(f, o, l) \ 176*7e75ca54SJens Wiklander (__FTMN_FUNC_HASH16((f), (o), (l)) ^ \ 177*7e75ca54SJens Wiklander __FTMN_FUNC_HASH16((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 8, (l))) 178*7e75ca54SJens Wiklander 179*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH4(f, o, l) \ 180*7e75ca54SJens Wiklander (__FTMN_FUNC_HASH8((f), (o), (l)) ^ \ 181*7e75ca54SJens Wiklander __FTMN_FUNC_HASH8((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 4, (l))) 182*7e75ca54SJens Wiklander 183*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH2(f, l) \ 184*7e75ca54SJens Wiklander (__FTMN_FUNC_HASH4(f, 0, l) ^ \ 185*7e75ca54SJens Wiklander __FTMN_FUNC_HASH4(f, __FTMN_MAX_FUNC_NAME_LEN / 2, l)) 186*7e75ca54SJens Wiklander 187*7e75ca54SJens Wiklander #ifdef __ILP32__ 188*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH(f, l) \ 189*7e75ca54SJens Wiklander (unsigned long)(__FTMN_FUNC_HASH2((f), (l)) ^ \ 190*7e75ca54SJens Wiklander (__FTMN_FUNC_HASH2((f), (l)) >> 32)) 191*7e75ca54SJens Wiklander #else 192*7e75ca54SJens Wiklander #define __FTMN_FUNC_HASH(f, l) (unsigned long)__FTMN_FUNC_HASH2((f), (l)) 193*7e75ca54SJens Wiklander #endif 194*7e75ca54SJens Wiklander 195*7e75ca54SJens Wiklander #define __ftmn_step_count_1(c0) ((c0) * FTMN_INCR0) 196*7e75ca54SJens Wiklander #define __ftmn_step_count_2(c0, c1) \ 197*7e75ca54SJens Wiklander (__ftmn_step_count_1(c0) + (c1) * FTMN_INCR1) 198*7e75ca54SJens Wiklander #define __ftmn_step_count_3(c0, c1, c2) \ 199*7e75ca54SJens Wiklander (__ftmn_step_count_2(c0, c1) + (c2) * FTMN_INCR2) 200*7e75ca54SJens Wiklander #define __ftmn_step_count_4(c0, c1, c2, c3) \ 201*7e75ca54SJens Wiklander (__ftmn_step_count_3(c0, c1, c2) + (c3) * FTMN_INCR3) 202*7e75ca54SJens Wiklander #define __ftmn_step_count_5(c0, c1, c2, c3, c4) \ 203*7e75ca54SJens Wiklander (__ftmn_step_count_4(c0, c1, c2, c3) + (c4) * FTMN_INCR4) 204*7e75ca54SJens Wiklander #define __ftmn_step_count_6(c0, c1, c2, c3, c4, c5) \ 205*7e75ca54SJens Wiklander (__ftmn_step_count_5(c0, c1, c2, c3, c4) + (c5) * FTMN_INCR5) 206*7e75ca54SJens Wiklander #define ___ftmn_args_count(_0, _1, _2, _3, _4, _5, x, ...) x 207*7e75ca54SJens Wiklander #define __ftmn_args_count(...) \ 208*7e75ca54SJens Wiklander ___ftmn_args_count(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) 209*7e75ca54SJens Wiklander #define ___ftmn_step_count(count, ...) __ftmn_step_count_ ## count(__VA_ARGS__) 210*7e75ca54SJens Wiklander #define __ftmn_step_count(count, ...) ___ftmn_step_count(count, __VA_ARGS__) 211*7e75ca54SJens Wiklander 212*7e75ca54SJens Wiklander unsigned long ___ftmn_return_res(struct ftmn_check *check, unsigned long steps, 213*7e75ca54SJens Wiklander unsigned long res); 214*7e75ca54SJens Wiklander void ___ftmn_expect_state(struct ftmn_check *check, enum ftmn_incr incr, 215*7e75ca54SJens Wiklander unsigned long steps, unsigned long res); 216*7e75ca54SJens Wiklander 217*7e75ca54SJens Wiklander void ___ftmn_callee_done(struct ftmn_func_arg *arg, unsigned long my_hash, 218*7e75ca54SJens Wiklander unsigned long res); 219*7e75ca54SJens Wiklander void ___ftmn_callee_done_not_zero(struct ftmn_func_arg *arg, 220*7e75ca54SJens Wiklander unsigned long my_hash, 221*7e75ca54SJens Wiklander unsigned long res); 222*7e75ca54SJens Wiklander void ___ftmn_callee_done_memcmp(struct ftmn_func_arg *arg, 223*7e75ca54SJens Wiklander unsigned long my_hash, int res, 224*7e75ca54SJens Wiklander ftmn_memcmp_t my_memcmp, 225*7e75ca54SJens Wiklander const void *p1, const void *p2, size_t nb); 226*7e75ca54SJens Wiklander void ___ftmn_callee_done_check(struct ftmn_func_arg *arg, unsigned long my_hash, 227*7e75ca54SJens Wiklander struct ftmn_check *check, enum ftmn_incr incr, 228*7e75ca54SJens Wiklander unsigned long steps, unsigned long res); 229*7e75ca54SJens Wiklander 230*7e75ca54SJens Wiklander void ___ftmn_callee_update_not_zero(struct ftmn_func_arg *arg, 231*7e75ca54SJens Wiklander unsigned long res); 232*7e75ca54SJens Wiklander 233*7e75ca54SJens Wiklander void ___ftmn_set_check_res(struct ftmn_check *check, enum ftmn_incr incr, 234*7e75ca54SJens Wiklander unsigned long res); 235*7e75ca54SJens Wiklander void ___ftmn_set_check_res_not_zero(struct ftmn_check *check, 236*7e75ca54SJens Wiklander enum ftmn_incr incr, 237*7e75ca54SJens Wiklander unsigned long res); 238*7e75ca54SJens Wiklander void ___ftmn_set_check_res_memcmp(struct ftmn_check *check, enum ftmn_incr incr, 239*7e75ca54SJens Wiklander int res, ftmn_memcmp_t my_memcmp, 240*7e75ca54SJens Wiklander const void *p1, const void *p2, size_t nb); 241*7e75ca54SJens Wiklander 242*7e75ca54SJens Wiklander void ___ftmn_copy_linked_call_res(struct ftmn_check *check, enum ftmn_incr incr, 243*7e75ca54SJens Wiklander struct ftmn_func_arg *arg, unsigned long res); 244*7e75ca54SJens Wiklander 245*7e75ca54SJens Wiklander 246*7e75ca54SJens Wiklander #ifndef __KERNEL__ 247*7e75ca54SJens Wiklander extern struct ftmn_func_arg *__ftmn_global_func_arg; 248*7e75ca54SJens Wiklander #endif 249*7e75ca54SJens Wiklander 250*7e75ca54SJens Wiklander static inline struct ftmn_func_arg **__ftmn_get_tsd_func_arg_pp(void) 251*7e75ca54SJens Wiklander { 252*7e75ca54SJens Wiklander #if defined(CFG_FAULT_MITIGATION) && defined(__KERNEL__) 253*7e75ca54SJens Wiklander return &thread_get_tsd()->ftmn_arg; 254*7e75ca54SJens Wiklander #elif defined(CFG_FAULT_MITIGATION) 255*7e75ca54SJens Wiklander return &__ftmn_global_func_arg; 256*7e75ca54SJens Wiklander #else 257*7e75ca54SJens Wiklander return NULL; 258*7e75ca54SJens Wiklander #endif 259*7e75ca54SJens Wiklander } 260*7e75ca54SJens Wiklander 261*7e75ca54SJens Wiklander static inline struct ftmn_func_arg *__ftmn_get_tsd_func_arg(void) 262*7e75ca54SJens Wiklander { 263*7e75ca54SJens Wiklander struct ftmn_func_arg **pp = __ftmn_get_tsd_func_arg_pp(); 264*7e75ca54SJens Wiklander 265*7e75ca54SJens Wiklander if (!pp) 266*7e75ca54SJens Wiklander return NULL; 267*7e75ca54SJens Wiklander 268*7e75ca54SJens Wiklander return *pp; 269*7e75ca54SJens Wiklander } 270*7e75ca54SJens Wiklander 271*7e75ca54SJens Wiklander static inline void __ftmn_push_linked_call(struct ftmn *ftmn, 272*7e75ca54SJens Wiklander unsigned long my_hash, 273*7e75ca54SJens Wiklander unsigned long called_hash) 274*7e75ca54SJens Wiklander { 275*7e75ca54SJens Wiklander struct ftmn_func_arg **arg_pp = __ftmn_get_tsd_func_arg_pp(); 276*7e75ca54SJens Wiklander 277*7e75ca54SJens Wiklander if (arg_pp) { 278*7e75ca54SJens Wiklander ftmn->arg_pp = arg_pp; 279*7e75ca54SJens Wiklander ftmn->my_hash = my_hash; 280*7e75ca54SJens Wiklander ftmn->called_hash = called_hash; 281*7e75ca54SJens Wiklander ftmn->saved_arg = *ftmn->arg_pp; 282*7e75ca54SJens Wiklander *ftmn->arg_pp = &ftmn->arg; 283*7e75ca54SJens Wiklander ftmn->arg.hash = my_hash; 284*7e75ca54SJens Wiklander } 285*7e75ca54SJens Wiklander } 286*7e75ca54SJens Wiklander 287*7e75ca54SJens Wiklander static inline void __ftmn_pop_linked_call(struct ftmn *ftmn) 288*7e75ca54SJens Wiklander { 289*7e75ca54SJens Wiklander if (ftmn->arg_pp) 290*7e75ca54SJens Wiklander *ftmn->arg_pp = ftmn->saved_arg; 291*7e75ca54SJens Wiklander } 292*7e75ca54SJens Wiklander 293*7e75ca54SJens Wiklander static inline void __ftmn_copy_linked_call_res(struct ftmn *f, 294*7e75ca54SJens Wiklander enum ftmn_incr incr, 295*7e75ca54SJens Wiklander unsigned long res) 296*7e75ca54SJens Wiklander { 297*7e75ca54SJens Wiklander if (f->arg_pp) { 298*7e75ca54SJens Wiklander assert(f->arg.hash == (f->my_hash ^ f->called_hash)); 299*7e75ca54SJens Wiklander assert(&f->arg == *f->arg_pp); 300*7e75ca54SJens Wiklander assert((f->arg.hash ^ f->arg.res) == res); 301*7e75ca54SJens Wiklander ___ftmn_copy_linked_call_res(&f->check, incr, &f->arg, res); 302*7e75ca54SJens Wiklander } 303*7e75ca54SJens Wiklander } 304*7e75ca54SJens Wiklander 305*7e75ca54SJens Wiklander static inline void __ftmn_calle_swap_hash(struct ftmn_func_arg *arg, 306*7e75ca54SJens Wiklander unsigned long my_old_hash, 307*7e75ca54SJens Wiklander unsigned long my_new_hash) 308*7e75ca54SJens Wiklander { 309*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg) 310*7e75ca54SJens Wiklander arg->hash ^= my_old_hash ^ my_new_hash; 311*7e75ca54SJens Wiklander } 312*7e75ca54SJens Wiklander 313*7e75ca54SJens Wiklander static inline void __ftmn_callee_done(struct ftmn_func_arg *arg, 314*7e75ca54SJens Wiklander unsigned long my_hash, unsigned long res) 315*7e75ca54SJens Wiklander { 316*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg) 317*7e75ca54SJens Wiklander ___ftmn_callee_done(arg, my_hash, res); 318*7e75ca54SJens Wiklander } 319*7e75ca54SJens Wiklander 320*7e75ca54SJens Wiklander static inline void __ftmn_callee_done_not_zero(struct ftmn_func_arg *arg, 321*7e75ca54SJens Wiklander unsigned long hash, 322*7e75ca54SJens Wiklander unsigned long res) 323*7e75ca54SJens Wiklander { 324*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg) 325*7e75ca54SJens Wiklander ___ftmn_callee_done_not_zero(arg, hash, res); 326*7e75ca54SJens Wiklander } 327*7e75ca54SJens Wiklander 328*7e75ca54SJens Wiklander static inline int 329*7e75ca54SJens Wiklander __ftmn_callee_done_memcmp(struct ftmn_func_arg *arg, unsigned long hash, 330*7e75ca54SJens Wiklander ftmn_memcmp_t my_memcmp, 331*7e75ca54SJens Wiklander const void *p1, const void *p2, size_t nb) 332*7e75ca54SJens Wiklander { 333*7e75ca54SJens Wiklander int res = my_memcmp(p1, p2, nb); 334*7e75ca54SJens Wiklander 335*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg) 336*7e75ca54SJens Wiklander ___ftmn_callee_done_memcmp(arg, hash, res, my_memcmp, 337*7e75ca54SJens Wiklander p1, p2, nb); 338*7e75ca54SJens Wiklander 339*7e75ca54SJens Wiklander return res; 340*7e75ca54SJens Wiklander } 341*7e75ca54SJens Wiklander 342*7e75ca54SJens Wiklander static inline void __ftmn_callee_done_check(struct ftmn *ftmn, 343*7e75ca54SJens Wiklander unsigned long my_hash, 344*7e75ca54SJens Wiklander enum ftmn_incr incr, 345*7e75ca54SJens Wiklander unsigned long steps, 346*7e75ca54SJens Wiklander unsigned long res) 347*7e75ca54SJens Wiklander { 348*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) 349*7e75ca54SJens Wiklander ___ftmn_callee_done_check(__ftmn_get_tsd_func_arg(), my_hash, 350*7e75ca54SJens Wiklander &ftmn->check, incr, steps, res); 351*7e75ca54SJens Wiklander } 352*7e75ca54SJens Wiklander 353*7e75ca54SJens Wiklander static inline void __ftmn_callee_update_not_zero(struct ftmn_func_arg *arg, 354*7e75ca54SJens Wiklander unsigned long res) 355*7e75ca54SJens Wiklander { 356*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg) 357*7e75ca54SJens Wiklander ___ftmn_callee_update_not_zero(arg, res); 358*7e75ca54SJens Wiklander } 359*7e75ca54SJens Wiklander 360*7e75ca54SJens Wiklander static inline void __ftmn_set_check_res(struct ftmn *ftmn, enum ftmn_incr incr, 361*7e75ca54SJens Wiklander unsigned long res) 362*7e75ca54SJens Wiklander { 363*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) 364*7e75ca54SJens Wiklander ___ftmn_set_check_res(&ftmn->check, incr, res); 365*7e75ca54SJens Wiklander } 366*7e75ca54SJens Wiklander 367*7e75ca54SJens Wiklander static inline void __ftmn_set_check_res_not_zero(struct ftmn *ftmn, 368*7e75ca54SJens Wiklander enum ftmn_incr incr, 369*7e75ca54SJens Wiklander unsigned long res) 370*7e75ca54SJens Wiklander { 371*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) 372*7e75ca54SJens Wiklander ___ftmn_set_check_res_not_zero(&ftmn->check, incr, res); 373*7e75ca54SJens Wiklander } 374*7e75ca54SJens Wiklander 375*7e75ca54SJens Wiklander 376*7e75ca54SJens Wiklander 377*7e75ca54SJens Wiklander /* 378*7e75ca54SJens Wiklander * FTMN_FUNC_HASH() - "hash" a function name 379*7e75ca54SJens Wiklander * 380*7e75ca54SJens Wiklander * Function names are "hashed" into an unsigned long. The "hashing" is done 381*7e75ca54SJens Wiklander * by xoring each 32/64 bit word of the function name producing a bit 382*7e75ca54SJens Wiklander * pattern that should be mostly unique for each function. Only the first 383*7e75ca54SJens Wiklander * 256 characters of the name are used when xoring as this is expected to 384*7e75ca54SJens Wiklander * be optimized to be calculated when compiling the source code in order to 385*7e75ca54SJens Wiklander * minimize the overhead. 386*7e75ca54SJens Wiklander */ 387*7e75ca54SJens Wiklander #define FTMN_FUNC_HASH(name) __FTMN_FUNC_HASH(name, sizeof(name)) 388*7e75ca54SJens Wiklander 389*7e75ca54SJens Wiklander /* 390*7e75ca54SJens Wiklander * FTMN_PUSH_LINKED_CALL() - push call into a linked call chain 391*7e75ca54SJens Wiklander * @ftmn: The local struct ftmn 392*7e75ca54SJens Wiklander * @called_func_hash: The hash of the called function 393*7e75ca54SJens Wiklander * 394*7e75ca54SJens Wiklander * Inserts a call into a linked call chain or starts a new call chain if 395*7e75ca54SJens Wiklander * the passed struct ftmn_func_arg pointer was NULL. 396*7e75ca54SJens Wiklander * 397*7e75ca54SJens Wiklander * Each FTMN_PUSH_LINKED_CALL() is supposed to be matched by a 398*7e75ca54SJens Wiklander * FTMN_POP_LINKED_CALL(). 399*7e75ca54SJens Wiklander */ 400*7e75ca54SJens Wiklander #define FTMN_PUSH_LINKED_CALL(ftmn, called_func_hash) \ 401*7e75ca54SJens Wiklander __ftmn_push_linked_call((ftmn), FTMN_FUNC_HASH(__func__), \ 402*7e75ca54SJens Wiklander (called_func_hash)) 403*7e75ca54SJens Wiklander 404*7e75ca54SJens Wiklander /* 405*7e75ca54SJens Wiklander * FTMN_SET_CHECK_RES_FROM_CALL() - copy the result from a linked call 406*7e75ca54SJens Wiklander * @ftmn: The struct ftmn used during the linked call 407*7e75ca54SJens Wiklander * @incr: Value to increase the checked state with 408*7e75ca54SJens Wiklander * @res: Returned result to be match against the saved/copied result 409*7e75ca54SJens Wiklander * 410*7e75ca54SJens Wiklander * This macro is called just after a checked linked function has returned. 411*7e75ca54SJens Wiklander * The return value from the function is copied from the struct ftmn_func_arg 412*7e75ca54SJens Wiklander * passed to the called function into the local checked state. The checked 413*7e75ca54SJens Wiklander * state is increased with @incr. @res is checked against the saved result 414*7e75ca54SJens Wiklander * of the called function. 415*7e75ca54SJens Wiklander */ 416*7e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES_FROM_CALL(ftmn, incr, res) \ 417*7e75ca54SJens Wiklander __ftmn_copy_linked_call_res((ftmn), (incr), (res)) 418*7e75ca54SJens Wiklander 419*7e75ca54SJens Wiklander /* 420*7e75ca54SJens Wiklander * FTMN_POP_LINKED_CALL() - remove a call from a linked call chain 421*7e75ca54SJens Wiklander * @ftmn: The local struct ftmn 422*7e75ca54SJens Wiklander * 423*7e75ca54SJens Wiklander * Supposed to match a call to FTMN_PUSH_LINKED_CALL() 424*7e75ca54SJens Wiklander */ 425*7e75ca54SJens Wiklander #define FTMN_POP_LINKED_CALL(ftmn) __ftmn_pop_linked_call((ftmn)) 426*7e75ca54SJens Wiklander 427*7e75ca54SJens Wiklander /* 428*7e75ca54SJens Wiklander * FTMN_CALL_FUNC() - Do a linked call to a function 429*7e75ca54SJens Wiklander * @res: Variable to be assigned the result of the called function 430*7e75ca54SJens Wiklander * @ftmn: The local struct ftmn 431*7e75ca54SJens Wiklander * @incr: Value to increase the checked state with 432*7e75ca54SJens Wiklander * @func: Function to be called 433*7e75ca54SJens Wiklander * @...: Arguments to pass to @func 434*7e75ca54SJens Wiklander * 435*7e75ca54SJens Wiklander * This macro can be used to make a linked call to another function, the 436*7e75ca54SJens Wiklander * callee. This macro depends on the callee to always update the struct 437*7e75ca54SJens Wiklander * ftmn_func_arg (part of struct ftmn) even when returning an error. 438*7e75ca54SJens Wiklander * 439*7e75ca54SJens Wiklander * Note that in the cases where the callee may skip updating the struct 440*7e75ca54SJens Wiklander * ftmn_func_arg this macro cannot be used as 441*7e75ca54SJens Wiklander * FTMN_SET_CHECK_RES_FROM_CALL() would cause a panic due to mismatching 442*7e75ca54SJens Wiklander * return value and saved result. 443*7e75ca54SJens Wiklander */ 444*7e75ca54SJens Wiklander #define FTMN_CALL_FUNC(res, ftmn, incr, func, ...) \ 445*7e75ca54SJens Wiklander do { \ 446*7e75ca54SJens Wiklander FTMN_PUSH_LINKED_CALL((ftmn), FTMN_FUNC_HASH(#func)); \ 447*7e75ca54SJens Wiklander (res) = func(__VA_ARGS__); \ 448*7e75ca54SJens Wiklander FTMN_SET_CHECK_RES_FROM_CALL((ftmn), (incr), (res)); \ 449*7e75ca54SJens Wiklander FTMN_POP_LINKED_CALL((ftmn)); \ 450*7e75ca54SJens Wiklander } while (0) 451*7e75ca54SJens Wiklander 452*7e75ca54SJens Wiklander /* 453*7e75ca54SJens Wiklander * FTMN_CALLEE_DONE() - Record result of callee 454*7e75ca54SJens Wiklander * @res: Result or return value 455*7e75ca54SJens Wiklander * 456*7e75ca54SJens Wiklander * The passed result will be stored in the struct ftmn_func_arg struct 457*7e75ca54SJens Wiklander * supplied by the caller. This function must only be called once by the 458*7e75ca54SJens Wiklander * callee. 459*7e75ca54SJens Wiklander * 460*7e75ca54SJens Wiklander * Note that this function is somewhat dangerous as any passed value will 461*7e75ca54SJens Wiklander * be stored so if the value has been tampered with there is no additional 462*7e75ca54SJens Wiklander * redundant checks to rely on. 463*7e75ca54SJens Wiklander */ 464*7e75ca54SJens Wiklander #define FTMN_CALLEE_DONE(res) \ 465*7e75ca54SJens Wiklander __ftmn_callee_done(__ftmn_get_tsd_func_arg(), \ 466*7e75ca54SJens Wiklander FTMN_FUNC_HASH(__func__), (res)) 467*7e75ca54SJens Wiklander /* 468*7e75ca54SJens Wiklander * FTMN_CALLEE_DONE_NOT_ZERO() - Record non-zero result of callee 469*7e75ca54SJens Wiklander * @res: Result or return value 470*7e75ca54SJens Wiklander * 471*7e75ca54SJens Wiklander * The passed result will be stored in the struct ftmn_func_arg struct 472*7e75ca54SJens Wiklander * supplied by the caller. This function must only be called once by the 473*7e75ca54SJens Wiklander * callee. 474*7e75ca54SJens Wiklander * 475*7e75ca54SJens Wiklander * Note that this function is somewhat dangerous as any passed value will 476*7e75ca54SJens Wiklander * be stored so if the value has been tampered with there is no additional 477*7e75ca54SJens Wiklander * redundant checks to rely on. However, there are extra checks against 478*7e75ca54SJens Wiklander * unintentionally storing a zero which often is interpreted as a 479*7e75ca54SJens Wiklander * successful return value. 480*7e75ca54SJens Wiklander */ 481*7e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_NOT_ZERO(res) \ 482*7e75ca54SJens Wiklander __ftmn_callee_done_not_zero(__ftmn_get_tsd_func_arg(), \ 483*7e75ca54SJens Wiklander FTMN_FUNC_HASH(__func__), (res)) 484*7e75ca54SJens Wiklander 485*7e75ca54SJens Wiklander /* 486*7e75ca54SJens Wiklander * FTMN_CALLEE_DONE_CHECK() - Record result of callee with checked state 487*7e75ca54SJens Wiklander * @ftmn: The local struct ftmn 488*7e75ca54SJens Wiklander * @incr: Value to increase the checked state with 489*7e75ca54SJens Wiklander * @exp_steps: Expected recorded checkpoints 490*7e75ca54SJens Wiklander * @res: Result or return value 491*7e75ca54SJens Wiklander * 492*7e75ca54SJens Wiklander * The passed result will be stored in the struct ftmn_func_arg struct 493*7e75ca54SJens Wiklander * supplied by the caller. This function must only be called once by the 494*7e75ca54SJens Wiklander * callee. 495*7e75ca54SJens Wiklander * 496*7e75ca54SJens Wiklander * @res is double checked against the value stored in local checked state. 497*7e75ca54SJens Wiklander * @exp_steps is checked against the locate checked state. The local 498*7e75ca54SJens Wiklander * checked state is increased by @incr. 499*7e75ca54SJens Wiklander */ 500*7e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_CHECK(ftmn, incr, exp_steps, res) \ 501*7e75ca54SJens Wiklander __ftmn_callee_done_check((ftmn), FTMN_FUNC_HASH(__func__), \ 502*7e75ca54SJens Wiklander (incr), (exp_steps), (res)) 503*7e75ca54SJens Wiklander 504*7e75ca54SJens Wiklander /* 505*7e75ca54SJens Wiklander * FTMN_CALLEE_DONE_MEMCMP() - Record result of memcmp() in a callee 506*7e75ca54SJens Wiklander * @my_memcmp: Function pointer of custom memcmp() 507*7e75ca54SJens Wiklander * @p1: Pointer to first buffer 508*7e75ca54SJens Wiklander * @p2: Pointer to second buffer 509*7e75ca54SJens Wiklander * @nb: Number of bytes 510*7e75ca54SJens Wiklander * 511*7e75ca54SJens Wiklander * The result from the mem compare is saved in the local checked state. 512*7e75ca54SJens Wiklander * This function must only be called once by the callee. 513*7e75ca54SJens Wiklander */ 514*7e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_MEMCMP(my_memcmp, p1, p2, nb) \ 515*7e75ca54SJens Wiklander __ftmn_callee_done_memcmp(__ftmn_get_tsd_func_arg(), \ 516*7e75ca54SJens Wiklander FTMN_FUNC_HASH(__func__), (my_memcmp), \ 517*7e75ca54SJens Wiklander (p1), (p2), (nb)) 518*7e75ca54SJens Wiklander 519*7e75ca54SJens Wiklander /* 520*7e75ca54SJens Wiklander * FTMN_CALLEE_UPDATE_NOT_ZERO() - Update the result of a callee with a 521*7e75ca54SJens Wiklander * non-zero value 522*7e75ca54SJens Wiklander * @res: Result or return value 523*7e75ca54SJens Wiklander * 524*7e75ca54SJens Wiklander * The passed result will be stored in the struct ftmn_func_arg struct 525*7e75ca54SJens Wiklander * supplied by the caller. This function can be called any number of times 526*7e75ca54SJens Wiklander * by the callee, provided that one of the FTMN_CALLEE_DONE_XXX() functions 527*7e75ca54SJens Wiklander * has been called first. 528*7e75ca54SJens Wiklander * 529*7e75ca54SJens Wiklander * Note that this function is somewhat dangerous as any passed value will 530*7e75ca54SJens Wiklander * be stored so if the value has been tampered with there is no additional 531*7e75ca54SJens Wiklander * redundant checks to rely on. However, there are extra checks against 532*7e75ca54SJens Wiklander * unintentionally storing a zero which often is interpreted as a 533*7e75ca54SJens Wiklander * successful return value. 534*7e75ca54SJens Wiklander */ 535*7e75ca54SJens Wiklander #define FTMN_CALLEE_UPDATE_NOT_ZERO(res) \ 536*7e75ca54SJens Wiklander __ftmn_callee_update_not_zero(__ftmn_get_tsd_func_arg(), res) 537*7e75ca54SJens Wiklander 538*7e75ca54SJens Wiklander /* 539*7e75ca54SJens Wiklander * FTMN_CALLEE_SWAP_HASH() - Remove old hash and add new hash 540*7e75ca54SJens Wiklander * @my_old_hash: The old hash to remove 541*7e75ca54SJens Wiklander * 542*7e75ca54SJens Wiklander * This macro replaces the old expected function hash with the hash of the 543*7e75ca54SJens Wiklander * current function. 544*7e75ca54SJens Wiklander * 545*7e75ca54SJens Wiklander * If a function is called using an alias the caller uses the hash of the 546*7e75ca54SJens Wiklander * alias not the real function name. This hash is recoded in the field 547*7e75ca54SJens Wiklander * "hash" in struct ftmn_func_arg which can be found with 548*7e75ca54SJens Wiklander * __ftmn_get_tsd_func_arg(). 549*7e75ca54SJens Wiklander * 550*7e75ca54SJens Wiklander * The FTMN_CALLE_* functions only work with the real function name so the 551*7e75ca54SJens Wiklander * old hash must be removed and replaced with the new for the calling 552*7e75ca54SJens Wiklander * function to be able to verify the result. 553*7e75ca54SJens Wiklander */ 554*7e75ca54SJens Wiklander #define FTMN_CALLEE_SWAP_HASH(my_old_hash) \ 555*7e75ca54SJens Wiklander __ftmn_calle_swap_hash(__ftmn_get_tsd_func_arg(), \ 556*7e75ca54SJens Wiklander (my_old_hash), FTMN_FUNC_HASH(__func__)) 557*7e75ca54SJens Wiklander 558*7e75ca54SJens Wiklander /* 559*7e75ca54SJens Wiklander * FTMN_SET_CHECK_RES() - Records a result in local checked state 560*7e75ca54SJens Wiklander * @ftmn: The local struct ftmn 561*7e75ca54SJens Wiklander * @incr: Value to increase the checked state with 562*7e75ca54SJens Wiklander * @res: Result or return value 563*7e75ca54SJens Wiklander * 564*7e75ca54SJens Wiklander * Note that this function is somewhat dangerous as any passed value will 565*7e75ca54SJens Wiklander * be stored so if the value has been tampered with there is no additional 566*7e75ca54SJens Wiklander * redundant checks to rely on. 567*7e75ca54SJens Wiklander */ 568*7e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES(ftmn, incr, res) \ 569*7e75ca54SJens Wiklander __ftmn_set_check_res((ftmn), (incr), (res)) 570*7e75ca54SJens Wiklander 571*7e75ca54SJens Wiklander /* 572*7e75ca54SJens Wiklander * FTMN_SET_CHECK_RES_NOT_ZERO() - Records a non-zero result in local checked 573*7e75ca54SJens Wiklander * state 574*7e75ca54SJens Wiklander * @ftmn: The local struct ftmn 575*7e75ca54SJens Wiklander * @incr: Value to increase the checked state with 576*7e75ca54SJens Wiklander * @res: Result or return value 577*7e75ca54SJens Wiklander * 578*7e75ca54SJens Wiklander * Note that this function is somewhat dangerous as any passed value will 579*7e75ca54SJens Wiklander * be stored so if the value has been tampered with there is no additional 580*7e75ca54SJens Wiklander * redundant checks to rely on. However, there are extra checks against 581*7e75ca54SJens Wiklander * unintentionally storing a zero which often is interpreted as a 582*7e75ca54SJens Wiklander * successful return value. 583*7e75ca54SJens Wiklander */ 584*7e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES_NOT_ZERO(ftmn, incr, res) \ 585*7e75ca54SJens Wiklander __ftmn_set_check_res_not_zero((ftmn), (incr), (res)) 586*7e75ca54SJens Wiklander 587*7e75ca54SJens Wiklander static inline int ftmn_set_check_res_memcmp(struct ftmn *ftmn, 588*7e75ca54SJens Wiklander enum ftmn_incr incr, 589*7e75ca54SJens Wiklander ftmn_memcmp_t my_memcmp, 590*7e75ca54SJens Wiklander const void *p1, const void *p2, 591*7e75ca54SJens Wiklander size_t nb) 592*7e75ca54SJens Wiklander { 593*7e75ca54SJens Wiklander int res = my_memcmp(p1, p2, nb); 594*7e75ca54SJens Wiklander 595*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) 596*7e75ca54SJens Wiklander ___ftmn_set_check_res_memcmp(&ftmn->check, incr, res, 597*7e75ca54SJens Wiklander my_memcmp, p1, p2, nb); 598*7e75ca54SJens Wiklander 599*7e75ca54SJens Wiklander return res; 600*7e75ca54SJens Wiklander } 601*7e75ca54SJens Wiklander 602*7e75ca54SJens Wiklander /* 603*7e75ca54SJens Wiklander * FTMN_STEP_COUNT() - Calculate total step count 604*7e75ca54SJens Wiklander * 605*7e75ca54SJens Wiklander * Takes variable number of arguments, up to a total of 6. Where arg0 606*7e75ca54SJens Wiklander * is the number of times the counter has been increased by FTMN_INCR0, 607*7e75ca54SJens Wiklander * arg1 FTMN_INCR1 and so on. 608*7e75ca54SJens Wiklander */ 609*7e75ca54SJens Wiklander #define FTMN_STEP_COUNT(...) \ 610*7e75ca54SJens Wiklander __ftmn_step_count(__ftmn_args_count(__VA_ARGS__), __VA_ARGS__) 611*7e75ca54SJens Wiklander 612*7e75ca54SJens Wiklander /* 613*7e75ca54SJens Wiklander * ftmn_checkpoint() - Add a checkpoint 614*7e75ca54SJens Wiklander * @ftmn: The local struct ftmn 615*7e75ca54SJens Wiklander * @incr: Value to increase the checked state with 616*7e75ca54SJens Wiklander * 617*7e75ca54SJens Wiklander * Adds a checkpoint by increasing the internal checked state. This 618*7e75ca54SJens Wiklander * can be checked at a later point in the calling function, for instance 619*7e75ca54SJens Wiklander * with ftmn_return_res(). 620*7e75ca54SJens Wiklander */ 621*7e75ca54SJens Wiklander static inline void ftmn_checkpoint(struct ftmn *ftmn, enum ftmn_incr incr) 622*7e75ca54SJens Wiklander { 623*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) { 624*7e75ca54SJens Wiklander /* 625*7e75ca54SJens Wiklander * The purpose of the barriers is to prevent the compiler 626*7e75ca54SJens Wiklander * from optimizing this increase to some other location 627*7e75ca54SJens Wiklander * in the calling function. 628*7e75ca54SJens Wiklander */ 629*7e75ca54SJens Wiklander barrier(); 630*7e75ca54SJens Wiklander ftmn->check.steps += incr; 631*7e75ca54SJens Wiklander barrier(); 632*7e75ca54SJens Wiklander } 633*7e75ca54SJens Wiklander } 634*7e75ca54SJens Wiklander 635*7e75ca54SJens Wiklander /* 636*7e75ca54SJens Wiklander * ftmn_expect_state() - Check expected state 637*7e75ca54SJens Wiklander * @ftmn: The local struct ftmn 638*7e75ca54SJens Wiklander * @incr: Value to increase the checked state with 639*7e75ca54SJens Wiklander * @steps: Expected accumulated steps 640*7e75ca54SJens Wiklander * @res: Expected saved result or return value 641*7e75ca54SJens Wiklander * 642*7e75ca54SJens Wiklander * This is a more advanced version of ftmn_checkpoint() which before 643*7e75ca54SJens Wiklander * increasing the accumulated steps first checks the accumulated steps and 644*7e75ca54SJens Wiklander * saved result or return value. 645*7e75ca54SJens Wiklander */ 646*7e75ca54SJens Wiklander static inline void ftmn_expect_state(struct ftmn *ftmn, 647*7e75ca54SJens Wiklander enum ftmn_incr incr, unsigned long steps, 648*7e75ca54SJens Wiklander unsigned long res) 649*7e75ca54SJens Wiklander { 650*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) { 651*7e75ca54SJens Wiklander assert((ftmn->check.res ^ FTMN_DEFAULT_HASH) == res); 652*7e75ca54SJens Wiklander assert(ftmn->check.steps == steps); 653*7e75ca54SJens Wiklander 654*7e75ca54SJens Wiklander ___ftmn_expect_state(&ftmn->check, incr, steps, res); 655*7e75ca54SJens Wiklander } 656*7e75ca54SJens Wiklander } 657*7e75ca54SJens Wiklander 658*7e75ca54SJens Wiklander /* 659*7e75ca54SJens Wiklander * ftmn_return_res() - Check and return result 660*7e75ca54SJens Wiklander * @ftmn: The local struct ftmn 661*7e75ca54SJens Wiklander * @steps: Expected accumulated steps 662*7e75ca54SJens Wiklander * @res: Expected saved result or return value 663*7e75ca54SJens Wiklander * 664*7e75ca54SJens Wiklander * Checks that the internal accumulated state matches the supplied @steps 665*7e75ca54SJens Wiklander * and that the saved result or return value matches the supplied one. 666*7e75ca54SJens Wiklander * 667*7e75ca54SJens Wiklander * Returns @res. 668*7e75ca54SJens Wiklander */ 669*7e75ca54SJens Wiklander static inline unsigned long ftmn_return_res(struct ftmn *ftmn, 670*7e75ca54SJens Wiklander unsigned long steps, 671*7e75ca54SJens Wiklander unsigned long res) 672*7e75ca54SJens Wiklander { 673*7e75ca54SJens Wiklander /* 674*7e75ca54SJens Wiklander * We're expecting that the compiler does a tail call optimization 675*7e75ca54SJens Wiklander * allowing ___ftmn_return_res() to have full control over the 676*7e75ca54SJens Wiklander * returned value. Thus trying to reduce the window where the 677*7e75ca54SJens Wiklander * return value can be tampered with. 678*7e75ca54SJens Wiklander */ 679*7e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) { 680*7e75ca54SJens Wiklander assert((ftmn->check.res ^ FTMN_DEFAULT_HASH) == res); 681*7e75ca54SJens Wiklander assert(ftmn->check.steps == steps); 682*7e75ca54SJens Wiklander 683*7e75ca54SJens Wiklander return ___ftmn_return_res(&ftmn->check, steps, res); 684*7e75ca54SJens Wiklander } 685*7e75ca54SJens Wiklander return res; 686*7e75ca54SJens Wiklander } 687*7e75ca54SJens Wiklander #endif /*__FAULT_MITIGATION_H*/ 688