xref: /optee_os/core/pta/system.c (revision 52e7b1a67f8ff9adf25f1936f048a3b488103c77)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2018-2022 Linaro Limited
4  * Copyright (c) 2020, Arm Limited.
5  * Copyright (c) 2020, Open Mobile Platform LLC
6  */
7 
8 #include <assert.h>
9 #include <crypto/crypto.h>
10 #include <kernel/handle.h>
11 #include <kernel/huk_subkey.h>
12 #include <kernel/ldelf_loader.h>
13 #include <kernel/misc.h>
14 #include <kernel/msg_param.h>
15 #include <kernel/pseudo_ta.h>
16 #include <kernel/tpm.h>
17 #include <kernel/ts_store.h>
18 #include <kernel/user_access.h>
19 #include <kernel/user_mode_ctx.h>
20 #include <ldelf.h>
21 #include <mm/file.h>
22 #include <mm/fobj.h>
23 #include <mm/vm.h>
24 #include <pta_system.h>
25 #include <stdlib_ext.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <tee_api_defines_extensions.h>
29 #include <tee_api_defines.h>
30 #include <tee/tee_supp_plugin_rpc.h>
31 #include <tee/uuid.h>
32 #include <util.h>
33 
34 static unsigned int system_pnum;
35 
36 static TEE_Result system_rng_reseed(uint32_t param_types,
37 				    TEE_Param params[TEE_NUM_PARAMS])
38 {
39 	size_t entropy_sz = 0;
40 	uint8_t *entropy_input = NULL;
41 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
42 					  TEE_PARAM_TYPE_NONE,
43 					  TEE_PARAM_TYPE_NONE,
44 					  TEE_PARAM_TYPE_NONE);
45 
46 	if (exp_pt != param_types)
47 		return TEE_ERROR_BAD_PARAMETERS;
48 	entropy_input = params[0].memref.buffer;
49 	entropy_sz = params[0].memref.size;
50 
51 	if (!entropy_sz || !entropy_input)
52 		return TEE_ERROR_BAD_PARAMETERS;
53 
54 	crypto_rng_add_event(CRYPTO_RNG_SRC_NONSECURE, &system_pnum,
55 			     entropy_input, entropy_sz);
56 	return TEE_SUCCESS;
57 }
58 
59 static TEE_Result system_derive_ta_unique_key(struct user_mode_ctx *uctx,
60 					      uint32_t param_types,
61 					      TEE_Param params[TEE_NUM_PARAMS])
62 {
63 	size_t data_len = sizeof(TEE_UUID);
64 	TEE_Result res = TEE_ERROR_GENERIC;
65 	uint8_t *data = NULL;
66 	uint32_t access_flags = 0;
67 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
68 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
69 					  TEE_PARAM_TYPE_NONE,
70 					  TEE_PARAM_TYPE_NONE);
71 
72 	if (exp_pt != param_types)
73 		return TEE_ERROR_BAD_PARAMETERS;
74 
75 	if (params[0].memref.size > TA_DERIVED_EXTRA_DATA_MAX_SIZE ||
76 	    params[1].memref.size < TA_DERIVED_KEY_MIN_SIZE ||
77 	    params[1].memref.size > TA_DERIVED_KEY_MAX_SIZE)
78 		return TEE_ERROR_BAD_PARAMETERS;
79 
80 	/*
81 	 * The derived key shall not end up in non-secure memory by
82 	 * mistake.
83 	 *
84 	 * Note that we're allowing shared memory as long as it's
85 	 * secure. This is needed because a TA always uses shared memory
86 	 * when communicating with another TA.
87 	 */
88 	access_flags = TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER |
89 		       TEE_MEMORY_ACCESS_SECURE;
90 	res = vm_check_access_rights(uctx, access_flags,
91 				     (uaddr_t)params[1].memref.buffer,
92 				     params[1].memref.size);
93 	if (res != TEE_SUCCESS)
94 		return TEE_ERROR_SECURITY;
95 
96 	/* Take extra data into account. */
97 	if (ADD_OVERFLOW(data_len, params[0].memref.size, &data_len))
98 		return TEE_ERROR_SECURITY;
99 
100 	data = calloc(data_len, 1);
101 	if (!data)
102 		return TEE_ERROR_OUT_OF_MEMORY;
103 
104 	memcpy(data, &uctx->ts_ctx->uuid, sizeof(TEE_UUID));
105 
106 	/* Append the user provided data */
107 	memcpy(data + sizeof(TEE_UUID), params[0].memref.buffer,
108 	       params[0].memref.size);
109 
110 	res = huk_subkey_derive(HUK_SUBKEY_UNIQUE_TA, data, data_len,
111 				params[1].memref.buffer,
112 				params[1].memref.size);
113 	free_wipe(data);
114 
115 	return res;
116 }
117 
118 static TEE_Result system_map_zi(struct user_mode_ctx *uctx,
119 				uint32_t param_types,
120 				TEE_Param params[TEE_NUM_PARAMS])
121 {
122 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
123 					  TEE_PARAM_TYPE_VALUE_INOUT,
124 					  TEE_PARAM_TYPE_VALUE_INPUT,
125 					  TEE_PARAM_TYPE_NONE);
126 	uint32_t prot = TEE_MATTR_URW | TEE_MATTR_PRW;
127 	TEE_Result res = TEE_ERROR_GENERIC;
128 	struct mobj *mobj = NULL;
129 	uint32_t pad_begin = 0;
130 	uint32_t vm_flags = 0;
131 	struct fobj *f = NULL;
132 	uint32_t pad_end = 0;
133 	size_t num_bytes = 0;
134 	vaddr_t va = 0;
135 
136 	if (exp_pt != param_types)
137 		return TEE_ERROR_BAD_PARAMETERS;
138 	if (params[0].value.b & ~PTA_SYSTEM_MAP_FLAG_SHAREABLE)
139 		return TEE_ERROR_BAD_PARAMETERS;
140 
141 	if (params[0].value.b & PTA_SYSTEM_MAP_FLAG_SHAREABLE)
142 		vm_flags |= VM_FLAG_SHAREABLE;
143 
144 	num_bytes = params[0].value.a;
145 	va = reg_pair_to_64(params[1].value.a, params[1].value.b);
146 	pad_begin = params[2].value.a;
147 	pad_end = params[2].value.b;
148 
149 	f = fobj_ta_mem_alloc(ROUNDUP_DIV(num_bytes, SMALL_PAGE_SIZE));
150 	if (!f)
151 		return TEE_ERROR_OUT_OF_MEMORY;
152 	mobj = mobj_with_fobj_alloc(f, NULL, TEE_MATTR_MEM_TYPE_TAGGED);
153 	fobj_put(f);
154 	if (!mobj)
155 		return TEE_ERROR_OUT_OF_MEMORY;
156 	res = vm_map_pad(uctx, &va, num_bytes, prot, vm_flags,
157 			 mobj, 0, pad_begin, pad_end, 0);
158 	mobj_put(mobj);
159 	if (!res)
160 		reg_pair_from_64(va, &params[1].value.a, &params[1].value.b);
161 
162 	return res;
163 }
164 
165 static TEE_Result system_unmap(struct user_mode_ctx *uctx, uint32_t param_types,
166 			       TEE_Param params[TEE_NUM_PARAMS])
167 {
168 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
169 					  TEE_PARAM_TYPE_VALUE_INPUT,
170 					  TEE_PARAM_TYPE_NONE,
171 					  TEE_PARAM_TYPE_NONE);
172 	TEE_Result res = TEE_SUCCESS;
173 	uint32_t vm_flags = 0;
174 	vaddr_t end_va = 0;
175 	vaddr_t va = 0;
176 	size_t sz = 0;
177 
178 	if (exp_pt != param_types)
179 		return TEE_ERROR_BAD_PARAMETERS;
180 
181 	if (params[0].value.b)
182 		return TEE_ERROR_BAD_PARAMETERS;
183 
184 	va = reg_pair_to_64(params[1].value.a, params[1].value.b);
185 	sz = ROUNDUP(params[0].value.a, SMALL_PAGE_SIZE);
186 
187 	/*
188 	 * The vm_get_flags() and vm_unmap() are supposed to detect or
189 	 * handle overflow directly or indirectly. However, this function
190 	 * an API function so an extra guard here is in order. If nothing
191 	 * else to make it easier to review the code.
192 	 */
193 	if (ADD_OVERFLOW(va, sz, &end_va))
194 		return TEE_ERROR_BAD_PARAMETERS;
195 
196 	res = vm_get_flags(uctx, va, sz, &vm_flags);
197 	if (res)
198 		return res;
199 	if (vm_flags & VM_FLAG_PERMANENT)
200 		return TEE_ERROR_ACCESS_DENIED;
201 
202 	return vm_unmap(uctx, va, sz);
203 }
204 
205 static TEE_Result system_dlopen(struct user_mode_ctx *uctx,
206 				uint32_t param_types,
207 				TEE_Param params[TEE_NUM_PARAMS])
208 {
209 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
210 					  TEE_PARAM_TYPE_VALUE_INPUT,
211 					  TEE_PARAM_TYPE_NONE,
212 					  TEE_PARAM_TYPE_NONE);
213 	TEE_Result res = TEE_ERROR_GENERIC;
214 	struct ts_session *s = NULL;
215 	TEE_UUID uuid = { };
216 	uint32_t flags = 0;
217 
218 	if (exp_pt != param_types)
219 		return TEE_ERROR_BAD_PARAMETERS;
220 
221 	if (!params[0].memref.buffer || params[0].memref.size != sizeof(uuid))
222 		return TEE_ERROR_BAD_PARAMETERS;
223 
224 	res = copy_from_user(&uuid, params[0].memref.buffer, sizeof(uuid));
225 	if (res)
226 		return res;
227 
228 	flags = params[1].value.a;
229 
230 	s = ts_pop_current_session();
231 	res = ldelf_dlopen(uctx, &uuid, flags);
232 	ts_push_current_session(s);
233 
234 	return res;
235 }
236 
237 static TEE_Result system_dlsym(struct user_mode_ctx *uctx, uint32_t param_types,
238 			       TEE_Param params[TEE_NUM_PARAMS])
239 {
240 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
241 					  TEE_PARAM_TYPE_MEMREF_INPUT,
242 					  TEE_PARAM_TYPE_VALUE_OUTPUT,
243 					  TEE_PARAM_TYPE_NONE);
244 	TEE_Result res = TEE_ERROR_GENERIC;
245 	struct ts_session *s = NULL;
246 	char *sym = NULL;
247 	TEE_UUID uuid = { };
248 	size_t symlen = 0;
249 	vaddr_t va = 0;
250 
251 	if (exp_pt != param_types)
252 		return TEE_ERROR_BAD_PARAMETERS;
253 
254 	if (!params[0].memref.buffer || params[0].memref.size != sizeof(uuid))
255 		return TEE_ERROR_BAD_PARAMETERS;
256 
257 	res = copy_from_user(&uuid, params[0].memref.buffer, sizeof(uuid));
258 	if (res)
259 		return res;
260 
261 	if (!params[1].memref.buffer)
262 		return TEE_ERROR_BAD_PARAMETERS;
263 	res = bb_strndup_user(params[1].memref.buffer, params[1].memref.size,
264 			      &sym, &symlen);
265 	if (res)
266 		return res;
267 
268 	s = ts_pop_current_session();
269 	res = ldelf_dlsym(uctx, &uuid, sym, symlen, &va);
270 	ts_push_current_session(s);
271 
272 	if (!res)
273 		reg_pair_from_64(va, &params[2].value.a, &params[2].value.b);
274 
275 	return res;
276 }
277 
278 static TEE_Result system_get_tpm_event_log(uint32_t param_types,
279 					   TEE_Param params[TEE_NUM_PARAMS])
280 {
281 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
282 					  TEE_PARAM_TYPE_NONE,
283 					  TEE_PARAM_TYPE_NONE,
284 					  TEE_PARAM_TYPE_NONE);
285 	size_t size = 0;
286 	TEE_Result res = TEE_SUCCESS;
287 
288 	if (exp_pt != param_types)
289 		return TEE_ERROR_BAD_PARAMETERS;
290 
291 	size = params[0].memref.size;
292 	res = tpm_get_event_log(params[0].memref.buffer, &size);
293 	params[0].memref.size = size;
294 
295 	return res;
296 }
297 
298 static TEE_Result system_supp_plugin_invoke(uint32_t param_types,
299 					    TEE_Param params[TEE_NUM_PARAMS])
300 {
301 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
302 					  TEE_PARAM_TYPE_VALUE_INPUT,
303 					  TEE_PARAM_TYPE_MEMREF_INOUT,
304 					  TEE_PARAM_TYPE_VALUE_OUTPUT);
305 	TEE_Result res = TEE_ERROR_GENERIC;
306 	size_t outlen = 0;
307 
308 	if (exp_pt != param_types)
309 		return TEE_ERROR_BAD_PARAMETERS;
310 
311 	res = tee_invoke_supp_plugin_rpc(params[0].memref.buffer, /* uuid */
312 					 params[1].value.a, /* cmd */
313 					 params[1].value.b, /* sub_cmd */
314 					 params[2].memref.buffer, /* data */
315 					 params[2].memref.size, /* in len */
316 					 &outlen);
317 	params[3].value.a = (uint32_t)outlen;
318 
319 	return res;
320 }
321 
322 static TEE_Result open_session(uint32_t param_types __unused,
323 			       TEE_Param params[TEE_NUM_PARAMS] __unused,
324 			       void **sess_ctx __unused)
325 {
326 	struct ts_session *s = NULL;
327 
328 	/* Check that we're called from a user TA */
329 	s = ts_get_calling_session();
330 	if (!s)
331 		return TEE_ERROR_ACCESS_DENIED;
332 	if (!is_user_ta_ctx(s->ctx))
333 		return TEE_ERROR_ACCESS_DENIED;
334 
335 	return TEE_SUCCESS;
336 }
337 
338 static TEE_Result invoke_command(void *sess_ctx __unused, uint32_t cmd_id,
339 				 uint32_t param_types,
340 				 TEE_Param params[TEE_NUM_PARAMS])
341 {
342 	struct ts_session *s = ts_get_calling_session();
343 	struct user_mode_ctx *uctx = to_user_mode_ctx(s->ctx);
344 
345 	switch (cmd_id) {
346 	case PTA_SYSTEM_ADD_RNG_ENTROPY:
347 		return system_rng_reseed(param_types, params);
348 	case PTA_SYSTEM_DERIVE_TA_UNIQUE_KEY:
349 		return system_derive_ta_unique_key(uctx, param_types, params);
350 	case PTA_SYSTEM_MAP_ZI:
351 		return system_map_zi(uctx, param_types, params);
352 	case PTA_SYSTEM_UNMAP:
353 		return system_unmap(uctx, param_types, params);
354 	case PTA_SYSTEM_DLOPEN:
355 		return system_dlopen(uctx, param_types, params);
356 	case PTA_SYSTEM_DLSYM:
357 		return system_dlsym(uctx, param_types, params);
358 	case PTA_SYSTEM_GET_TPM_EVENT_LOG:
359 		return system_get_tpm_event_log(param_types, params);
360 	case PTA_SYSTEM_SUPP_PLUGIN_INVOKE:
361 		return system_supp_plugin_invoke(param_types, params);
362 	default:
363 		break;
364 	}
365 
366 	return TEE_ERROR_NOT_IMPLEMENTED;
367 }
368 
369 pseudo_ta_register(.uuid = PTA_SYSTEM_UUID, .name = "system.pta",
370 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT,
371 		   .open_session_entry_point = open_session,
372 		   .invoke_command_entry_point = invoke_command);
373