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