17e75ca54SJens Wiklander /* SPDX-License-Identifier: BSD-2-Clause */ 27e75ca54SJens Wiklander /* 37e75ca54SJens Wiklander * Copyright (c) 2022, Linaro Limited 47e75ca54SJens Wiklander */ 57e75ca54SJens Wiklander #ifndef __FAULT_MITIGATION_H 67e75ca54SJens Wiklander #define __FAULT_MITIGATION_H 77e75ca54SJens Wiklander 87e75ca54SJens Wiklander #include <assert.h> 97e75ca54SJens Wiklander #include <config.h> 107e75ca54SJens Wiklander #include <string.h> 117e75ca54SJens Wiklander #include <util.h> 127e75ca54SJens Wiklander 137e75ca54SJens Wiklander #ifdef __KERNEL__ 147e75ca54SJens Wiklander #include <kernel/panic.h> 157e75ca54SJens Wiklander #include <kernel/thread.h> 167e75ca54SJens Wiklander #else 177e75ca54SJens Wiklander #include <tee_api.h> 187e75ca54SJens Wiklander #endif 197e75ca54SJens Wiklander 207e75ca54SJens Wiklander /* 217e75ca54SJens Wiklander * Fault migitigation helpers to make successful Hardware Fault Attacks 227e75ca54SJens Wiklander * harder to achieve. The paper [1] by Riscure gives background to the 237e75ca54SJens Wiklander * problem. 247e75ca54SJens Wiklander * 257e75ca54SJens Wiklander * These helpers aim to make it hard for a single glitch attack to succeed 267e75ca54SJens Wiklander * while the protected function or one of the ftmn_*() functions are 277e75ca54SJens Wiklander * executed. 287e75ca54SJens Wiklander * 297e75ca54SJens Wiklander * To have something to work with we assume that a single glitch may affect 307e75ca54SJens Wiklander * a few instructions in sequence to do nothing or to corrupt the content 317e75ca54SJens Wiklander * of a few registers. 327e75ca54SJens Wiklander * 337e75ca54SJens Wiklander * Using the terminology from [1] we are implementing the following patterns: 347e75ca54SJens Wiklander * 3 FAULT.VALUE.CHECK 357e75ca54SJens Wiklander * 5 FAULT.DECISION.CHECK 367e75ca54SJens Wiklander * 9 FAULT.FLOW.CONTROL 377e75ca54SJens Wiklander * 387e75ca54SJens Wiklander * Additionally are the following patterns also acknowledged with a few 397e75ca54SJens Wiklander * comments: 407e75ca54SJens Wiklander * 1. FAULT.CONSTANT.CODING 417e75ca54SJens Wiklander * Zero is normally a success code in OP-TEE so special functions are 427e75ca54SJens Wiklander * added to record anything but a zero result. 437e75ca54SJens Wiklander * 8. FAULT.NESTED.CHECK 447e75ca54SJens Wiklander * The linked calls performed by for instance FTMN_CALL_FUNC() addresses 457e75ca54SJens Wiklander * this by relying on the called function to update a state in 467e75ca54SJens Wiklander * struct ftmn_func_arg which is checked when the function has returned. 477e75ca54SJens Wiklander * 11. FAULT.PENALTY 487e75ca54SJens Wiklander * This is implicit since we're normally trying to protect things post 497e75ca54SJens Wiklander * boot and booting takes quite some time. 507e75ca54SJens Wiklander * 517e75ca54SJens Wiklander * [1] https://web.archive.org/web/20220616035354/https://www.riscure.com/uploads/2020/05/Riscure_Whitepaper_Fault_Mitigation_Patterns_final.pdf 527e75ca54SJens Wiklander */ 537e75ca54SJens Wiklander 547e75ca54SJens Wiklander #include <stdint.h> 557e75ca54SJens Wiklander #include <stdbool.h> 567e75ca54SJens Wiklander 577e75ca54SJens Wiklander /* 587e75ca54SJens Wiklander * struct ftmn_check - track current checked state 597e75ca54SJens Wiklander * @steps: accumulated checkpoints 607e75ca54SJens Wiklander * @res: last stored result or return value 617e75ca54SJens Wiklander * 627e75ca54SJens Wiklander * While a function is executed it can update its state as a way of keeping 637e75ca54SJens Wiklander * track of important passages inside the function. When the function 647e75ca54SJens Wiklander * returns with for instance ftmn_return_res() it is checked that the 657e75ca54SJens Wiklander * accumulated state matches the expected state. 667e75ca54SJens Wiklander * 677e75ca54SJens Wiklander * @res is xored with FTMN_DEFAULT_HASH in order to retrieve the saved 687e75ca54SJens Wiklander * result or return value. 697e75ca54SJens Wiklander */ 707e75ca54SJens Wiklander struct ftmn_check { 717e75ca54SJens Wiklander unsigned long steps; 727e75ca54SJens Wiklander unsigned long res; 737e75ca54SJens Wiklander }; 747e75ca54SJens Wiklander 757e75ca54SJens Wiklander /* 767e75ca54SJens Wiklander * struct ftmn_func_arg - track a called function 777e75ca54SJens Wiklander * @hash: xor bitmask 787e75ca54SJens Wiklander * @res: stored result xored with @hash 797e75ca54SJens Wiklander * 807e75ca54SJens Wiklander * When the call of a function is tracked @hash is initialized to hash of 817e75ca54SJens Wiklander * caller xored with hash of called function. Before the called function 827e75ca54SJens Wiklander * updates @res it first xors @hash with its own hash, which is supposed to 837e75ca54SJens Wiklander * restore @hash to the hash of the calling function. This allows the 847e75ca54SJens Wiklander * calling function to confirm that the correct function has been called. 857e75ca54SJens Wiklander */ 867e75ca54SJens Wiklander struct ftmn_func_arg { 877e75ca54SJens Wiklander unsigned long hash; 887e75ca54SJens Wiklander unsigned long res; 897e75ca54SJens Wiklander }; 907e75ca54SJens Wiklander 917e75ca54SJens Wiklander /* 927e75ca54SJens Wiklander * struct ftmn - link a tracked call chain 937e75ca54SJens Wiklander * @check: local checked state 947e75ca54SJens Wiklander * @arg: argument for the next called tracked function 957e75ca54SJens Wiklander * @saved_arg: pointer to an optional argument passed to this function 967e75ca54SJens Wiklander * @arg_pp: cached return value from __ftmn_get_tsd_func_arg_pp() 977e75ca54SJens Wiklander * @my_hash: the hash of the calling function 987e75ca54SJens Wiklander * @called_hash:the hash of the called function 997e75ca54SJens Wiklander * 1007e75ca54SJens Wiklander * In order to maintain the linked call chain of tracked functions the 1017e75ca54SJens Wiklander * struct ftmn_func_arg passed to this function is saved in @saved_arg 1027e75ca54SJens Wiklander * before updating the argument pointer with @arg. 1037e75ca54SJens Wiklander */ 1047e75ca54SJens Wiklander struct ftmn { 1057e75ca54SJens Wiklander struct ftmn_check check; 1067e75ca54SJens Wiklander struct ftmn_func_arg arg; 1077e75ca54SJens Wiklander struct ftmn_func_arg *saved_arg; 1087e75ca54SJens Wiklander struct ftmn_func_arg **arg_pp; 1097e75ca54SJens Wiklander unsigned long my_hash; 1107e75ca54SJens Wiklander unsigned long called_hash; 1117e75ca54SJens Wiklander }; 1127e75ca54SJens Wiklander 1137e75ca54SJens Wiklander /* 1147e75ca54SJens Wiklander * enum ftmn_incr - increase counter values 1157e75ca54SJens Wiklander * 1167e75ca54SJens Wiklander * Prime numbers to be used when increasing the accumulated state. 1177e75ca54SJens Wiklander * Different increase counters can be used to keep apart different 1187e75ca54SJens Wiklander * checkpoints. 1197e75ca54SJens Wiklander */ 1207e75ca54SJens Wiklander enum ftmn_incr { 1217e75ca54SJens Wiklander FTMN_INCR0 = 7873, 1227e75ca54SJens Wiklander FTMN_INCR1 = 7877, 1237e75ca54SJens Wiklander FTMN_INCR2 = 7879, 1247e75ca54SJens Wiklander FTMN_INCR3 = 7883, 1257e75ca54SJens Wiklander FTMN_INCR4 = 7901, 1267e75ca54SJens Wiklander FTMN_INCR5 = 7907, 1277e75ca54SJens Wiklander FTMN_INCR_RESERVED = 7919, 1287e75ca54SJens Wiklander }; 1297e75ca54SJens Wiklander 1307e75ca54SJens Wiklander typedef int (*ftmn_memcmp_t)(const void *p1, const void *p2, size_t nb); 1317e75ca54SJens Wiklander 1327e75ca54SJens Wiklander /* The default hash used when xoring the result in struct ftmn_check */ 1337e75ca54SJens Wiklander #ifdef __ILP32__ 1347e75ca54SJens Wiklander #define FTMN_DEFAULT_HASH 0x9c478bf6UL 1357e75ca54SJens Wiklander #else 1367e75ca54SJens Wiklander #define FTMN_DEFAULT_HASH 0xc478bf63e9500cb5UL 1377e75ca54SJens Wiklander #endif 1387e75ca54SJens Wiklander 1397e75ca54SJens Wiklander /* 1407e75ca54SJens Wiklander * FTMN_PANIC() - FTMN specific panic function 1417e75ca54SJens Wiklander * 1427e75ca54SJens Wiklander * This function is called whenever the FTMN function detects an 1437e75ca54SJens Wiklander * inconsistency. An inconsistency is able to occur if the system is 1447e75ca54SJens Wiklander * subject to a fault injection attack, in this case doing a panic() isn't 1457e75ca54SJens Wiklander * an extreme measure. 1467e75ca54SJens Wiklander */ 1477e75ca54SJens Wiklander #ifdef __KERNEL__ 1487e75ca54SJens Wiklander #define FTMN_PANIC() panic(); 1497e75ca54SJens Wiklander #else 1507e75ca54SJens Wiklander #define FTMN_PANIC() TEE_Panic(0); 1517e75ca54SJens Wiklander #endif 1527e75ca54SJens Wiklander 1537e75ca54SJens Wiklander #define __FTMN_MAX_FUNC_NAME_LEN 256 1547e75ca54SJens Wiklander 1557e75ca54SJens Wiklander #define __FTMN_FUNC_BYTE(f, o, l) ((o) < (l) ? (uint8_t)(f)[(o)] : 0) 1567e75ca54SJens Wiklander 1577e75ca54SJens Wiklander #define __FTMN_GET_FUNC_U64(f, o, l) \ 1587e75ca54SJens Wiklander (SHIFT_U64(__FTMN_FUNC_BYTE((f), (o), (l)), 0) | \ 1597e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 1, (l)), 8) | \ 1607e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 2, (l)), 16) | \ 1617e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 3, (l)), 24) | \ 1627e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 4, (l)), 32) | \ 1637e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 5, (l)), 40) | \ 1647e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 6, (l)), 48) | \ 1657e75ca54SJens Wiklander SHIFT_U64(__FTMN_FUNC_BYTE((f), (o) + 7, (l)), 56)) 1667e75ca54SJens Wiklander 1677e75ca54SJens Wiklander #define __FTMN_FUNC_HASH32(f, o, l) \ 1687e75ca54SJens Wiklander (__FTMN_GET_FUNC_U64((f), (o), (l)) ^ \ 1697e75ca54SJens Wiklander __FTMN_GET_FUNC_U64((f), (o) + 8, (l))) 1707e75ca54SJens Wiklander 1717e75ca54SJens Wiklander #define __FTMN_FUNC_HASH16(f, o, l) \ 1727e75ca54SJens Wiklander (__FTMN_FUNC_HASH32((f), (o), (l)) ^ \ 1737e75ca54SJens Wiklander __FTMN_FUNC_HASH32((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 16, (l))) 1747e75ca54SJens Wiklander 1757e75ca54SJens Wiklander #define __FTMN_FUNC_HASH8(f, o, l) \ 1767e75ca54SJens Wiklander (__FTMN_FUNC_HASH16((f), (o), (l)) ^ \ 1777e75ca54SJens Wiklander __FTMN_FUNC_HASH16((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 8, (l))) 1787e75ca54SJens Wiklander 1797e75ca54SJens Wiklander #define __FTMN_FUNC_HASH4(f, o, l) \ 1807e75ca54SJens Wiklander (__FTMN_FUNC_HASH8((f), (o), (l)) ^ \ 1817e75ca54SJens Wiklander __FTMN_FUNC_HASH8((f), (o) + __FTMN_MAX_FUNC_NAME_LEN / 4, (l))) 1827e75ca54SJens Wiklander 1837e75ca54SJens Wiklander #define __FTMN_FUNC_HASH2(f, l) \ 1847e75ca54SJens Wiklander (__FTMN_FUNC_HASH4(f, 0, l) ^ \ 1857e75ca54SJens Wiklander __FTMN_FUNC_HASH4(f, __FTMN_MAX_FUNC_NAME_LEN / 2, l)) 1867e75ca54SJens Wiklander 1877e75ca54SJens Wiklander #ifdef __ILP32__ 1887e75ca54SJens Wiklander #define __FTMN_FUNC_HASH(f, l) \ 1897e75ca54SJens Wiklander (unsigned long)(__FTMN_FUNC_HASH2((f), (l)) ^ \ 1907e75ca54SJens Wiklander (__FTMN_FUNC_HASH2((f), (l)) >> 32)) 1917e75ca54SJens Wiklander #else 1927e75ca54SJens Wiklander #define __FTMN_FUNC_HASH(f, l) (unsigned long)__FTMN_FUNC_HASH2((f), (l)) 1937e75ca54SJens Wiklander #endif 1947e75ca54SJens Wiklander 1957e75ca54SJens Wiklander #define __ftmn_step_count_1(c0) ((c0) * FTMN_INCR0) 1967e75ca54SJens Wiklander #define __ftmn_step_count_2(c0, c1) \ 1977e75ca54SJens Wiklander (__ftmn_step_count_1(c0) + (c1) * FTMN_INCR1) 1987e75ca54SJens Wiklander #define __ftmn_step_count_3(c0, c1, c2) \ 1997e75ca54SJens Wiklander (__ftmn_step_count_2(c0, c1) + (c2) * FTMN_INCR2) 2007e75ca54SJens Wiklander #define __ftmn_step_count_4(c0, c1, c2, c3) \ 2017e75ca54SJens Wiklander (__ftmn_step_count_3(c0, c1, c2) + (c3) * FTMN_INCR3) 2027e75ca54SJens Wiklander #define __ftmn_step_count_5(c0, c1, c2, c3, c4) \ 2037e75ca54SJens Wiklander (__ftmn_step_count_4(c0, c1, c2, c3) + (c4) * FTMN_INCR4) 2047e75ca54SJens Wiklander #define __ftmn_step_count_6(c0, c1, c2, c3, c4, c5) \ 2057e75ca54SJens Wiklander (__ftmn_step_count_5(c0, c1, c2, c3, c4) + (c5) * FTMN_INCR5) 2067e75ca54SJens Wiklander #define ___ftmn_args_count(_0, _1, _2, _3, _4, _5, x, ...) x 2077e75ca54SJens Wiklander #define __ftmn_args_count(...) \ 2087e75ca54SJens Wiklander ___ftmn_args_count(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) 2097e75ca54SJens Wiklander #define ___ftmn_step_count(count, ...) __ftmn_step_count_ ## count(__VA_ARGS__) 2107e75ca54SJens Wiklander #define __ftmn_step_count(count, ...) ___ftmn_step_count(count, __VA_ARGS__) 2117e75ca54SJens Wiklander 2127e75ca54SJens Wiklander unsigned long ___ftmn_return_res(struct ftmn_check *check, unsigned long steps, 2137e75ca54SJens Wiklander unsigned long res); 2147e75ca54SJens Wiklander void ___ftmn_expect_state(struct ftmn_check *check, enum ftmn_incr incr, 2157e75ca54SJens Wiklander unsigned long steps, unsigned long res); 2167e75ca54SJens Wiklander 2177e75ca54SJens Wiklander void ___ftmn_callee_done(struct ftmn_func_arg *arg, unsigned long my_hash, 2187e75ca54SJens Wiklander unsigned long res); 2197e75ca54SJens Wiklander void ___ftmn_callee_done_not_zero(struct ftmn_func_arg *arg, 2207e75ca54SJens Wiklander unsigned long my_hash, 2217e75ca54SJens Wiklander unsigned long res); 2227e75ca54SJens Wiklander void ___ftmn_callee_done_memcmp(struct ftmn_func_arg *arg, 2237e75ca54SJens Wiklander unsigned long my_hash, int res, 2247e75ca54SJens Wiklander ftmn_memcmp_t my_memcmp, 2257e75ca54SJens Wiklander const void *p1, const void *p2, size_t nb); 2267e75ca54SJens Wiklander void ___ftmn_callee_done_check(struct ftmn_func_arg *arg, unsigned long my_hash, 2277e75ca54SJens Wiklander struct ftmn_check *check, enum ftmn_incr incr, 2287e75ca54SJens Wiklander unsigned long steps, unsigned long res); 2297e75ca54SJens Wiklander 2307e75ca54SJens Wiklander void ___ftmn_callee_update_not_zero(struct ftmn_func_arg *arg, 2317e75ca54SJens Wiklander unsigned long res); 2327e75ca54SJens Wiklander 2337e75ca54SJens Wiklander void ___ftmn_set_check_res(struct ftmn_check *check, enum ftmn_incr incr, 2347e75ca54SJens Wiklander unsigned long res); 2357e75ca54SJens Wiklander void ___ftmn_set_check_res_not_zero(struct ftmn_check *check, 2367e75ca54SJens Wiklander enum ftmn_incr incr, 2377e75ca54SJens Wiklander unsigned long res); 2387e75ca54SJens Wiklander void ___ftmn_set_check_res_memcmp(struct ftmn_check *check, enum ftmn_incr incr, 2397e75ca54SJens Wiklander int res, ftmn_memcmp_t my_memcmp, 2407e75ca54SJens Wiklander const void *p1, const void *p2, size_t nb); 2417e75ca54SJens Wiklander 2427e75ca54SJens Wiklander void ___ftmn_copy_linked_call_res(struct ftmn_check *check, enum ftmn_incr incr, 2437e75ca54SJens Wiklander struct ftmn_func_arg *arg, unsigned long res); 2447e75ca54SJens Wiklander 2457e75ca54SJens Wiklander 2467e75ca54SJens Wiklander #ifndef __KERNEL__ 2477e75ca54SJens Wiklander extern struct ftmn_func_arg *__ftmn_global_func_arg; 2487e75ca54SJens Wiklander #endif 2497e75ca54SJens Wiklander 2507e75ca54SJens Wiklander static inline struct ftmn_func_arg **__ftmn_get_tsd_func_arg_pp(void) 2517e75ca54SJens Wiklander { 2527e75ca54SJens Wiklander #if defined(CFG_FAULT_MITIGATION) && defined(__KERNEL__) 253*ce56605aSSichun Qin if (thread_get_id_may_fail() >= 0) 2547e75ca54SJens Wiklander return &thread_get_tsd()->ftmn_arg; 255*ce56605aSSichun Qin else 256*ce56605aSSichun Qin return &thread_get_core_local()->ftmn_arg; 2577e75ca54SJens Wiklander #elif defined(CFG_FAULT_MITIGATION) 2587e75ca54SJens Wiklander return &__ftmn_global_func_arg; 2597e75ca54SJens Wiklander #else 2607e75ca54SJens Wiklander return NULL; 2617e75ca54SJens Wiklander #endif 2627e75ca54SJens Wiklander } 2637e75ca54SJens Wiklander 2647e75ca54SJens Wiklander static inline struct ftmn_func_arg *__ftmn_get_tsd_func_arg(void) 2657e75ca54SJens Wiklander { 2667e75ca54SJens Wiklander struct ftmn_func_arg **pp = __ftmn_get_tsd_func_arg_pp(); 2677e75ca54SJens Wiklander 2687e75ca54SJens Wiklander if (!pp) 2697e75ca54SJens Wiklander return NULL; 2707e75ca54SJens Wiklander 2717e75ca54SJens Wiklander return *pp; 2727e75ca54SJens Wiklander } 2737e75ca54SJens Wiklander 2747e75ca54SJens Wiklander static inline void __ftmn_push_linked_call(struct ftmn *ftmn, 2757e75ca54SJens Wiklander unsigned long my_hash, 2767e75ca54SJens Wiklander unsigned long called_hash) 2777e75ca54SJens Wiklander { 2787e75ca54SJens Wiklander struct ftmn_func_arg **arg_pp = __ftmn_get_tsd_func_arg_pp(); 2797e75ca54SJens Wiklander 2807e75ca54SJens Wiklander if (arg_pp) { 2817e75ca54SJens Wiklander ftmn->arg_pp = arg_pp; 2827e75ca54SJens Wiklander ftmn->my_hash = my_hash; 2837e75ca54SJens Wiklander ftmn->called_hash = called_hash; 2847e75ca54SJens Wiklander ftmn->saved_arg = *ftmn->arg_pp; 2857e75ca54SJens Wiklander *ftmn->arg_pp = &ftmn->arg; 2867e75ca54SJens Wiklander ftmn->arg.hash = my_hash; 2877e75ca54SJens Wiklander } 2887e75ca54SJens Wiklander } 2897e75ca54SJens Wiklander 2907e75ca54SJens Wiklander static inline void __ftmn_pop_linked_call(struct ftmn *ftmn) 2917e75ca54SJens Wiklander { 2927e75ca54SJens Wiklander if (ftmn->arg_pp) 2937e75ca54SJens Wiklander *ftmn->arg_pp = ftmn->saved_arg; 2947e75ca54SJens Wiklander } 2957e75ca54SJens Wiklander 2967e75ca54SJens Wiklander static inline void __ftmn_copy_linked_call_res(struct ftmn *f, 2977e75ca54SJens Wiklander enum ftmn_incr incr, 2987e75ca54SJens Wiklander unsigned long res) 2997e75ca54SJens Wiklander { 3007e75ca54SJens Wiklander if (f->arg_pp) { 3017e75ca54SJens Wiklander assert(f->arg.hash == (f->my_hash ^ f->called_hash)); 3027e75ca54SJens Wiklander assert(&f->arg == *f->arg_pp); 3037e75ca54SJens Wiklander assert((f->arg.hash ^ f->arg.res) == res); 3047e75ca54SJens Wiklander ___ftmn_copy_linked_call_res(&f->check, incr, &f->arg, res); 3057e75ca54SJens Wiklander } 3067e75ca54SJens Wiklander } 3077e75ca54SJens Wiklander 3087e75ca54SJens Wiklander static inline void __ftmn_calle_swap_hash(struct ftmn_func_arg *arg, 3097e75ca54SJens Wiklander unsigned long my_old_hash, 3107e75ca54SJens Wiklander unsigned long my_new_hash) 3117e75ca54SJens Wiklander { 3127e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg) 3137e75ca54SJens Wiklander arg->hash ^= my_old_hash ^ my_new_hash; 3147e75ca54SJens Wiklander } 3157e75ca54SJens Wiklander 3167e75ca54SJens Wiklander static inline void __ftmn_callee_done(struct ftmn_func_arg *arg, 3177e75ca54SJens Wiklander unsigned long my_hash, unsigned long res) 3187e75ca54SJens Wiklander { 3197e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg) 3207e75ca54SJens Wiklander ___ftmn_callee_done(arg, my_hash, res); 3217e75ca54SJens Wiklander } 3227e75ca54SJens Wiklander 3237e75ca54SJens Wiklander static inline void __ftmn_callee_done_not_zero(struct ftmn_func_arg *arg, 3247e75ca54SJens Wiklander unsigned long hash, 3257e75ca54SJens Wiklander unsigned long res) 3267e75ca54SJens Wiklander { 3277e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg) 3287e75ca54SJens Wiklander ___ftmn_callee_done_not_zero(arg, hash, res); 3297e75ca54SJens Wiklander } 3307e75ca54SJens Wiklander 3317e75ca54SJens Wiklander static inline int 3327e75ca54SJens Wiklander __ftmn_callee_done_memcmp(struct ftmn_func_arg *arg, unsigned long hash, 3337e75ca54SJens Wiklander ftmn_memcmp_t my_memcmp, 3347e75ca54SJens Wiklander const void *p1, const void *p2, size_t nb) 3357e75ca54SJens Wiklander { 3367e75ca54SJens Wiklander int res = my_memcmp(p1, p2, nb); 3377e75ca54SJens Wiklander 3387e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg) 3397e75ca54SJens Wiklander ___ftmn_callee_done_memcmp(arg, hash, res, my_memcmp, 3407e75ca54SJens Wiklander p1, p2, nb); 3417e75ca54SJens Wiklander 3427e75ca54SJens Wiklander return res; 3437e75ca54SJens Wiklander } 3447e75ca54SJens Wiklander 3457e75ca54SJens Wiklander static inline void __ftmn_callee_done_check(struct ftmn *ftmn, 3467e75ca54SJens Wiklander unsigned long my_hash, 3477e75ca54SJens Wiklander enum ftmn_incr incr, 3487e75ca54SJens Wiklander unsigned long steps, 3497e75ca54SJens Wiklander unsigned long res) 3507e75ca54SJens Wiklander { 3517e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) 3527e75ca54SJens Wiklander ___ftmn_callee_done_check(__ftmn_get_tsd_func_arg(), my_hash, 3537e75ca54SJens Wiklander &ftmn->check, incr, steps, res); 3547e75ca54SJens Wiklander } 3557e75ca54SJens Wiklander 3567e75ca54SJens Wiklander static inline void __ftmn_callee_update_not_zero(struct ftmn_func_arg *arg, 3577e75ca54SJens Wiklander unsigned long res) 3587e75ca54SJens Wiklander { 3597e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION) && arg) 3607e75ca54SJens Wiklander ___ftmn_callee_update_not_zero(arg, res); 3617e75ca54SJens Wiklander } 3627e75ca54SJens Wiklander 3637e75ca54SJens Wiklander static inline void __ftmn_set_check_res(struct ftmn *ftmn, enum ftmn_incr incr, 3647e75ca54SJens Wiklander unsigned long res) 3657e75ca54SJens Wiklander { 3667e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) 3677e75ca54SJens Wiklander ___ftmn_set_check_res(&ftmn->check, incr, res); 3687e75ca54SJens Wiklander } 3697e75ca54SJens Wiklander 3707e75ca54SJens Wiklander static inline void __ftmn_set_check_res_not_zero(struct ftmn *ftmn, 3717e75ca54SJens Wiklander enum ftmn_incr incr, 3727e75ca54SJens Wiklander unsigned long res) 3737e75ca54SJens Wiklander { 3747e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) 3757e75ca54SJens Wiklander ___ftmn_set_check_res_not_zero(&ftmn->check, incr, res); 3767e75ca54SJens Wiklander } 3777e75ca54SJens Wiklander 3787e75ca54SJens Wiklander 3797e75ca54SJens Wiklander 3807e75ca54SJens Wiklander /* 3817e75ca54SJens Wiklander * FTMN_FUNC_HASH() - "hash" a function name 3827e75ca54SJens Wiklander * 3837e75ca54SJens Wiklander * Function names are "hashed" into an unsigned long. The "hashing" is done 3847e75ca54SJens Wiklander * by xoring each 32/64 bit word of the function name producing a bit 3857e75ca54SJens Wiklander * pattern that should be mostly unique for each function. Only the first 3867e75ca54SJens Wiklander * 256 characters of the name are used when xoring as this is expected to 3877e75ca54SJens Wiklander * be optimized to be calculated when compiling the source code in order to 3887e75ca54SJens Wiklander * minimize the overhead. 3897e75ca54SJens Wiklander */ 3907e75ca54SJens Wiklander #define FTMN_FUNC_HASH(name) __FTMN_FUNC_HASH(name, sizeof(name)) 3917e75ca54SJens Wiklander 3927e75ca54SJens Wiklander /* 3937e75ca54SJens Wiklander * FTMN_PUSH_LINKED_CALL() - push call into a linked call chain 3947e75ca54SJens Wiklander * @ftmn: The local struct ftmn 3957e75ca54SJens Wiklander * @called_func_hash: The hash of the called function 3967e75ca54SJens Wiklander * 3977e75ca54SJens Wiklander * Inserts a call into a linked call chain or starts a new call chain if 3987e75ca54SJens Wiklander * the passed struct ftmn_func_arg pointer was NULL. 3997e75ca54SJens Wiklander * 4007e75ca54SJens Wiklander * Each FTMN_PUSH_LINKED_CALL() is supposed to be matched by a 4017e75ca54SJens Wiklander * FTMN_POP_LINKED_CALL(). 4027e75ca54SJens Wiklander */ 4037e75ca54SJens Wiklander #define FTMN_PUSH_LINKED_CALL(ftmn, called_func_hash) \ 4047e75ca54SJens Wiklander __ftmn_push_linked_call((ftmn), FTMN_FUNC_HASH(__func__), \ 4057e75ca54SJens Wiklander (called_func_hash)) 4067e75ca54SJens Wiklander 4077e75ca54SJens Wiklander /* 4087e75ca54SJens Wiklander * FTMN_SET_CHECK_RES_FROM_CALL() - copy the result from a linked call 4097e75ca54SJens Wiklander * @ftmn: The struct ftmn used during the linked call 4107e75ca54SJens Wiklander * @incr: Value to increase the checked state with 4117e75ca54SJens Wiklander * @res: Returned result to be match against the saved/copied result 4127e75ca54SJens Wiklander * 4137e75ca54SJens Wiklander * This macro is called just after a checked linked function has returned. 4147e75ca54SJens Wiklander * The return value from the function is copied from the struct ftmn_func_arg 4157e75ca54SJens Wiklander * passed to the called function into the local checked state. The checked 4167e75ca54SJens Wiklander * state is increased with @incr. @res is checked against the saved result 4177e75ca54SJens Wiklander * of the called function. 4187e75ca54SJens Wiklander */ 4197e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES_FROM_CALL(ftmn, incr, res) \ 4207e75ca54SJens Wiklander __ftmn_copy_linked_call_res((ftmn), (incr), (res)) 4217e75ca54SJens Wiklander 4227e75ca54SJens Wiklander /* 4237e75ca54SJens Wiklander * FTMN_POP_LINKED_CALL() - remove a call from a linked call chain 4247e75ca54SJens Wiklander * @ftmn: The local struct ftmn 4257e75ca54SJens Wiklander * 4267e75ca54SJens Wiklander * Supposed to match a call to FTMN_PUSH_LINKED_CALL() 4277e75ca54SJens Wiklander */ 4287e75ca54SJens Wiklander #define FTMN_POP_LINKED_CALL(ftmn) __ftmn_pop_linked_call((ftmn)) 4297e75ca54SJens Wiklander 4307e75ca54SJens Wiklander /* 4317e75ca54SJens Wiklander * FTMN_CALL_FUNC() - Do a linked call to a function 4327e75ca54SJens Wiklander * @res: Variable to be assigned the result of the called function 4337e75ca54SJens Wiklander * @ftmn: The local struct ftmn 4347e75ca54SJens Wiklander * @incr: Value to increase the checked state with 4357e75ca54SJens Wiklander * @func: Function to be called 4367e75ca54SJens Wiklander * @...: Arguments to pass to @func 4377e75ca54SJens Wiklander * 4387e75ca54SJens Wiklander * This macro can be used to make a linked call to another function, the 4397e75ca54SJens Wiklander * callee. This macro depends on the callee to always update the struct 4407e75ca54SJens Wiklander * ftmn_func_arg (part of struct ftmn) even when returning an error. 4417e75ca54SJens Wiklander * 4427e75ca54SJens Wiklander * Note that in the cases where the callee may skip updating the struct 4437e75ca54SJens Wiklander * ftmn_func_arg this macro cannot be used as 4447e75ca54SJens Wiklander * FTMN_SET_CHECK_RES_FROM_CALL() would cause a panic due to mismatching 4457e75ca54SJens Wiklander * return value and saved result. 4467e75ca54SJens Wiklander */ 4477e75ca54SJens Wiklander #define FTMN_CALL_FUNC(res, ftmn, incr, func, ...) \ 4487e75ca54SJens Wiklander do { \ 4497e75ca54SJens Wiklander FTMN_PUSH_LINKED_CALL((ftmn), FTMN_FUNC_HASH(#func)); \ 4507e75ca54SJens Wiklander (res) = func(__VA_ARGS__); \ 4517e75ca54SJens Wiklander FTMN_SET_CHECK_RES_FROM_CALL((ftmn), (incr), (res)); \ 4527e75ca54SJens Wiklander FTMN_POP_LINKED_CALL((ftmn)); \ 4537e75ca54SJens Wiklander } while (0) 4547e75ca54SJens Wiklander 4557e75ca54SJens Wiklander /* 4567e75ca54SJens Wiklander * FTMN_CALLEE_DONE() - Record result of callee 4577e75ca54SJens Wiklander * @res: Result or return value 4587e75ca54SJens Wiklander * 4597e75ca54SJens Wiklander * The passed result will be stored in the struct ftmn_func_arg struct 4607e75ca54SJens Wiklander * supplied by the caller. This function must only be called once by the 4617e75ca54SJens Wiklander * callee. 4627e75ca54SJens Wiklander * 4637e75ca54SJens Wiklander * Note that this function is somewhat dangerous as any passed value will 4647e75ca54SJens Wiklander * be stored so if the value has been tampered with there is no additional 4657e75ca54SJens Wiklander * redundant checks to rely on. 4667e75ca54SJens Wiklander */ 4677e75ca54SJens Wiklander #define FTMN_CALLEE_DONE(res) \ 4687e75ca54SJens Wiklander __ftmn_callee_done(__ftmn_get_tsd_func_arg(), \ 4697e75ca54SJens Wiklander FTMN_FUNC_HASH(__func__), (res)) 4707e75ca54SJens Wiklander /* 4717e75ca54SJens Wiklander * FTMN_CALLEE_DONE_NOT_ZERO() - Record non-zero result of callee 4727e75ca54SJens Wiklander * @res: Result or return value 4737e75ca54SJens Wiklander * 4747e75ca54SJens Wiklander * The passed result will be stored in the struct ftmn_func_arg struct 4757e75ca54SJens Wiklander * supplied by the caller. This function must only be called once by the 4767e75ca54SJens Wiklander * callee. 4777e75ca54SJens Wiklander * 4787e75ca54SJens Wiklander * Note that this function is somewhat dangerous as any passed value will 4797e75ca54SJens Wiklander * be stored so if the value has been tampered with there is no additional 4807e75ca54SJens Wiklander * redundant checks to rely on. However, there are extra checks against 4817e75ca54SJens Wiklander * unintentionally storing a zero which often is interpreted as a 4827e75ca54SJens Wiklander * successful return value. 4837e75ca54SJens Wiklander */ 4847e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_NOT_ZERO(res) \ 4857e75ca54SJens Wiklander __ftmn_callee_done_not_zero(__ftmn_get_tsd_func_arg(), \ 4867e75ca54SJens Wiklander FTMN_FUNC_HASH(__func__), (res)) 4877e75ca54SJens Wiklander 4887e75ca54SJens Wiklander /* 4897e75ca54SJens Wiklander * FTMN_CALLEE_DONE_CHECK() - Record result of callee with checked state 4907e75ca54SJens Wiklander * @ftmn: The local struct ftmn 4917e75ca54SJens Wiklander * @incr: Value to increase the checked state with 4927e75ca54SJens Wiklander * @exp_steps: Expected recorded checkpoints 4937e75ca54SJens Wiklander * @res: Result or return value 4947e75ca54SJens Wiklander * 4957e75ca54SJens Wiklander * The passed result will be stored in the struct ftmn_func_arg struct 4967e75ca54SJens Wiklander * supplied by the caller. This function must only be called once by the 4977e75ca54SJens Wiklander * callee. 4987e75ca54SJens Wiklander * 4997e75ca54SJens Wiklander * @res is double checked against the value stored in local checked state. 5007e75ca54SJens Wiklander * @exp_steps is checked against the locate checked state. The local 5017e75ca54SJens Wiklander * checked state is increased by @incr. 5027e75ca54SJens Wiklander */ 5037e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_CHECK(ftmn, incr, exp_steps, res) \ 5047e75ca54SJens Wiklander __ftmn_callee_done_check((ftmn), FTMN_FUNC_HASH(__func__), \ 5057e75ca54SJens Wiklander (incr), (exp_steps), (res)) 5067e75ca54SJens Wiklander 5077e75ca54SJens Wiklander /* 5087e75ca54SJens Wiklander * FTMN_CALLEE_DONE_MEMCMP() - Record result of memcmp() in a callee 5097e75ca54SJens Wiklander * @my_memcmp: Function pointer of custom memcmp() 5107e75ca54SJens Wiklander * @p1: Pointer to first buffer 5117e75ca54SJens Wiklander * @p2: Pointer to second buffer 5127e75ca54SJens Wiklander * @nb: Number of bytes 5137e75ca54SJens Wiklander * 5147e75ca54SJens Wiklander * The result from the mem compare is saved in the local checked state. 5157e75ca54SJens Wiklander * This function must only be called once by the callee. 5167e75ca54SJens Wiklander */ 5177e75ca54SJens Wiklander #define FTMN_CALLEE_DONE_MEMCMP(my_memcmp, p1, p2, nb) \ 5187e75ca54SJens Wiklander __ftmn_callee_done_memcmp(__ftmn_get_tsd_func_arg(), \ 5197e75ca54SJens Wiklander FTMN_FUNC_HASH(__func__), (my_memcmp), \ 5207e75ca54SJens Wiklander (p1), (p2), (nb)) 5217e75ca54SJens Wiklander 5227e75ca54SJens Wiklander /* 5237e75ca54SJens Wiklander * FTMN_CALLEE_UPDATE_NOT_ZERO() - Update the result of a callee with a 5247e75ca54SJens Wiklander * non-zero value 5257e75ca54SJens Wiklander * @res: Result or return value 5267e75ca54SJens Wiklander * 5277e75ca54SJens Wiklander * The passed result will be stored in the struct ftmn_func_arg struct 5287e75ca54SJens Wiklander * supplied by the caller. This function can be called any number of times 5297e75ca54SJens Wiklander * by the callee, provided that one of the FTMN_CALLEE_DONE_XXX() functions 5307e75ca54SJens Wiklander * has been called first. 5317e75ca54SJens Wiklander * 5327e75ca54SJens Wiklander * Note that this function is somewhat dangerous as any passed value will 5337e75ca54SJens Wiklander * be stored so if the value has been tampered with there is no additional 5347e75ca54SJens Wiklander * redundant checks to rely on. However, there are extra checks against 5357e75ca54SJens Wiklander * unintentionally storing a zero which often is interpreted as a 5367e75ca54SJens Wiklander * successful return value. 5377e75ca54SJens Wiklander */ 5387e75ca54SJens Wiklander #define FTMN_CALLEE_UPDATE_NOT_ZERO(res) \ 5397e75ca54SJens Wiklander __ftmn_callee_update_not_zero(__ftmn_get_tsd_func_arg(), res) 5407e75ca54SJens Wiklander 5417e75ca54SJens Wiklander /* 5427e75ca54SJens Wiklander * FTMN_CALLEE_SWAP_HASH() - Remove old hash and add new hash 5437e75ca54SJens Wiklander * @my_old_hash: The old hash to remove 5447e75ca54SJens Wiklander * 5457e75ca54SJens Wiklander * This macro replaces the old expected function hash with the hash of the 5467e75ca54SJens Wiklander * current function. 5477e75ca54SJens Wiklander * 5487e75ca54SJens Wiklander * If a function is called using an alias the caller uses the hash of the 5497e75ca54SJens Wiklander * alias not the real function name. This hash is recoded in the field 5507e75ca54SJens Wiklander * "hash" in struct ftmn_func_arg which can be found with 5517e75ca54SJens Wiklander * __ftmn_get_tsd_func_arg(). 5527e75ca54SJens Wiklander * 5537e75ca54SJens Wiklander * The FTMN_CALLE_* functions only work with the real function name so the 5547e75ca54SJens Wiklander * old hash must be removed and replaced with the new for the calling 5557e75ca54SJens Wiklander * function to be able to verify the result. 5567e75ca54SJens Wiklander */ 5577e75ca54SJens Wiklander #define FTMN_CALLEE_SWAP_HASH(my_old_hash) \ 5587e75ca54SJens Wiklander __ftmn_calle_swap_hash(__ftmn_get_tsd_func_arg(), \ 5597e75ca54SJens Wiklander (my_old_hash), FTMN_FUNC_HASH(__func__)) 5607e75ca54SJens Wiklander 5617e75ca54SJens Wiklander /* 5627e75ca54SJens Wiklander * FTMN_SET_CHECK_RES() - Records a result in local checked state 5637e75ca54SJens Wiklander * @ftmn: The local struct ftmn 5647e75ca54SJens Wiklander * @incr: Value to increase the checked state with 5657e75ca54SJens Wiklander * @res: Result or return value 5667e75ca54SJens Wiklander * 5677e75ca54SJens Wiklander * Note that this function is somewhat dangerous as any passed value will 5687e75ca54SJens Wiklander * be stored so if the value has been tampered with there is no additional 5697e75ca54SJens Wiklander * redundant checks to rely on. 5707e75ca54SJens Wiklander */ 5717e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES(ftmn, incr, res) \ 5727e75ca54SJens Wiklander __ftmn_set_check_res((ftmn), (incr), (res)) 5737e75ca54SJens Wiklander 5747e75ca54SJens Wiklander /* 5757e75ca54SJens Wiklander * FTMN_SET_CHECK_RES_NOT_ZERO() - Records a non-zero result in local checked 5767e75ca54SJens Wiklander * state 5777e75ca54SJens Wiklander * @ftmn: The local struct ftmn 5787e75ca54SJens Wiklander * @incr: Value to increase the checked state with 5797e75ca54SJens Wiklander * @res: Result or return value 5807e75ca54SJens Wiklander * 5817e75ca54SJens Wiklander * Note that this function is somewhat dangerous as any passed value will 5827e75ca54SJens Wiklander * be stored so if the value has been tampered with there is no additional 5837e75ca54SJens Wiklander * redundant checks to rely on. However, there are extra checks against 5847e75ca54SJens Wiklander * unintentionally storing a zero which often is interpreted as a 5857e75ca54SJens Wiklander * successful return value. 5867e75ca54SJens Wiklander */ 5877e75ca54SJens Wiklander #define FTMN_SET_CHECK_RES_NOT_ZERO(ftmn, incr, res) \ 5887e75ca54SJens Wiklander __ftmn_set_check_res_not_zero((ftmn), (incr), (res)) 5897e75ca54SJens Wiklander 5907e75ca54SJens Wiklander static inline int ftmn_set_check_res_memcmp(struct ftmn *ftmn, 5917e75ca54SJens Wiklander enum ftmn_incr incr, 5927e75ca54SJens Wiklander ftmn_memcmp_t my_memcmp, 5937e75ca54SJens Wiklander const void *p1, const void *p2, 5947e75ca54SJens Wiklander size_t nb) 5957e75ca54SJens Wiklander { 5967e75ca54SJens Wiklander int res = my_memcmp(p1, p2, nb); 5977e75ca54SJens Wiklander 5987e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) 5997e75ca54SJens Wiklander ___ftmn_set_check_res_memcmp(&ftmn->check, incr, res, 6007e75ca54SJens Wiklander my_memcmp, p1, p2, nb); 6017e75ca54SJens Wiklander 6027e75ca54SJens Wiklander return res; 6037e75ca54SJens Wiklander } 6047e75ca54SJens Wiklander 6057e75ca54SJens Wiklander /* 6067e75ca54SJens Wiklander * FTMN_STEP_COUNT() - Calculate total step count 6077e75ca54SJens Wiklander * 6087e75ca54SJens Wiklander * Takes variable number of arguments, up to a total of 6. Where arg0 6097e75ca54SJens Wiklander * is the number of times the counter has been increased by FTMN_INCR0, 6107e75ca54SJens Wiklander * arg1 FTMN_INCR1 and so on. 6117e75ca54SJens Wiklander */ 6127e75ca54SJens Wiklander #define FTMN_STEP_COUNT(...) \ 6137e75ca54SJens Wiklander __ftmn_step_count(__ftmn_args_count(__VA_ARGS__), __VA_ARGS__) 6147e75ca54SJens Wiklander 6157e75ca54SJens Wiklander /* 6167e75ca54SJens Wiklander * ftmn_checkpoint() - Add a checkpoint 6177e75ca54SJens Wiklander * @ftmn: The local struct ftmn 6187e75ca54SJens Wiklander * @incr: Value to increase the checked state with 6197e75ca54SJens Wiklander * 6207e75ca54SJens Wiklander * Adds a checkpoint by increasing the internal checked state. This 6217e75ca54SJens Wiklander * can be checked at a later point in the calling function, for instance 6227e75ca54SJens Wiklander * with ftmn_return_res(). 6237e75ca54SJens Wiklander */ 6247e75ca54SJens Wiklander static inline void ftmn_checkpoint(struct ftmn *ftmn, enum ftmn_incr incr) 6257e75ca54SJens Wiklander { 6267e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) { 6277e75ca54SJens Wiklander /* 6287e75ca54SJens Wiklander * The purpose of the barriers is to prevent the compiler 6297e75ca54SJens Wiklander * from optimizing this increase to some other location 6307e75ca54SJens Wiklander * in the calling function. 6317e75ca54SJens Wiklander */ 6327e75ca54SJens Wiklander barrier(); 6337e75ca54SJens Wiklander ftmn->check.steps += incr; 6347e75ca54SJens Wiklander barrier(); 6357e75ca54SJens Wiklander } 6367e75ca54SJens Wiklander } 6377e75ca54SJens Wiklander 6387e75ca54SJens Wiklander /* 6397e75ca54SJens Wiklander * ftmn_expect_state() - Check expected state 6407e75ca54SJens Wiklander * @ftmn: The local struct ftmn 6417e75ca54SJens Wiklander * @incr: Value to increase the checked state with 6427e75ca54SJens Wiklander * @steps: Expected accumulated steps 6437e75ca54SJens Wiklander * @res: Expected saved result or return value 6447e75ca54SJens Wiklander * 6457e75ca54SJens Wiklander * This is a more advanced version of ftmn_checkpoint() which before 6467e75ca54SJens Wiklander * increasing the accumulated steps first checks the accumulated steps and 6477e75ca54SJens Wiklander * saved result or return value. 6487e75ca54SJens Wiklander */ 6497e75ca54SJens Wiklander static inline void ftmn_expect_state(struct ftmn *ftmn, 6507e75ca54SJens Wiklander enum ftmn_incr incr, unsigned long steps, 6517e75ca54SJens Wiklander unsigned long res) 6527e75ca54SJens Wiklander { 6537e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) { 6547e75ca54SJens Wiklander assert((ftmn->check.res ^ FTMN_DEFAULT_HASH) == res); 6557e75ca54SJens Wiklander assert(ftmn->check.steps == steps); 6567e75ca54SJens Wiklander 6577e75ca54SJens Wiklander ___ftmn_expect_state(&ftmn->check, incr, steps, res); 6587e75ca54SJens Wiklander } 6597e75ca54SJens Wiklander } 6607e75ca54SJens Wiklander 6617e75ca54SJens Wiklander /* 6627e75ca54SJens Wiklander * ftmn_return_res() - Check and return result 6637e75ca54SJens Wiklander * @ftmn: The local struct ftmn 6647e75ca54SJens Wiklander * @steps: Expected accumulated steps 6657e75ca54SJens Wiklander * @res: Expected saved result or return value 6667e75ca54SJens Wiklander * 6677e75ca54SJens Wiklander * Checks that the internal accumulated state matches the supplied @steps 6687e75ca54SJens Wiklander * and that the saved result or return value matches the supplied one. 6697e75ca54SJens Wiklander * 6707e75ca54SJens Wiklander * Returns @res. 6717e75ca54SJens Wiklander */ 6727e75ca54SJens Wiklander static inline unsigned long ftmn_return_res(struct ftmn *ftmn, 6737e75ca54SJens Wiklander unsigned long steps, 6747e75ca54SJens Wiklander unsigned long res) 6757e75ca54SJens Wiklander { 6767e75ca54SJens Wiklander /* 6777e75ca54SJens Wiklander * We're expecting that the compiler does a tail call optimization 6787e75ca54SJens Wiklander * allowing ___ftmn_return_res() to have full control over the 6797e75ca54SJens Wiklander * returned value. Thus trying to reduce the window where the 6807e75ca54SJens Wiklander * return value can be tampered with. 6817e75ca54SJens Wiklander */ 6827e75ca54SJens Wiklander if (IS_ENABLED(CFG_FAULT_MITIGATION)) { 6837e75ca54SJens Wiklander assert((ftmn->check.res ^ FTMN_DEFAULT_HASH) == res); 6847e75ca54SJens Wiklander assert(ftmn->check.steps == steps); 6857e75ca54SJens Wiklander 6867e75ca54SJens Wiklander return ___ftmn_return_res(&ftmn->check, steps, res); 6877e75ca54SJens Wiklander } 6887e75ca54SJens Wiklander return res; 6897e75ca54SJens Wiklander } 6907e75ca54SJens Wiklander #endif /*__FAULT_MITIGATION_H*/ 691