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