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