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