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