1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2022, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <fault_mitigation.h>
8 #include <initcall.h>
9 #include <kernel/thread.h>
10 #include <trace.h>
11 #include <types_ext.h>
12 
13 /*
14  * Simple straightforward tests.
15  */
16 static TEE_Result simple_call_func_res;
17 
simple_call_func1(void)18 static TEE_Result __noinline simple_call_func1(void)
19 {
20 	TEE_Result res = simple_call_func_res;
21 
22 	FTMN_CALLEE_DONE(res);
23 	return res;
24 }
25 
simple_call_memcmp(const void * s1,const void * s2,size_t n)26 static TEE_Result __noinline simple_call_memcmp(const void *s1, const void *s2,
27 						size_t n)
28 {
29 	if (!FTMN_CALLEE_DONE_MEMCMP(memcmp, s1, s2, n))
30 		return TEE_SUCCESS;
31 	return TEE_ERROR_GENERIC;
32 }
33 
simple_call(void)34 static void __noinline simple_call(void)
35 {
36 	TEE_Result res = TEE_SUCCESS;
37 	struct ftmn ftmn = { };
38 	static const char s1[] = "s1";
39 
40 	simple_call_func_res = TEE_SUCCESS;
41 	FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0, simple_call_func1);
42 	ftmn_expect_state(&ftmn, FTMN_INCR1, FTMN_STEP_COUNT(1), res);
43 
44 	simple_call_func_res = TEE_ERROR_GENERIC;
45 	FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0, simple_call_func1);
46 	ftmn_expect_state(&ftmn, FTMN_INCR1, FTMN_STEP_COUNT(2, 1), res);
47 
48 	FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0,
49 		       simple_call_memcmp, s1, s1, sizeof(s1));
50 	ftmn_expect_state(&ftmn, FTMN_INCR1, FTMN_STEP_COUNT(3, 2), res);
51 }
52 
53 /*
54  * Simulate calling with multiple unmitigated functions in the chain
55  * between checked callee and the caller. The result has always been set
56  * regardless of return value.
57  */
58 
two_level_call_memcmp2(const void * s1,const void * s2,size_t n)59 static TEE_Result __noinline two_level_call_memcmp2(const void *s1,
60 						    const void *s2, size_t n)
61 {
62 	if (!FTMN_CALLEE_DONE_MEMCMP(memcmp, s1, s2, n))
63 		return TEE_SUCCESS;
64 	/*
65 	 * If FTMN_CALLEE_DONE_MEMCMP() returned non-zero the strings are
66 	 * different. Update with an error code we can understand.
67 	 */
68 	FTMN_CALLEE_UPDATE_NOT_ZERO(TEE_ERROR_GENERIC);
69 	return TEE_ERROR_GENERIC;
70 }
71 
two_level_call_memcmp1(const void * s1,const void * s2,size_t n)72 static TEE_Result __noinline two_level_call_memcmp1(const void *s1,
73 						    const void *s2, size_t n)
74 {
75 	return two_level_call_memcmp2(s1, s2, n);
76 }
77 
two_level_call_memcmp(const void * s1,const void * s2,size_t n)78 static TEE_Result __noinline two_level_call_memcmp(const void *s1,
79 						   const void *s2, size_t n)
80 {
81 	unsigned long func_hash = FTMN_FUNC_HASH("two_level_call_memcmp2");
82 	struct ftmn ftmn = { };
83 	TEE_Result res = TEE_SUCCESS;
84 
85 	FTMN_PUSH_LINKED_CALL(&ftmn, func_hash);
86 	res = two_level_call_memcmp1(s1, s2, n);
87 	FTMN_SET_CHECK_RES_FROM_CALL(&ftmn, 0, res);
88 	FTMN_POP_LINKED_CALL(&ftmn);
89 	FTMN_CALLEE_DONE_CHECK(&ftmn, FTMN_INCR1, 0, res);
90 
91 	return res;
92 }
93 
two_level_call(void)94 static void __noinline two_level_call(void)
95 {
96 	struct ftmn ftmn = { };
97 	TEE_Result res = TEE_SUCCESS;
98 	static const char s1[] = "s1";
99 	static const char s2[] = "s2";
100 
101 	FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0,
102 		       two_level_call_memcmp, s1, s1, sizeof(s1));
103 	ftmn_expect_state(&ftmn, FTMN_INCR1, FTMN_STEP_COUNT(1), res);
104 
105 	FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0,
106 		       two_level_call_memcmp, s1, s2, sizeof(s1));
107 	ftmn_expect_state(&ftmn, FTMN_INCR1, FTMN_STEP_COUNT(2, 1), res);
108 }
109 
110 /*
111  * Simulate chained calls in several levels.
112  *
113  * For instance ree_fs_ta_open() -> shdr_verify_signature() ->
114  * crypto_acipher_rsassa_verify() -> ... ->
115  * mbedtls_rsa_rsassa_pss_verify_ext()
116  */
117 
chained_call_memcmp2(const void * s1,const void * s2,size_t n)118 static TEE_Result __noinline chained_call_memcmp2(const void *s1,
119 						  const void *s2, size_t n)
120 {
121 	if (!FTMN_CALLEE_DONE_MEMCMP(memcmp, s1, s2, n))
122 		return TEE_SUCCESS;
123 	return TEE_ERROR_GENERIC;
124 }
125 
chained_call_memcmp1(const void * s1,const void * s2,size_t n)126 static TEE_Result __noinline chained_call_memcmp1(const void *s1,
127 						  const void *s2, size_t n)
128 {
129 	TEE_Result res = chained_call_memcmp2(s1, s2, n);
130 
131 	/*
132 	 * If s1 and s2 has the same content but different pointers we're
133 	 * testing the case with an error detected after the linked leaf
134 	 * function has been called.
135 	 */
136 	if (!res && s1 != s2)
137 		res = TEE_ERROR_BAD_STATE;
138 
139 	return res;
140 }
141 
chained_call_memcmp(const void * s1,const void * s2,size_t n)142 static TEE_Result __noinline chained_call_memcmp(const void *s1,
143 						 const void *s2, size_t n)
144 {
145 	struct ftmn ftmn = { };
146 	TEE_Result res = TEE_SUCCESS;
147 
148 	FTMN_PUSH_LINKED_CALL(&ftmn, FTMN_FUNC_HASH("chained_call_memcmp2"));
149 
150 	res = chained_call_memcmp1(s1, s2, n);
151 
152 	if (!res)
153 		FTMN_SET_CHECK_RES_FROM_CALL(&ftmn, FTMN_INCR0, res);
154 	else
155 		FTMN_SET_CHECK_RES(&ftmn, FTMN_INCR0, res);
156 	FTMN_POP_LINKED_CALL(&ftmn);
157 	FTMN_CALLEE_DONE_CHECK(&ftmn, FTMN_INCR0, FTMN_STEP_COUNT(1), res);
158 
159 	return res;
160 }
161 
chained_calls(void)162 static void __noinline chained_calls(void)
163 {
164 	struct ftmn ftmn = { };
165 	static const char s[] = "s1s2s1";
166 	TEE_Result res = TEE_SUCCESS;
167 
168 	/* Test a normal success case. */
169 	FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0, chained_call_memcmp, s, s, 2);
170 	ftmn_expect_state(&ftmn, FTMN_INCR1, FTMN_STEP_COUNT(1), res);
171 
172 	/* Test the case where the leaf function detects an error. */
173 	FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0,
174 		       chained_call_memcmp, s, s + 2, 2);
175 	assert(res == TEE_ERROR_GENERIC);
176 	ftmn_expect_state(&ftmn, FTMN_INCR1, FTMN_STEP_COUNT(2, 1),
177 			  TEE_ERROR_GENERIC);
178 
179 	/*
180 	 * Test the case where a function in the call chain detects an error
181 	 * after a the leaf function has returned success.
182 	 */
183 	FTMN_CALL_FUNC(res, &ftmn, FTMN_INCR0,
184 		       chained_call_memcmp, s, s + 4, 2);
185 	assert(res == TEE_ERROR_BAD_STATE);
186 	ftmn_expect_state(&ftmn, FTMN_INCR1, FTMN_STEP_COUNT(3, 2),
187 			  TEE_ERROR_BAD_STATE);
188 }
189 
190 #define CALL_TEST_FUNC(x) do { \
191 		DMSG("Calling " #x "()"); \
192 		x(); \
193 		DMSG("Return from " #x "()"); \
194 	} while (0)
195 
ftmn_boot_tests(void)196 static TEE_Result ftmn_boot_tests(void)
197 {
198 	CALL_TEST_FUNC(simple_call);
199 	CALL_TEST_FUNC(two_level_call);
200 	CALL_TEST_FUNC(chained_calls);
201 
202 	DMSG("*************************************************");
203 	DMSG("**************  Tests complete  *****************");
204 	DMSG("*************************************************");
205 	return TEE_SUCCESS;
206 }
207 
208 driver_init_late(ftmn_boot_tests);
209