1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2014-2022, Linaro Limited 4 * Copyright (c) 2020, Arm Limited 5 */ 6 7 #include <assert.h> 8 #include <kernel/abort.h> 9 #include <kernel/arch_scall.h> 10 #include <kernel/ldelf_syscalls.h> 11 #include <kernel/misc.h> 12 #include <kernel/panic.h> 13 #include <kernel/scall.h> 14 #include <kernel/tee_ta_manager.h> 15 #include <kernel/thread.h> 16 #include <kernel/trace_ta.h> 17 #include <kernel/user_ta.h> 18 #include <ldelf.h> 19 #include <mm/vm.h> 20 #include <speculation_barrier.h> 21 #include <string.h> 22 #include <tee/svc_cache.h> 23 #include <tee_syscall_numbers.h> 24 #include <tee/tee_svc_cryp.h> 25 #include <tee/tee_svc.h> 26 #include <tee/tee_svc_storage.h> 27 #include <trace.h> 28 #include <util.h> 29 30 #if (TRACE_LEVEL == TRACE_FLOW) && defined(CFG_TEE_CORE_TA_TRACE) 31 #define TRACE_SYSCALLS 32 #endif 33 34 struct syscall_entry { 35 syscall_t fn; 36 #ifdef TRACE_SYSCALLS 37 const char *name; 38 #endif 39 }; 40 41 #ifdef TRACE_SYSCALLS 42 #define SYSCALL_ENTRY(_fn) { .fn = (syscall_t)_fn, .name = #_fn } 43 #else 44 #define SYSCALL_ENTRY(_fn) { .fn = (syscall_t)_fn } 45 #endif 46 47 /* 48 * This array is ordered according to the SYSCALL ids TEE_SCN_xxx 49 */ 50 static const struct syscall_entry tee_syscall_table[] = { 51 SYSCALL_ENTRY(syscall_sys_return), 52 SYSCALL_ENTRY(syscall_log), 53 SYSCALL_ENTRY(syscall_panic), 54 SYSCALL_ENTRY(syscall_get_property), 55 SYSCALL_ENTRY(syscall_get_property_name_to_index), 56 SYSCALL_ENTRY(syscall_open_ta_session), 57 SYSCALL_ENTRY(syscall_close_ta_session), 58 SYSCALL_ENTRY(syscall_invoke_ta_command), 59 SYSCALL_ENTRY(syscall_check_access_rights), 60 SYSCALL_ENTRY(syscall_get_cancellation_flag), 61 SYSCALL_ENTRY(syscall_unmask_cancellation), 62 SYSCALL_ENTRY(syscall_mask_cancellation), 63 SYSCALL_ENTRY(syscall_wait), 64 SYSCALL_ENTRY(syscall_get_time), 65 SYSCALL_ENTRY(syscall_set_ta_time), 66 SYSCALL_ENTRY(syscall_cryp_state_alloc), 67 SYSCALL_ENTRY(syscall_cryp_state_copy), 68 SYSCALL_ENTRY(syscall_cryp_state_free), 69 SYSCALL_ENTRY(syscall_hash_init), 70 SYSCALL_ENTRY(syscall_hash_update), 71 SYSCALL_ENTRY(syscall_hash_final), 72 SYSCALL_ENTRY(syscall_cipher_init), 73 SYSCALL_ENTRY(syscall_cipher_update), 74 SYSCALL_ENTRY(syscall_cipher_final), 75 SYSCALL_ENTRY(syscall_cryp_obj_get_info), 76 SYSCALL_ENTRY(syscall_cryp_obj_restrict_usage), 77 SYSCALL_ENTRY(syscall_cryp_obj_get_attr), 78 SYSCALL_ENTRY(syscall_cryp_obj_alloc), 79 SYSCALL_ENTRY(syscall_cryp_obj_close), 80 SYSCALL_ENTRY(syscall_cryp_obj_reset), 81 SYSCALL_ENTRY(syscall_cryp_obj_populate), 82 SYSCALL_ENTRY(syscall_cryp_obj_copy), 83 SYSCALL_ENTRY(syscall_cryp_derive_key), 84 SYSCALL_ENTRY(syscall_cryp_random_number_generate), 85 SYSCALL_ENTRY(syscall_authenc_init), 86 SYSCALL_ENTRY(syscall_authenc_update_aad), 87 SYSCALL_ENTRY(syscall_authenc_update_payload), 88 SYSCALL_ENTRY(syscall_authenc_enc_final), 89 SYSCALL_ENTRY(syscall_authenc_dec_final), 90 SYSCALL_ENTRY(syscall_asymm_operate), 91 SYSCALL_ENTRY(syscall_asymm_verify), 92 SYSCALL_ENTRY(syscall_storage_obj_open), 93 SYSCALL_ENTRY(syscall_storage_obj_create), 94 SYSCALL_ENTRY(syscall_storage_obj_del), 95 SYSCALL_ENTRY(syscall_storage_obj_rename), 96 SYSCALL_ENTRY(syscall_storage_alloc_enum), 97 SYSCALL_ENTRY(syscall_storage_free_enum), 98 SYSCALL_ENTRY(syscall_storage_reset_enum), 99 SYSCALL_ENTRY(syscall_storage_start_enum), 100 SYSCALL_ENTRY(syscall_storage_next_enum), 101 SYSCALL_ENTRY(syscall_storage_obj_read), 102 SYSCALL_ENTRY(syscall_storage_obj_write), 103 SYSCALL_ENTRY(syscall_storage_obj_trunc), 104 SYSCALL_ENTRY(syscall_storage_obj_seek), 105 SYSCALL_ENTRY(syscall_obj_generate_key), 106 SYSCALL_ENTRY(syscall_not_supported), 107 SYSCALL_ENTRY(syscall_not_supported), 108 SYSCALL_ENTRY(syscall_not_supported), 109 SYSCALL_ENTRY(syscall_not_supported), 110 SYSCALL_ENTRY(syscall_not_supported), 111 SYSCALL_ENTRY(syscall_not_supported), 112 SYSCALL_ENTRY(syscall_not_supported), 113 SYSCALL_ENTRY(syscall_not_supported), 114 SYSCALL_ENTRY(syscall_not_supported), 115 SYSCALL_ENTRY(syscall_not_supported), 116 SYSCALL_ENTRY(syscall_not_supported), 117 SYSCALL_ENTRY(syscall_not_supported), 118 SYSCALL_ENTRY(syscall_not_supported), 119 SYSCALL_ENTRY(syscall_not_supported), 120 SYSCALL_ENTRY(syscall_not_supported), 121 SYSCALL_ENTRY(syscall_cache_operation), 122 }; 123 124 /* 125 * The ldelf return, log, panic syscalls have the same functionality and syscall 126 * number as the user TAs'. To avoid unnecessary code duplication, the ldelf SVC 127 * handler doesn't implement separate functions for these. 128 */ 129 static const struct syscall_entry ldelf_syscall_table[] = { 130 SYSCALL_ENTRY(syscall_sys_return), 131 SYSCALL_ENTRY(syscall_log), 132 SYSCALL_ENTRY(syscall_panic), 133 SYSCALL_ENTRY(ldelf_syscall_map_zi), 134 SYSCALL_ENTRY(ldelf_syscall_unmap), 135 SYSCALL_ENTRY(ldelf_syscall_open_bin), 136 SYSCALL_ENTRY(ldelf_syscall_close_bin), 137 SYSCALL_ENTRY(ldelf_syscall_map_bin), 138 SYSCALL_ENTRY(ldelf_syscall_copy_from_bin), 139 SYSCALL_ENTRY(ldelf_syscall_set_prot), 140 SYSCALL_ENTRY(ldelf_syscall_remap), 141 SYSCALL_ENTRY(ldelf_syscall_gen_rnd_num), 142 }; 143 144 #ifdef TRACE_SYSCALLS 145 static void trace_syscall(size_t num) 146 { 147 if (num == TEE_SCN_RETURN || num == TEE_SCN_LOG || num > TEE_SCN_MAX) 148 return; 149 FMSG("syscall #%zu (%s)", num, tee_syscall_table[num].name); 150 } 151 #else 152 static void trace_syscall(size_t num __unused) 153 { 154 } 155 #endif 156 157 #ifdef CFG_SYSCALL_FTRACE 158 static void __noprof ftrace_syscall_enter(size_t num) 159 { 160 struct ts_session *s = NULL; 161 162 /* 163 * Syscalls related to inter-TA communication can't be traced in the 164 * caller TA's ftrace buffer as it involves context switching to callee 165 * TA's context. Moreover, user can enable ftrace for callee TA to dump 166 * function trace in corresponding ftrace buffer. 167 */ 168 if (num == TEE_SCN_OPEN_TA_SESSION || num == TEE_SCN_CLOSE_TA_SESSION || 169 num == TEE_SCN_INVOKE_TA_COMMAND) 170 return; 171 172 s = TAILQ_FIRST(&thread_get_tsd()->sess_stack); 173 if (s && s->fbuf) 174 s->fbuf->syscall_trace_enabled = true; 175 } 176 177 static void __noprof ftrace_syscall_leave(void) 178 { 179 struct ts_session *s = TAILQ_FIRST(&thread_get_tsd()->sess_stack); 180 181 if (s && s->fbuf) 182 s->fbuf->syscall_trace_enabled = false; 183 } 184 #else 185 static void __noprof ftrace_syscall_enter(size_t num __unused) 186 { 187 } 188 189 static void __noprof ftrace_syscall_leave(void) 190 { 191 } 192 #endif 193 194 static syscall_t get_tee_syscall_func(size_t num) 195 { 196 /* Cast away const */ 197 struct syscall_entry *sc_table = (void *)tee_syscall_table; 198 199 static_assert(ARRAY_SIZE(tee_syscall_table) == (TEE_SCN_MAX + 1)); 200 201 if (num > TEE_SCN_MAX) 202 return (syscall_t)syscall_not_supported; 203 204 return load_no_speculate(&sc_table[num].fn, &sc_table[0].fn, 205 &sc_table[TEE_SCN_MAX].fn + 1); 206 } 207 208 bool scall_handle_user_ta(struct thread_scall_regs *regs) 209 { 210 size_t scn = 0; 211 size_t max_args = 0; 212 syscall_t scf = NULL; 213 214 scall_get_max_args(regs, &scn, &max_args); 215 216 trace_syscall(scn); 217 218 if (max_args > TEE_SVC_MAX_ARGS) { 219 DMSG("Too many arguments for SCN %zu (%zu)", scn, max_args); 220 scall_set_retval(regs, TEE_ERROR_GENERIC); 221 return true; /* return to user mode */ 222 } 223 224 scf = get_tee_syscall_func(scn); 225 226 ftrace_syscall_enter(scn); 227 228 scall_set_retval(regs, scall_do_call(regs, scf)); 229 230 ftrace_syscall_leave(); 231 232 /* 233 * Return true if we're to return to user mode, 234 * thread_scall_handler() will take care of the rest. 235 */ 236 return scn != TEE_SCN_RETURN && scn != TEE_SCN_PANIC; 237 } 238 239 static syscall_t get_ldelf_syscall_func(size_t num) 240 { 241 /* Cast away const */ 242 struct syscall_entry *sc_table = (void *)ldelf_syscall_table; 243 244 COMPILE_TIME_ASSERT(ARRAY_SIZE(ldelf_syscall_table) == 245 (LDELF_SCN_MAX + 1)); 246 247 if (num > LDELF_SCN_MAX) 248 return (syscall_t)syscall_not_supported; 249 250 return load_no_speculate(&sc_table[num].fn, &sc_table[0].fn, 251 &sc_table[LDELF_SCN_MAX].fn + 1); 252 } 253 254 bool scall_handle_ldelf(struct thread_scall_regs *regs) 255 { 256 size_t scn = 0; 257 size_t max_args = 0; 258 syscall_t scf = NULL; 259 260 scall_get_max_args(regs, &scn, &max_args); 261 262 trace_syscall(scn); 263 264 if (max_args > TEE_SVC_MAX_ARGS) { 265 DMSG("Too many arguments for SCN %zu (%zu)", scn, max_args); 266 scall_set_retval(regs, TEE_ERROR_GENERIC); 267 return true; /* return to user mode */ 268 } 269 270 scf = get_ldelf_syscall_func(scn); 271 272 ftrace_syscall_enter(scn); 273 274 scall_set_retval(regs, scall_do_call(regs, scf)); 275 276 ftrace_syscall_leave(); 277 278 /* 279 * Return true if we're to return to user mode, 280 * thread_scall_handler() will take care of the rest. 281 */ 282 return scn != LDELF_RETURN && scn != LDELF_PANIC; 283 } 284 285 uint32_t scall_sys_return_helper(uint32_t ret, bool panic, uint32_t panic_code, 286 struct thread_scall_regs *regs) 287 { 288 if (panic) { 289 TAMSG_RAW(""); 290 TAMSG_RAW("TA panicked with code 0x%" PRIx32, panic_code); 291 scall_save_panic_stack(regs); 292 } 293 294 scall_set_sys_return_regs(regs, panic, panic_code); 295 296 return ret; 297 } 298