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