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