xref: /optee_os/core/kernel/scall.c (revision 4edd96e6d7a7228e907cf498b23e5b5fbdaf39a0)
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