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