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 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 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 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 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 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 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 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 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 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 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 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 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