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
trace_syscall(size_t num)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
trace_syscall(size_t num __unused)150 static void trace_syscall(size_t num __unused)
151 {
152 }
153 #endif
154
155 #ifdef CFG_SYSCALL_FTRACE
ftrace_syscall_enter(size_t num)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
ftrace_syscall_leave(void)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
ftrace_syscall_enter(size_t num __unused)183 static void __noprof ftrace_syscall_enter(size_t num __unused)
184 {
185 }
186
ftrace_syscall_leave(void)187 static void __noprof ftrace_syscall_leave(void)
188 {
189 }
190 #endif
191
get_tee_syscall_func(size_t num)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
scall_handle_user_ta(struct thread_scall_regs * regs)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
get_ldelf_syscall_func(size_t num)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
scall_handle_ldelf(struct thread_scall_regs * regs)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
scall_sys_return_helper(uint32_t ret,bool panic,uint32_t panic_code,struct thread_scall_regs * regs)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