1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2022, Linaro Limited
4  */
5 
6 #include <compiler.h>
7 #include <fault_mitigation.h>
8 
9 #ifndef __KERNEL__
10 struct ftmn_func_arg *__ftmn_global_func_arg;
11 #endif
12 
13 /*
14  * These functions can be implemented in assembly if needed. They would
15  * provide the same API but an implementation more resilient to fault
16  * injections.
17  *
18  * For now there is no need since it's enough with the single redundancy
19  * provided just by having these function implemented separately from where
20  * they are used.
21  */
22 
___ftmn_return_res(struct ftmn_check * check,unsigned long steps,unsigned long res)23 unsigned long __weak ___ftmn_return_res(struct ftmn_check *check,
24 					unsigned long steps, unsigned long res)
25 {
26 	if (check->steps != steps)
27 		FTMN_PANIC();
28 	if ((check->res ^ FTMN_DEFAULT_HASH) != res)
29 		FTMN_PANIC();
30 	return res;
31 }
32 
___ftmn_expect_state(struct ftmn_check * check,enum ftmn_incr incr,unsigned long steps,unsigned long res)33 void __weak ___ftmn_expect_state(struct ftmn_check *check, enum ftmn_incr incr,
34 				 unsigned long steps, unsigned long res)
35 {
36 	if ((check->res ^ FTMN_DEFAULT_HASH) != res)
37 		FTMN_PANIC();
38 	if (check->steps != steps)
39 		FTMN_PANIC();
40 	check->steps += incr;
41 }
42 
___ftmn_callee_done(struct ftmn_func_arg * arg,unsigned long my_hash,unsigned long res)43 void __weak ___ftmn_callee_done(struct ftmn_func_arg *arg,
44 				unsigned long my_hash,
45 				unsigned long res)
46 {
47 	arg->hash ^= my_hash;
48 	arg->res = arg->hash ^ res;
49 }
50 
___ftmn_callee_done_not_zero(struct ftmn_func_arg * arg,unsigned long my_hash,unsigned long res)51 void __weak ___ftmn_callee_done_not_zero(struct ftmn_func_arg *arg,
52 					 unsigned long my_hash,
53 					 unsigned long res)
54 {
55 	if (res == 0)
56 		FTMN_PANIC();
57 	arg->hash ^= my_hash;
58 	arg->res = arg->hash ^ res;
59 }
60 
___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)61 void __weak ___ftmn_callee_done_memcmp(struct ftmn_func_arg *arg,
62 				       unsigned long my_hash, int res,
63 				       ftmn_memcmp_t my_memcmp,
64 					const void *p1, const void *p2,
65 					size_t nb)
66 {
67 	int res2 = 0;
68 
69 	if (!nb)
70 		FTMN_PANIC();
71 
72 	res2 = my_memcmp(p1, p2, nb);
73 	if (res2 != res)
74 		FTMN_PANIC();
75 
76 	arg->hash ^= my_hash;
77 	arg->res = arg->hash ^ res;
78 }
79 
___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)80 void __weak ___ftmn_callee_done_check(struct ftmn_func_arg *arg,
81 				      unsigned long my_hash,
82 				      struct ftmn_check *check,
83 				      enum ftmn_incr incr, unsigned long steps,
84 				      unsigned long res)
85 {
86 	if ((check->res ^ FTMN_DEFAULT_HASH) != res)
87 		FTMN_PANIC();
88 	if (check->steps != steps)
89 		FTMN_PANIC();
90 
91 	check->steps += incr;
92 	if (arg) {
93 		arg->hash ^= my_hash;
94 		arg->res = check->res ^ FTMN_DEFAULT_HASH ^ arg->hash;
95 	}
96 
97 }
98 
___ftmn_callee_update_not_zero(struct ftmn_func_arg * arg,unsigned long res)99 void ___ftmn_callee_update_not_zero(struct ftmn_func_arg *arg,
100 				    unsigned long res)
101 {
102 	if (!res)
103 		FTMN_PANIC();
104 	arg->res = arg->hash ^ res;
105 }
106 
107 
___ftmn_copy_linked_call_res(struct ftmn_check * check,enum ftmn_incr incr,struct ftmn_func_arg * arg,unsigned long res)108 void __weak ___ftmn_copy_linked_call_res(struct ftmn_check *check,
109 					 enum ftmn_incr incr,
110 					 struct ftmn_func_arg *arg,
111 					 unsigned long res)
112 {
113 	if ((arg->res ^ arg->hash) != res)
114 		FTMN_PANIC();
115 	check->res = res ^ FTMN_DEFAULT_HASH;
116 	check->steps += incr;
117 }
118 
___ftmn_set_check_res(struct ftmn_check * check,enum ftmn_incr incr,unsigned long res)119 void __weak ___ftmn_set_check_res(struct ftmn_check *check, enum ftmn_incr incr,
120 				  unsigned long res)
121 {
122 	check->steps += incr;
123 	check->res = res ^ FTMN_DEFAULT_HASH;
124 }
125 
___ftmn_set_check_res_not_zero(struct ftmn_check * check,enum ftmn_incr incr,unsigned long res)126 void __weak ___ftmn_set_check_res_not_zero(struct ftmn_check *check,
127 					   enum ftmn_incr incr,
128 					   unsigned long res)
129 {
130 	if (!res)
131 		FTMN_PANIC();
132 	check->steps += incr;
133 	check->res = res ^ FTMN_DEFAULT_HASH;
134 }
135 
___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)136 void __weak ___ftmn_set_check_res_memcmp(struct ftmn_check *check,
137 					 enum ftmn_incr incr, int res,
138 					 ftmn_memcmp_t my_memcmp,
139 					 const void *p1, const void *p2,
140 					 size_t nb)
141 {
142 	int res2 = 0;
143 
144 	if (!nb)
145 		FTMN_PANIC();
146 
147 	res2 = my_memcmp(p1, p2, nb);
148 	if (res2 != res)
149 		FTMN_PANIC();
150 
151 	check->steps += incr;
152 	check->res = FTMN_DEFAULT_HASH ^ res;
153 }
154