xref: /optee_os/lib/libutee/tee_api.c (revision 9fc2442cc66c279cb962c90c4375746fc9b28bb9)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  */
5 #include <stdlib.h>
6 #include <string.h>
7 #include <string_ext.h>
8 #include <tee_api.h>
9 #include <tee_internal_api_extensions.h>
10 #include <types_ext.h>
11 #include <user_ta_header.h>
12 #include <utee_syscalls.h>
13 #include "tee_api_private.h"
14 
15 static const void *tee_api_instance_data;
16 
17 /* System API - Internal Client API */
18 
19 static TEE_Result copy_param(struct utee_params *up, uint32_t param_types,
20 			     const TEE_Param params[TEE_NUM_PARAMS],
21 			     void **tmp_buf, size_t *tmp_len,
22 			     void *tmp_va[TEE_NUM_PARAMS])
23 {
24 	size_t n = 0;
25 	uint8_t *tb = NULL;
26 	size_t tbl = 0;
27 	size_t tmp_align = sizeof(vaddr_t) * 2;
28 	bool is_tmp_mem[TEE_NUM_PARAMS] = { false };
29 	void *b = NULL;
30 	size_t s = 0;
31 	const uint32_t flags = TEE_MEMORY_ACCESS_READ;
32 
33 	/*
34 	 * If a memory parameter points to TA private memory we need to
35 	 * allocate a temporary buffer to avoid exposing the memory
36 	 * directly to the called TA.
37 	 */
38 
39 	*tmp_buf = NULL;
40 	*tmp_len = 0;
41 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
42 		tmp_va[n] = NULL;
43 		switch (TEE_PARAM_TYPE_GET(param_types, n)) {
44 		case TEE_PARAM_TYPE_MEMREF_INPUT:
45 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
46 		case TEE_PARAM_TYPE_MEMREF_INOUT:
47 			b = params[n].memref.buffer;
48 			s = params[n].memref.size;
49 			/*
50 			 * We're only allocating temporary memory if the
51 			 * buffer is completely within TA memory. If it's
52 			 * NULL, empty, partially outside or completely
53 			 * outside TA memory there's nothing more we need
54 			 * to do here. If there's security/permissions
55 			 * problem we'll get an error in the
56 			 * invoke_command/open_session below.
57 			 */
58 			if (b && s &&
59 			    !TEE_CheckMemoryAccessRights(flags, b, s)) {
60 				is_tmp_mem[n] = true;
61 				tbl += ROUNDUP(s, tmp_align);
62 			}
63 			break;
64 		default:
65 			break;
66 		}
67 	}
68 
69 	if (tbl) {
70 		tb = tee_map_zi(tbl, TEE_MEMORY_ACCESS_ANY_OWNER);
71 		if (!tb)
72 			return TEE_ERROR_OUT_OF_MEMORY;
73 		*tmp_buf = tb;
74 		*tmp_len = tbl;
75 	}
76 
77 	up->types = param_types;
78 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
79 		switch (TEE_PARAM_TYPE_GET(param_types, n)) {
80 		case TEE_PARAM_TYPE_VALUE_INPUT:
81 		case TEE_PARAM_TYPE_VALUE_INOUT:
82 			up->vals[n * 2] = params[n].value.a;
83 			up->vals[n * 2 + 1] = params[n].value.b;
84 			break;
85 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
86 		case TEE_PARAM_TYPE_MEMREF_INOUT:
87 		case TEE_PARAM_TYPE_MEMREF_INPUT:
88 			s = params[n].memref.size;
89 			if (is_tmp_mem[n]) {
90 				b = tb;
91 				tmp_va[n] = tb;
92 				tb += ROUNDUP(s, tmp_align);
93 				if (TEE_PARAM_TYPE_GET(param_types, n) !=
94 				    TEE_PARAM_TYPE_MEMREF_OUTPUT)
95 					memcpy(b, params[n].memref.buffer, s);
96 			} else {
97 				b = params[n].memref.buffer;
98 			}
99 			up->vals[n * 2] = (vaddr_t)b;
100 			up->vals[n * 2 + 1] = s;
101 			break;
102 		default:
103 			up->vals[n * 2] = 0;
104 			up->vals[n * 2 + 1] = 0;
105 			break;
106 		}
107 	}
108 
109 	return TEE_SUCCESS;
110 }
111 
112 static void update_out_param(TEE_Param params[TEE_NUM_PARAMS],
113 			     void *tmp_va[TEE_NUM_PARAMS],
114 			     const struct utee_params *up)
115 {
116 	size_t n;
117 	uint32_t types = up->types;
118 
119 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
120 		uintptr_t a = up->vals[n * 2];
121 		uintptr_t b = up->vals[n * 2 + 1];
122 
123 		switch (TEE_PARAM_TYPE_GET(types, n)) {
124 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
125 		case TEE_PARAM_TYPE_VALUE_INOUT:
126 			params[n].value.a = a;
127 			params[n].value.b = b;
128 			break;
129 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
130 		case TEE_PARAM_TYPE_MEMREF_INOUT:
131 			if (tmp_va[n])
132 				memcpy(params[n].memref.buffer, tmp_va[n],
133 				       MIN(b, params[n].memref.size));
134 			params[n].memref.size = b;
135 			break;
136 		default:
137 			break;
138 		}
139 	}
140 }
141 
142 TEE_Result TEE_OpenTASession(const TEE_UUID *destination,
143 				uint32_t cancellationRequestTimeout,
144 				uint32_t paramTypes,
145 				TEE_Param params[TEE_NUM_PARAMS],
146 				TEE_TASessionHandle *session,
147 				uint32_t *returnOrigin)
148 {
149 	TEE_Result res = TEE_SUCCESS;
150 	struct utee_params up;
151 	uint32_t s = 0;
152 	void *tmp_buf = NULL;
153 	size_t tmp_len = 0;
154 	void *tmp_va[TEE_NUM_PARAMS] = { NULL };
155 
156 	if (paramTypes)
157 		__utee_check_inout_annotation(params,
158 					      sizeof(TEE_Param) *
159 					      TEE_NUM_PARAMS);
160 	__utee_check_out_annotation(session, sizeof(*session));
161 
162 	res = copy_param(&up, paramTypes, params, &tmp_buf, &tmp_len, tmp_va);
163 	if (res)
164 		goto out;
165 	res = _utee_open_ta_session(destination, cancellationRequestTimeout,
166 				    &up, &s, returnOrigin);
167 	update_out_param(params, tmp_va, &up);
168 	if (tmp_buf) {
169 		TEE_Result res2 = tee_unmap(tmp_buf, tmp_len);
170 
171 		if (res2)
172 			TEE_Panic(res2);
173 	}
174 
175 out:
176 	/*
177 	 * Specification says that *session must hold TEE_HANDLE_NULL is
178 	 * TEE_SUCCESS isn't returned. Set it here explicitly in case
179 	 * the syscall fails before out parameters has been updated.
180 	 */
181 	if (res != TEE_SUCCESS)
182 		s = TEE_HANDLE_NULL;
183 
184 	*session = (TEE_TASessionHandle)(uintptr_t)s;
185 	return res;
186 }
187 
188 void TEE_CloseTASession(TEE_TASessionHandle session)
189 {
190 	if (session != TEE_HANDLE_NULL) {
191 		TEE_Result res = _utee_close_ta_session((uintptr_t)session);
192 
193 		if (res != TEE_SUCCESS)
194 			TEE_Panic(res);
195 	}
196 }
197 
198 TEE_Result TEE_InvokeTACommand(TEE_TASessionHandle session,
199 				uint32_t cancellationRequestTimeout,
200 				uint32_t commandID, uint32_t paramTypes,
201 				TEE_Param params[TEE_NUM_PARAMS],
202 				uint32_t *returnOrigin)
203 {
204 	TEE_Result res = TEE_SUCCESS;
205 	uint32_t ret_origin = TEE_ORIGIN_TEE;
206 	struct utee_params up;
207 	void *tmp_buf = NULL;
208 	size_t tmp_len = 0;
209 	void *tmp_va[TEE_NUM_PARAMS] = { NULL };
210 
211 	if (paramTypes)
212 		__utee_check_inout_annotation(params,
213 					      sizeof(TEE_Param) *
214 					      TEE_NUM_PARAMS);
215 	if (returnOrigin)
216 		__utee_check_out_annotation(returnOrigin,
217 					    sizeof(*returnOrigin));
218 
219 	res = copy_param(&up, paramTypes, params, &tmp_buf, &tmp_len, tmp_va);
220 	if (res)
221 		goto out;
222 	res = _utee_invoke_ta_command((uintptr_t)session,
223 				      cancellationRequestTimeout,
224 				      commandID, &up, &ret_origin);
225 	update_out_param(params, tmp_va, &up);
226 	if (tmp_buf) {
227 		TEE_Result res2 = tee_unmap(tmp_buf, tmp_len);
228 
229 		if (res2)
230 			TEE_Panic(res2);
231 	}
232 
233 out:
234 	if (returnOrigin != NULL)
235 		*returnOrigin = ret_origin;
236 
237 	if (ret_origin == TEE_ORIGIN_TRUSTED_APP)
238 		return res;
239 
240 	if (res != TEE_SUCCESS &&
241 	    res != TEE_ERROR_OUT_OF_MEMORY &&
242 	    res != TEE_ERROR_TARGET_DEAD)
243 		TEE_Panic(res);
244 
245 	return res;
246 }
247 
248 /* System API - Cancellations */
249 
250 bool TEE_GetCancellationFlag(void)
251 {
252 	uint32_t c;
253 	TEE_Result res = _utee_get_cancellation_flag(&c);
254 
255 	if (res != TEE_SUCCESS)
256 		c = 0;
257 	return !!c;
258 }
259 
260 bool TEE_UnmaskCancellation(void)
261 {
262 	uint32_t old_mask;
263 	TEE_Result res = _utee_unmask_cancellation(&old_mask);
264 
265 	if (res != TEE_SUCCESS)
266 		TEE_Panic(res);
267 	return !!old_mask;
268 }
269 
270 bool TEE_MaskCancellation(void)
271 {
272 	uint32_t old_mask;
273 	TEE_Result res = _utee_mask_cancellation(&old_mask);
274 
275 	if (res != TEE_SUCCESS)
276 		TEE_Panic(res);
277 	return !!old_mask;
278 }
279 
280 /* System API - Memory Management */
281 
282 TEE_Result TEE_CheckMemoryAccessRights(uint32_t accessFlags, void *buffer,
283 				       uint32_t size)
284 {
285 	TEE_Result res;
286 
287 	if (size == 0)
288 		return TEE_SUCCESS;
289 
290 	/* Check access rights against memory mapping */
291 	res = _utee_check_access_rights(accessFlags, buffer, size);
292 	if (res != TEE_SUCCESS)
293 		goto out;
294 
295 	/*
296 	* Check access rights against input parameters
297 	* Previous legacy code was removed and will need to be restored
298 	*/
299 
300 	res = TEE_SUCCESS;
301 out:
302 	return res;
303 }
304 
305 void TEE_SetInstanceData(const void *instanceData)
306 {
307 	tee_api_instance_data = instanceData;
308 }
309 
310 const void *TEE_GetInstanceData(void)
311 {
312 	return tee_api_instance_data;
313 }
314 
315 void *TEE_MemMove(void *dest, const void *src, uint32_t size)
316 {
317 	return memmove(dest, src, size);
318 }
319 
320 int32_t TEE_MemCompare(const void *buffer1, const void *buffer2, uint32_t size)
321 {
322 	return consttime_memcmp(buffer1, buffer2, size);
323 }
324 
325 void *TEE_MemFill(void *buff, uint32_t x, uint32_t size)
326 {
327 	return memset(buff, x, size);
328 }
329 
330 /* Date & Time API */
331 
332 void TEE_GetSystemTime(TEE_Time *time)
333 {
334 	TEE_Result res = _utee_get_time(UTEE_TIME_CAT_SYSTEM, time);
335 
336 	if (res != TEE_SUCCESS)
337 		TEE_Panic(res);
338 }
339 
340 TEE_Result TEE_Wait(uint32_t timeout)
341 {
342 	TEE_Result res = _utee_wait(timeout);
343 
344 	if (res != TEE_SUCCESS && res != TEE_ERROR_CANCEL)
345 		TEE_Panic(res);
346 
347 	return res;
348 }
349 
350 TEE_Result TEE_GetTAPersistentTime(TEE_Time *time)
351 {
352 	TEE_Result res;
353 
354 	res = _utee_get_time(UTEE_TIME_CAT_TA_PERSISTENT, time);
355 
356 	if (res != TEE_SUCCESS && res != TEE_ERROR_OVERFLOW) {
357 		time->seconds = 0;
358 		time->millis = 0;
359 	}
360 
361 	if (res != TEE_SUCCESS &&
362 	    res != TEE_ERROR_TIME_NOT_SET &&
363 	    res != TEE_ERROR_TIME_NEEDS_RESET &&
364 	    res != TEE_ERROR_OVERFLOW &&
365 	    res != TEE_ERROR_OUT_OF_MEMORY)
366 		TEE_Panic(res);
367 
368 	return res;
369 }
370 
371 TEE_Result TEE_SetTAPersistentTime(const TEE_Time *time)
372 {
373 	TEE_Result res;
374 
375 	res = _utee_set_ta_time(time);
376 
377 	if (res != TEE_SUCCESS &&
378 	    res != TEE_ERROR_OUT_OF_MEMORY &&
379 	    res != TEE_ERROR_STORAGE_NO_SPACE)
380 		TEE_Panic(res);
381 
382 	return res;
383 }
384 
385 void TEE_GetREETime(TEE_Time *time)
386 {
387 	TEE_Result res = _utee_get_time(UTEE_TIME_CAT_REE, time);
388 
389 	if (res != TEE_SUCCESS)
390 		TEE_Panic(res);
391 }
392 
393 void *TEE_Malloc(uint32_t len, uint32_t hint)
394 {
395 	if (hint == TEE_MALLOC_FILL_ZERO)
396 		return calloc(1, len);
397 	else if (hint == TEE_USER_MEM_HINT_NO_FILL_ZERO)
398 		return malloc(len);
399 
400 	EMSG("Invalid hint %#" PRIx32, hint);
401 
402 	return NULL;
403 }
404 
405 void *TEE_Realloc(void *buffer, uint32_t newSize)
406 {
407 	return realloc(buffer, newSize);
408 }
409 
410 void TEE_Free(void *buffer)
411 {
412 	free(buffer);
413 }
414 
415 /* Cache maintenance support (TA requires the CACHE_MAINTENANCE property) */
416 TEE_Result TEE_CacheClean(char *buf, size_t len)
417 {
418 	return _utee_cache_operation(buf, len, TEE_CACHECLEAN);
419 }
420 TEE_Result TEE_CacheFlush(char *buf, size_t len)
421 {
422 	return _utee_cache_operation(buf, len, TEE_CACHEFLUSH);
423 }
424 
425 TEE_Result TEE_CacheInvalidate(char *buf, size_t len)
426 {
427 	return _utee_cache_operation(buf, len, TEE_CACHEINVALIDATE);
428 }
429