xref: /OK3568_Linux_fs/external/security/librkcrypto/third_party/optee_client/libteec/src/tee_client_api.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (c) 2015-2016, Linaro Limited
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <limits.h>
31 #include <pthread.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/ioctl.h>
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <tee_client_api_extensions.h>
40 #include <tee_client_api.h>
41 #include <teec_trace.h>
42 #include <unistd.h>
43 
44 #ifndef __aligned
45 #define __aligned(x) __attribute__((__aligned__(x)))
46 #endif
47 #include <linux/tee.h>
48 
49 #include "teec_benchmark.h"
50 
51 /* How many device sequence numbers will be tried before giving up */
52 #define TEEC_MAX_DEV_SEQ	10
53 
54 /* Helpers to access memref parts of a struct tee_ioctl_param */
55 #define MEMREF_SHM_ID(p)	((p)->c)
56 #define MEMREF_SHM_OFFS(p)	((p)->a)
57 #define MEMREF_SIZE(p)		((p)->b)
58 
59 /*
60  * Internal flags of TEEC_SharedMemory::internal.flags
61  */
62 #define SHM_FLAG_BUFFER_ALLOCED		(1u << 0)
63 #define SHM_FLAG_SHADOW_BUFFER_ALLOCED	(1u << 1)
64 
65 static pthread_mutex_t teec_mutex = PTHREAD_MUTEX_INITIALIZER;
66 
teec_mutex_lock(pthread_mutex_t * mu)67 static void teec_mutex_lock(pthread_mutex_t *mu)
68 {
69 	pthread_mutex_lock(mu);
70 }
71 
teec_mutex_unlock(pthread_mutex_t * mu)72 static void teec_mutex_unlock(pthread_mutex_t *mu)
73 {
74 	pthread_mutex_unlock(mu);
75 }
76 
teec_paged_aligned_alloc(size_t sz)77 static void *teec_paged_aligned_alloc(size_t sz)
78 {
79 	void *p = NULL;
80 
81 	if (!posix_memalign(&p, sysconf(_SC_PAGESIZE), sz))
82 		return p;
83 
84 	return NULL;
85 }
86 
teec_open_dev(const char * devname,const char * capabilities,uint32_t * gen_caps)87 static int teec_open_dev(const char *devname, const char *capabilities,
88 			 uint32_t *gen_caps)
89 {
90 	int fd = 0;
91 	struct tee_ioctl_version_data vers;
92 
93 	memset(&vers, 0, sizeof(vers));
94 
95 	fd = open(devname, O_RDWR);
96 	if (fd < 0)
97 		return -1;
98 
99 	if (ioctl(fd, TEE_IOC_VERSION, &vers)) {
100 		EMSG("TEE_IOC_VERSION failed");
101 		goto err;
102 	}
103 
104 	/* We can only handle GP TEEs */
105 	if (!(vers.gen_caps & TEE_GEN_CAP_GP))
106 		goto err;
107 
108 	if (capabilities) {
109 		if (strcmp(capabilities, "optee-tz") == 0) {
110 			if (vers.impl_id != TEE_IMPL_ID_OPTEE)
111 				goto err;
112 			if (!(vers.impl_caps & TEE_OPTEE_CAP_TZ))
113 				goto err;
114 		} else {
115 			/* Unrecognized capability requested */
116 			goto err;
117 		}
118 	}
119 
120 	*gen_caps = vers.gen_caps;
121 	return fd;
122 err:
123 	close(fd);
124 	return -1;
125 }
126 
teec_shm_alloc(int fd,size_t size,int * id)127 static int teec_shm_alloc(int fd, size_t size, int *id)
128 {
129 	int shm_fd = 0;
130 	struct tee_ioctl_shm_alloc_data data;
131 
132 	memset(&data, 0, sizeof(data));
133 
134 	data.size = size;
135 	shm_fd = ioctl(fd, TEE_IOC_SHM_ALLOC, &data);
136 	if (shm_fd < 0)
137 		return -1;
138 	*id = data.id;
139 	return shm_fd;
140 }
141 
teec_shm_register(int fd,void * buf,size_t size,int * id)142 static int teec_shm_register(int fd, void *buf, size_t size, int *id)
143 {
144 	int shm_fd = 0;
145 	struct tee_ioctl_shm_register_data data;
146 
147 	memset(&data, 0, sizeof(data));
148 
149 	data.addr = (uintptr_t)buf;
150 	data.length = size;
151 	shm_fd = ioctl(fd, TEE_IOC_SHM_REGISTER, &data);
152 	if (shm_fd < 0)
153 		return -1;
154 	*id = data.id;
155 	return shm_fd;
156 }
157 
TEEC_InitializeContext(const char * name,TEEC_Context * ctx)158 TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *ctx)
159 {
160 	char devname[PATH_MAX] = { 0 };
161 	int fd = 0;
162 	size_t n = 0;
163 
164 	if (!ctx)
165 		return TEEC_ERROR_BAD_PARAMETERS;
166 
167 	for (n = 0; n < TEEC_MAX_DEV_SEQ; n++) {
168 		uint32_t gen_caps = 0;
169 
170 		snprintf(devname, sizeof(devname), "/dev/tee%zu", n);
171 		fd = teec_open_dev(devname, name, &gen_caps);
172 		if (fd >= 0) {
173 			ctx->fd = fd;
174 			ctx->reg_mem = gen_caps & TEE_GEN_CAP_REG_MEM;
175 			ctx->memref_null = gen_caps & TEE_GEN_CAP_MEMREF_NULL;
176 			return TEEC_SUCCESS;
177 		}
178 	}
179 
180 	return TEEC_ERROR_ITEM_NOT_FOUND;
181 }
182 
TEEC_FinalizeContext(TEEC_Context * ctx)183 void TEEC_FinalizeContext(TEEC_Context *ctx)
184 {
185 	if (ctx)
186 		close(ctx->fd);
187 }
188 
189 
teec_pre_process_tmpref(TEEC_Context * ctx,uint32_t param_type,TEEC_TempMemoryReference * tmpref,struct tee_ioctl_param * param,TEEC_SharedMemory * shm)190 static TEEC_Result teec_pre_process_tmpref(TEEC_Context *ctx,
191 			uint32_t param_type, TEEC_TempMemoryReference *tmpref,
192 			struct tee_ioctl_param *param,
193 			TEEC_SharedMemory *shm)
194 {
195 	TEEC_Result res = TEEC_ERROR_GENERIC;
196 
197 	switch (param_type) {
198 	case TEEC_MEMREF_TEMP_INPUT:
199 		param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
200 		shm->flags = TEEC_MEM_INPUT;
201 		break;
202 	case TEEC_MEMREF_TEMP_OUTPUT:
203 		param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
204 		shm->flags = TEEC_MEM_OUTPUT;
205 		break;
206 	case TEEC_MEMREF_TEMP_INOUT:
207 		param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
208 		shm->flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
209 		break;
210 	default:
211 		return TEEC_ERROR_BAD_PARAMETERS;
212 	}
213 	shm->size = tmpref->size;
214 
215 	if (!tmpref->buffer) {
216 		if (tmpref->size)
217 			return TEEC_ERROR_BAD_PARAMETERS;
218 
219 		if (ctx->memref_null) {
220 			/* Null pointer, indicate no shared memory attached */
221 			MEMREF_SHM_ID(param) = TEE_MEMREF_NULL;
222 			shm->id = -1;
223 		} else {
224 			res = TEEC_AllocateSharedMemory(ctx, shm);
225 			if (res != TEEC_SUCCESS)
226 				return res;
227 			MEMREF_SHM_ID(param) = shm->id;
228 		}
229 	} else {
230 		shm->buffer = tmpref->buffer;
231 		res = TEEC_RegisterSharedMemory(ctx, shm);
232 		if (res != TEEC_SUCCESS)
233 			return res;
234 
235 		if (shm->shadow_buffer)
236 			memcpy(shm->shadow_buffer, tmpref->buffer,
237 			       tmpref->size);
238 
239 		MEMREF_SHM_ID(param) = shm->id;
240 	}
241 
242 	MEMREF_SIZE(param) = tmpref->size;
243 
244 	return TEEC_SUCCESS;
245 }
246 
teec_pre_process_whole(TEEC_RegisteredMemoryReference * memref,struct tee_ioctl_param * param)247 static TEEC_Result teec_pre_process_whole(
248 			TEEC_RegisteredMemoryReference *memref,
249 			struct tee_ioctl_param *param)
250 {
251 	const uint32_t inout = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
252 	uint32_t flags = memref->parent->flags & inout;
253 	TEEC_SharedMemory *shm = NULL;
254 
255 	if (flags == inout)
256 		param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
257 	else if (flags & TEEC_MEM_INPUT)
258 		param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
259 	else if (flags & TEEC_MEM_OUTPUT)
260 		param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
261 	else
262 		return TEEC_ERROR_BAD_PARAMETERS;
263 
264 	shm = memref->parent;
265 	/*
266 	 * We're using a shadow buffer in this reference, copy the real buffer
267 	 * into the shadow buffer if needed. We'll copy it back once we've
268 	 * returned from the call to secure world.
269 	 */
270 	if (shm->shadow_buffer && (flags & TEEC_MEM_INPUT))
271 		memcpy(shm->shadow_buffer, shm->buffer, shm->size);
272 
273 	MEMREF_SHM_ID(param) = shm->id;
274 	MEMREF_SIZE(param) = shm->size;
275 
276 	return TEEC_SUCCESS;
277 }
278 
teec_pre_process_partial(uint32_t param_type,TEEC_RegisteredMemoryReference * memref,struct tee_ioctl_param * param)279 static TEEC_Result teec_pre_process_partial(uint32_t param_type,
280 			TEEC_RegisteredMemoryReference *memref,
281 			struct tee_ioctl_param *param)
282 {
283 	uint32_t req_shm_flags = 0;
284 	TEEC_SharedMemory *shm = NULL;
285 
286 	switch (param_type) {
287 	case TEEC_MEMREF_PARTIAL_INPUT:
288 		req_shm_flags = TEEC_MEM_INPUT;
289 		param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
290 		break;
291 	case TEEC_MEMREF_PARTIAL_OUTPUT:
292 		req_shm_flags = TEEC_MEM_OUTPUT;
293 		param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
294 		break;
295 	case TEEC_MEMREF_PARTIAL_INOUT:
296 		req_shm_flags = TEEC_MEM_OUTPUT | TEEC_MEM_INPUT;
297 		param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
298 		break;
299 	default:
300 		return TEEC_ERROR_BAD_PARAMETERS;
301 	}
302 
303 	shm = memref->parent;
304 
305 	if ((shm->flags & req_shm_flags) != req_shm_flags)
306 		return TEEC_ERROR_BAD_PARAMETERS;
307 
308 	if ((memref->offset + memref->size < memref->offset) ||
309 	    (memref->offset + memref->size > shm->size))
310 		return TEEC_ERROR_BAD_PARAMETERS;
311 
312 	/*
313 	 * We're using a shadow buffer in this reference, copy the real buffer
314 	 * into the shadow buffer if needed. We'll copy it back once we've
315 	 * returned from the call to secure world.
316 	 */
317 	if (shm->shadow_buffer && param_type != TEEC_MEMREF_PARTIAL_OUTPUT)
318 		memcpy((char *)shm->shadow_buffer + memref->offset,
319 		       (char *)shm->buffer + memref->offset, memref->size);
320 
321 	MEMREF_SHM_ID(param) = shm->id;
322 	MEMREF_SHM_OFFS(param) = memref->offset;
323 	MEMREF_SIZE(param) = memref->size;
324 
325 	return TEEC_SUCCESS;
326 }
327 
teec_pre_process_operation(TEEC_Context * ctx,TEEC_Operation * operation,struct tee_ioctl_param * params,TEEC_SharedMemory * shms)328 static TEEC_Result teec_pre_process_operation(TEEC_Context *ctx,
329 			TEEC_Operation *operation,
330 			struct tee_ioctl_param *params,
331 			TEEC_SharedMemory *shms)
332 {
333 	TEEC_Result res = TEEC_ERROR_GENERIC;
334 	size_t n = 0;
335 
336 	memset(shms, 0, sizeof(TEEC_SharedMemory) *
337 			TEEC_CONFIG_PAYLOAD_REF_COUNT);
338 
339 	for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++)
340 		shms[n].id = -1;
341 
342 	if (!operation) {
343 		memset(params, 0, sizeof(struct tee_ioctl_param) *
344 				  TEEC_CONFIG_PAYLOAD_REF_COUNT);
345 		return TEEC_SUCCESS;
346 	}
347 
348 	for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
349 		uint32_t param_type = 0;
350 
351 		param_type = TEEC_PARAM_TYPE_GET(operation->paramTypes, n);
352 		switch (param_type) {
353 		case TEEC_NONE:
354 			params[n].attr = param_type;
355 			break;
356 		case TEEC_VALUE_INPUT:
357 		case TEEC_VALUE_OUTPUT:
358 		case TEEC_VALUE_INOUT:
359 			params[n].attr = param_type;
360 			params[n].a = operation->params[n].value.a;
361 			params[n].b = operation->params[n].value.b;
362 			break;
363 		case TEEC_MEMREF_TEMP_INPUT:
364 		case TEEC_MEMREF_TEMP_OUTPUT:
365 		case TEEC_MEMREF_TEMP_INOUT:
366 			res = teec_pre_process_tmpref(ctx, param_type,
367 				&operation->params[n].tmpref, params + n,
368 				shms + n);
369 			if (res != TEEC_SUCCESS)
370 				return res;
371 			break;
372 		case TEEC_MEMREF_WHOLE:
373 			res = teec_pre_process_whole(
374 					&operation->params[n].memref,
375 					params + n);
376 			if (res != TEEC_SUCCESS)
377 				return res;
378 			break;
379 		case TEEC_MEMREF_PARTIAL_INPUT:
380 		case TEEC_MEMREF_PARTIAL_OUTPUT:
381 		case TEEC_MEMREF_PARTIAL_INOUT:
382 			res = teec_pre_process_partial(param_type,
383 				&operation->params[n].memref, params + n);
384 			if (res != TEEC_SUCCESS)
385 				return res;
386 			break;
387 		default:
388 			return TEEC_ERROR_BAD_PARAMETERS;
389 		}
390 	}
391 
392 	return TEEC_SUCCESS;
393 }
394 
teec_post_process_tmpref(uint32_t param_type,TEEC_TempMemoryReference * tmpref,struct tee_ioctl_param * param,TEEC_SharedMemory * shm)395 static void teec_post_process_tmpref(uint32_t param_type,
396 			TEEC_TempMemoryReference *tmpref,
397 			struct tee_ioctl_param *param,
398 			TEEC_SharedMemory *shm)
399 {
400 	if (param_type != TEEC_MEMREF_TEMP_INPUT) {
401 		if (MEMREF_SIZE(param) <= tmpref->size && tmpref->buffer &&
402 		    shm->shadow_buffer)
403 			memcpy(tmpref->buffer, shm->shadow_buffer,
404 			       MEMREF_SIZE(param));
405 
406 		tmpref->size = MEMREF_SIZE(param);
407 	}
408 }
409 
teec_post_process_whole(TEEC_RegisteredMemoryReference * memref,struct tee_ioctl_param * param)410 static void teec_post_process_whole(TEEC_RegisteredMemoryReference *memref,
411 			struct tee_ioctl_param *param)
412 {
413 	TEEC_SharedMemory *shm = memref->parent;
414 
415 	if (shm->flags & TEEC_MEM_OUTPUT) {
416 
417 		/*
418 		 * We're using a shadow buffer in this reference, copy back
419 		 * the shadow buffer into the real buffer now that we've
420 		 * returned from secure world.
421 		 */
422 		if (shm->shadow_buffer && MEMREF_SIZE(param) <= shm->size)
423 			memcpy(shm->buffer, shm->shadow_buffer,
424 			       MEMREF_SIZE(param));
425 
426 		memref->size = MEMREF_SIZE(param);
427 	}
428 }
429 
teec_post_process_partial(uint32_t param_type,TEEC_RegisteredMemoryReference * memref,struct tee_ioctl_param * param)430 static void teec_post_process_partial(uint32_t param_type,
431 			TEEC_RegisteredMemoryReference *memref,
432 			struct tee_ioctl_param *param)
433 {
434 	if (param_type != TEEC_MEMREF_PARTIAL_INPUT) {
435 		TEEC_SharedMemory *shm = memref->parent;
436 
437 		/*
438 		 * We're using a shadow buffer in this reference, copy back
439 		 * the shadow buffer into the real buffer now that we've
440 		 * returned from secure world.
441 		 */
442 		if (shm->shadow_buffer && MEMREF_SIZE(param) <= memref->size)
443 			memcpy((char *)shm->buffer + memref->offset,
444 			       (char *)shm->shadow_buffer + memref->offset,
445 			       MEMREF_SIZE(param));
446 
447 		memref->size = MEMREF_SIZE(param);
448 	}
449 }
450 
teec_post_process_operation(TEEC_Operation * operation,struct tee_ioctl_param * params,TEEC_SharedMemory * shms)451 static void teec_post_process_operation(TEEC_Operation *operation,
452 			struct tee_ioctl_param *params,
453 			TEEC_SharedMemory *shms)
454 {
455 	size_t n = 0;
456 
457 	if (!operation)
458 		return;
459 
460 	for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
461 		uint32_t param_type = 0;
462 
463 		param_type = TEEC_PARAM_TYPE_GET(operation->paramTypes, n);
464 		switch (param_type) {
465 		case TEEC_VALUE_INPUT:
466 			break;
467 		case TEEC_VALUE_OUTPUT:
468 		case TEEC_VALUE_INOUT:
469 			operation->params[n].value.a = params[n].a;
470 			operation->params[n].value.b = params[n].b;
471 			break;
472 		case TEEC_MEMREF_TEMP_INPUT:
473 		case TEEC_MEMREF_TEMP_OUTPUT:
474 		case TEEC_MEMREF_TEMP_INOUT:
475 			teec_post_process_tmpref(param_type,
476 				&operation->params[n].tmpref, params + n,
477 				shms + n);
478 			break;
479 		case TEEC_MEMREF_WHOLE:
480 			teec_post_process_whole(&operation->params[n].memref,
481 						params + n);
482 			break;
483 		case TEEC_MEMREF_PARTIAL_INPUT:
484 		case TEEC_MEMREF_PARTIAL_OUTPUT:
485 		case TEEC_MEMREF_PARTIAL_INOUT:
486 			teec_post_process_partial(param_type,
487 				&operation->params[n].memref, params + n);
488 		default:
489 			break;
490 		}
491 	}
492 }
493 
teec_free_temp_refs(TEEC_Operation * operation,TEEC_SharedMemory * shms)494 static void teec_free_temp_refs(TEEC_Operation *operation,
495 			TEEC_SharedMemory *shms)
496 {
497 	size_t n = 0;
498 
499 	if (!operation)
500 		return;
501 
502 	for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
503 		switch (TEEC_PARAM_TYPE_GET(operation->paramTypes, n)) {
504 		case TEEC_MEMREF_TEMP_INPUT:
505 		case TEEC_MEMREF_TEMP_OUTPUT:
506 		case TEEC_MEMREF_TEMP_INOUT:
507 			TEEC_ReleaseSharedMemory(shms + n);
508 			break;
509 		default:
510 			break;
511 		}
512 	}
513 }
514 
ioctl_errno_to_res(int err)515 static TEEC_Result ioctl_errno_to_res(int err)
516 {
517 	switch (err) {
518 	case ENOMEM:
519 		return TEEC_ERROR_OUT_OF_MEMORY;
520 	default:
521 		return TEEC_ERROR_GENERIC;
522 	}
523 }
524 
uuid_to_octets(uint8_t d[TEE_IOCTL_UUID_LEN],const TEEC_UUID * s)525 static void uuid_to_octets(uint8_t d[TEE_IOCTL_UUID_LEN], const TEEC_UUID *s)
526 {
527 	d[0] = s->timeLow >> 24;
528 	d[1] = s->timeLow >> 16;
529 	d[2] = s->timeLow >> 8;
530 	d[3] = s->timeLow;
531 	d[4] = s->timeMid >> 8;
532 	d[5] = s->timeMid;
533 	d[6] = s->timeHiAndVersion >> 8;
534 	d[7] = s->timeHiAndVersion;
535 	memcpy(d + 8, s->clockSeqAndNode, sizeof(s->clockSeqAndNode));
536 }
537 
setup_client_data(struct tee_ioctl_open_session_arg * arg,uint32_t connection_method,const void * connection_data)538 static void setup_client_data(struct tee_ioctl_open_session_arg *arg,
539 			      uint32_t connection_method,
540 			      const void *connection_data)
541 {
542 	arg->clnt_login = connection_method;
543 
544 	switch (connection_method) {
545 	case TEE_IOCTL_LOGIN_PUBLIC:
546 		/* No connection data to pass */
547 		break;
548 	case TEE_IOCTL_LOGIN_USER:
549 		/* Kernel auto-fills UID and forms client UUID */
550 		break;
551 	case TEE_IOCTL_LOGIN_GROUP:
552 		/*
553 		 * Connection data for group login is uint32_t and rest of
554 		 * clnt_uuid is set as zero.
555 		 *
556 		 * Kernel verifies group membership and then forms client UUID.
557 		 */
558 		memcpy(arg->clnt_uuid, connection_data, sizeof(gid_t));
559 		break;
560 	case TEE_IOCTL_LOGIN_APPLICATION:
561 		/*
562 		 * Kernel auto-fills application identifier and forms client
563 		 * UUID.
564 		 */
565 		break;
566 	case TEE_IOCTL_LOGIN_USER_APPLICATION:
567 		/*
568 		 * Kernel auto-fills application identifier, UID and forms
569 		 * client UUID.
570 		 */
571 		break;
572 	case TEE_IOCTL_LOGIN_GROUP_APPLICATION:
573 		/*
574 		 * Connection data for group login is uint32_t rest of
575 		 * clnt_uuid is set as zero.
576 		 *
577 		 * Kernel verifies group membership, auto-fills application
578 		 * identifier and then forms client UUID.
579 		 */
580 		memcpy(arg->clnt_uuid, connection_data, sizeof(gid_t));
581 		break;
582 	default:
583 		/*
584 		 * Unknown login method, don't pass any connection data as we
585 		 * don't know size.
586 		 */
587 		break;
588 	}
589 }
590 
TEEC_OpenSession(TEEC_Context * ctx,TEEC_Session * session,const TEEC_UUID * destination,uint32_t connection_method,const void * connection_data,TEEC_Operation * operation,uint32_t * ret_origin)591 TEEC_Result TEEC_OpenSession(TEEC_Context *ctx, TEEC_Session *session,
592 			const TEEC_UUID *destination,
593 			uint32_t connection_method, const void *connection_data,
594 			TEEC_Operation *operation, uint32_t *ret_origin)
595 {
596 	struct tee_ioctl_open_session_arg *arg = NULL;
597 	struct tee_ioctl_param *params = NULL;
598 	TEEC_Result res = TEEC_ERROR_GENERIC;
599 	uint32_t eorig = 0;
600 	int rc = 0;
601 	const size_t arg_size = sizeof(struct tee_ioctl_open_session_arg) +
602 				TEEC_CONFIG_PAYLOAD_REF_COUNT *
603 					sizeof(struct tee_ioctl_param);
604 	union {
605 		struct tee_ioctl_open_session_arg arg;
606 		uint8_t data[arg_size];
607 	} buf;
608 	struct tee_ioctl_buf_data buf_data;
609 	TEEC_SharedMemory shm[TEEC_CONFIG_PAYLOAD_REF_COUNT];
610 
611 	memset(&buf, 0, sizeof(buf));
612 	memset(&shm, 0, sizeof(shm));
613 	memset(&buf_data, 0, sizeof(buf_data));
614 
615 	if (!ctx || !session) {
616 		eorig = TEEC_ORIGIN_API;
617 		res = TEEC_ERROR_BAD_PARAMETERS;
618 		goto out;
619 	}
620 
621 	buf_data.buf_ptr = (uintptr_t)&buf;
622 	buf_data.buf_len = sizeof(buf);
623 
624 	arg = &buf.arg;
625 	arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
626 	params = (struct tee_ioctl_param *)(arg + 1);
627 
628 	uuid_to_octets(arg->uuid, destination);
629 
630 	setup_client_data(arg, connection_method, connection_data);
631 
632 	res = teec_pre_process_operation(ctx, operation, params, shm);
633 	if (res != TEEC_SUCCESS) {
634 		eorig = TEEC_ORIGIN_API;
635 		goto out_free_temp_refs;
636 	}
637 
638 	rc = ioctl(ctx->fd, TEE_IOC_OPEN_SESSION, &buf_data);
639 	if (rc) {
640 		EMSG("TEE_IOC_OPEN_SESSION failed");
641 		eorig = TEEC_ORIGIN_COMMS;
642 		res = ioctl_errno_to_res(errno);
643 		goto out_free_temp_refs;
644 	}
645 	res = arg->ret;
646 	eorig = arg->ret_origin;
647 	if (res == TEEC_SUCCESS) {
648 		session->ctx = ctx;
649 		session->session_id = arg->session;
650 	}
651 	teec_post_process_operation(operation, params, shm);
652 
653 out_free_temp_refs:
654 	teec_free_temp_refs(operation, shm);
655 out:
656 	if (ret_origin)
657 		*ret_origin = eorig;
658 	return res;
659 }
660 
TEEC_CloseSession(TEEC_Session * session)661 void TEEC_CloseSession(TEEC_Session *session)
662 {
663 	struct tee_ioctl_close_session_arg arg;
664 
665 	memset(&arg, 0, sizeof(arg));
666 
667 	if (!session)
668 		return;
669 
670 	arg.session = session->session_id;
671 	if (ioctl(session->ctx->fd, TEE_IOC_CLOSE_SESSION, &arg))
672 		EMSG("Failed to close session 0x%x", session->session_id);
673 }
674 
TEEC_InvokeCommand(TEEC_Session * session,uint32_t cmd_id,TEEC_Operation * operation,uint32_t * error_origin)675 TEEC_Result TEEC_InvokeCommand(TEEC_Session *session, uint32_t cmd_id,
676 			TEEC_Operation *operation, uint32_t *error_origin)
677 {
678 	struct tee_ioctl_invoke_arg *arg = NULL;
679 	struct tee_ioctl_param *params = NULL;
680 	TEEC_Result res = TEEC_ERROR_GENERIC;
681 	uint32_t eorig = 0;
682 	int rc = 0;
683 	const size_t arg_size = sizeof(struct tee_ioctl_invoke_arg) +
684 				TEEC_CONFIG_PAYLOAD_REF_COUNT *
685 					sizeof(struct tee_ioctl_param);
686 	union {
687 		struct tee_ioctl_invoke_arg arg;
688 		uint8_t data[arg_size];
689 	} buf;
690 	struct tee_ioctl_buf_data buf_data;
691 	TEEC_SharedMemory shm[TEEC_CONFIG_PAYLOAD_REF_COUNT];
692 
693 	memset(&buf, 0, sizeof(buf));
694 	memset(&buf_data, 0, sizeof(buf_data));
695 	memset(&shm, 0, sizeof(shm));
696 
697 	if (!session) {
698 		eorig = TEEC_ORIGIN_API;
699 		res = TEEC_ERROR_BAD_PARAMETERS;
700 		goto out;
701 	}
702 
703 	bm_timestamp();
704 
705 	buf_data.buf_ptr = (uintptr_t)&buf;
706 	buf_data.buf_len = sizeof(buf);
707 
708 	arg = &buf.arg;
709 	arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
710 	params = (struct tee_ioctl_param *)(arg + 1);
711 
712 	arg->session = session->session_id;
713 	arg->func = cmd_id;
714 
715 	if (operation) {
716 		teec_mutex_lock(&teec_mutex);
717 		operation->session = session;
718 		teec_mutex_unlock(&teec_mutex);
719 	}
720 
721 	res = teec_pre_process_operation(session->ctx, operation, params, shm);
722 	if (res != TEEC_SUCCESS) {
723 		eorig = TEEC_ORIGIN_API;
724 		goto out_free_temp_refs;
725 	}
726 
727 	rc = ioctl(session->ctx->fd, TEE_IOC_INVOKE, &buf_data);
728 	if (rc) {
729 		EMSG("TEE_IOC_INVOKE failed");
730 		eorig = TEEC_ORIGIN_COMMS;
731 		res = ioctl_errno_to_res(errno);
732 		goto out_free_temp_refs;
733 	}
734 
735 	res = arg->ret;
736 	eorig = arg->ret_origin;
737 	teec_post_process_operation(operation, params, shm);
738 
739 	bm_timestamp();
740 
741 out_free_temp_refs:
742 	teec_free_temp_refs(operation, shm);
743 out:
744 	if (error_origin)
745 		*error_origin = eorig;
746 	return res;
747 }
748 
TEEC_RequestCancellation(TEEC_Operation * operation)749 void TEEC_RequestCancellation(TEEC_Operation *operation)
750 {
751 	TEEC_Session *session = NULL;
752 	struct tee_ioctl_cancel_arg arg;
753 
754 	memset(&arg, 0, sizeof(arg));
755 
756 	if (!operation)
757 		return;
758 
759 	teec_mutex_lock(&teec_mutex);
760 	session = operation->session;
761 	teec_mutex_unlock(&teec_mutex);
762 
763 	if (!session)
764 		return;
765 
766 	arg.session = session->session_id;
767 	arg.cancel_id = 0;
768 
769 	if (ioctl(session->ctx->fd, TEE_IOC_CANCEL, &arg))
770 		EMSG("TEE_IOC_CANCEL: %s", strerror(errno));
771 }
772 
TEEC_RegisterSharedMemory(TEEC_Context * ctx,TEEC_SharedMemory * shm)773 TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm)
774 {
775 	TEEC_Result res = TEEC_SUCCESS;
776 	int fd = 0;
777 	size_t s = 0;
778 
779 	if (!ctx || !shm)
780 		return TEEC_ERROR_BAD_PARAMETERS;
781 
782 	if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)))
783 		return TEEC_ERROR_BAD_PARAMETERS;
784 
785 	if (!shm->buffer)
786 		return TEEC_ERROR_BAD_PARAMETERS;
787 
788 	s = shm->size;
789 	if (!s)
790 		s = 8;
791 	if (ctx->reg_mem) {
792 		fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id);
793 		if (fd >= 0) {
794 			shm->registered_fd = fd;
795 			shm->shadow_buffer = NULL;
796 			shm->internal.flags = 0;
797 			goto out;
798 		}
799 
800 		/*
801 		 * If we're here TEE_IOC_SHM_REGISTER failed, probably
802 		 * because some read-only memory was supplied and the Linux
803 		 * kernel doesn't like that at the moment.
804 		 *
805 		 * The error could also have some other origin. In any case
806 		 * we're not making matters worse by trying to allocate and
807 		 * register a shadow buffer before giving up.
808 		 */
809 		shm->shadow_buffer = teec_paged_aligned_alloc(s);
810 		if (!shm->shadow_buffer)
811 			return TEEC_ERROR_OUT_OF_MEMORY;
812 		fd = teec_shm_register(ctx->fd, shm->shadow_buffer, s,
813 				       &shm->id);
814 		if (fd >= 0) {
815 			shm->registered_fd = fd;
816 			shm->internal.flags = SHM_FLAG_SHADOW_BUFFER_ALLOCED;
817 			goto out;
818 		}
819 
820 		if (errno == ENOMEM)
821 			res = TEEC_ERROR_OUT_OF_MEMORY;
822 		else
823 			res = TEEC_ERROR_GENERIC;
824 		free(shm->shadow_buffer);
825 		shm->shadow_buffer = NULL;
826 		return res;
827 	} else {
828 		fd = teec_shm_alloc(ctx->fd, s, &shm->id);
829 		if (fd < 0)
830 			return TEEC_ERROR_OUT_OF_MEMORY;
831 
832 		shm->shadow_buffer = mmap(NULL, s, PROT_READ | PROT_WRITE,
833 					  MAP_SHARED, fd, 0);
834 		close(fd);
835 		if (shm->shadow_buffer == (void *)MAP_FAILED) {
836 			shm->id = -1;
837 			return TEEC_ERROR_OUT_OF_MEMORY;
838 		}
839 		shm->registered_fd = -1;
840 		shm->internal.flags = 0;
841 	}
842 
843 out:
844 	shm->alloced_size = s;
845 	return TEEC_SUCCESS;
846 }
847 
TEEC_RegisterSharedMemoryFileDescriptor(TEEC_Context * ctx,TEEC_SharedMemory * shm,int fd)848 TEEC_Result TEEC_RegisterSharedMemoryFileDescriptor(TEEC_Context *ctx,
849 						    TEEC_SharedMemory *shm,
850 						    int fd)
851 {
852 	int rfd = 0;
853 	struct tee_ioctl_shm_register_fd_data data;
854 
855 	memset(&data, 0, sizeof(data));
856 
857 	if (!ctx || !shm || fd < 0)
858 		return TEEC_ERROR_BAD_PARAMETERS;
859 
860 	if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)))
861 		return TEEC_ERROR_BAD_PARAMETERS;
862 
863 	data.fd = fd;
864 	rfd = ioctl(ctx->fd, TEE_IOC_SHM_REGISTER_FD, &data);
865 	if (rfd < 0)
866 		return TEEC_ERROR_BAD_PARAMETERS;
867 
868 	shm->buffer = NULL;
869 	shm->shadow_buffer = NULL;
870 	shm->registered_fd = rfd;
871 	shm->id = data.id;
872 	shm->size = data.size;
873 	return TEEC_SUCCESS;
874 }
875 
TEEC_AllocateSharedMemory(TEEC_Context * ctx,TEEC_SharedMemory * shm)876 TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm)
877 {
878 	int fd = 0;
879 	size_t s = 0;
880 
881 	if (!ctx || !shm)
882 		return TEEC_ERROR_BAD_PARAMETERS;
883 
884 	if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)))
885 		return TEEC_ERROR_BAD_PARAMETERS;
886 
887 	s = shm->size;
888 	if (!s)
889 		s = 8;
890 
891 	if (ctx->reg_mem) {
892 		shm->buffer = teec_paged_aligned_alloc(s);
893 		if (!shm->buffer)
894 			return TEEC_ERROR_OUT_OF_MEMORY;
895 
896 		fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id);
897 		if (fd < 0) {
898 			free(shm->buffer);
899 			shm->buffer = NULL;
900 			return TEEC_ERROR_OUT_OF_MEMORY;
901 		}
902 		shm->registered_fd = fd;
903 	} else {
904 		fd = teec_shm_alloc(ctx->fd, s, &shm->id);
905 		if (fd < 0)
906 			return TEEC_ERROR_OUT_OF_MEMORY;
907 
908 		shm->buffer = mmap(NULL, s, PROT_READ | PROT_WRITE,
909 				   MAP_SHARED, fd, 0);
910 		close(fd);
911 		if (shm->buffer == (void *)MAP_FAILED) {
912 			shm->id = -1;
913 			return TEEC_ERROR_OUT_OF_MEMORY;
914 		}
915 		shm->registered_fd = -1;
916 	}
917 
918 	shm->shadow_buffer = NULL;
919 	shm->alloced_size = s;
920 	shm->internal.flags = SHM_FLAG_BUFFER_ALLOCED;
921 	return TEEC_SUCCESS;
922 }
923 
TEEC_ReleaseSharedMemory(TEEC_SharedMemory * shm)924 void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *shm)
925 {
926 	if (!shm || shm->id == -1)
927 		return;
928 
929 	if (shm->shadow_buffer) {
930 		if (shm->registered_fd >= 0) {
931 			if (shm->internal.flags &
932 			    SHM_FLAG_SHADOW_BUFFER_ALLOCED)
933 				free(shm->shadow_buffer);
934 			close(shm->registered_fd);
935 		} else {
936 			munmap(shm->shadow_buffer, shm->alloced_size);
937 		}
938 	} else if (shm->buffer) {
939 		if (shm->registered_fd >= 0) {
940 			if (shm->internal.flags & SHM_FLAG_BUFFER_ALLOCED)
941 				free(shm->buffer);
942 			close(shm->registered_fd);
943 		} else {
944 			munmap(shm->buffer, shm->alloced_size);
945 		}
946 	} else if (shm->registered_fd >= 0) {
947 		close(shm->registered_fd);
948 	}
949 
950 	shm->id = -1;
951 	shm->shadow_buffer = NULL;
952 	shm->buffer = NULL;
953 	shm->registered_fd = -1;
954 	shm->internal.flags = 0;
955 }
956