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 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
52
53 /* How many device sequence numbers will be tried before giving up */
54 #define TEEC_MAX_DEV_SEQ 10
55
56 /* Helpers to access memref parts of a struct tee_ioctl_param */
57 #define MEMREF_SHM_ID(p) ((p)->c)
58 #define MEMREF_SHM_OFFS(p) ((p)->a)
59 #define MEMREF_SIZE(p) ((p)->b)
60
61 /*
62 * Internal flags of TEEC_SharedMemory::internal.flags
63 */
64 #define SHM_FLAG_BUFFER_ALLOCED (1u << 0)
65 #define SHM_FLAG_SHADOW_BUFFER_ALLOCED (1u << 1)
66
67 static pthread_mutex_t teec_mutex = PTHREAD_MUTEX_INITIALIZER;
68
teec_mutex_lock(pthread_mutex_t * mu)69 static void teec_mutex_lock(pthread_mutex_t *mu)
70 {
71 pthread_mutex_lock(mu);
72 }
73
teec_mutex_unlock(pthread_mutex_t * mu)74 static void teec_mutex_unlock(pthread_mutex_t *mu)
75 {
76 pthread_mutex_unlock(mu);
77 }
78
teec_paged_aligned_alloc(size_t sz)79 static void *teec_paged_aligned_alloc(size_t sz)
80 {
81 void *p = NULL;
82
83 if (!posix_memalign(&p, sysconf(_SC_PAGESIZE), 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->fd = fd;
176 ctx->reg_mem = gen_caps & TEE_GEN_CAP_REG_MEM;
177 ctx->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->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->memref_null) {
222 /* Null pointer, indicate no shared memory attached */
223 MEMREF_SHM_ID(param) = TEE_MEMREF_NULL;
224 shm->id = -1;
225 } else {
226 res = TEEC_AllocateSharedMemory(ctx, shm);
227 if (res != TEEC_SUCCESS)
228 return res;
229 MEMREF_SHM_ID(param) = shm->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->shadow_buffer)
238 memcpy(shm->shadow_buffer, tmpref->buffer,
239 tmpref->size);
240
241 MEMREF_SHM_ID(param) = shm->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->shadow_buffer && (flags & TEEC_MEM_INPUT))
273 memcpy(shm->shadow_buffer, shm->buffer, shm->size);
274
275 MEMREF_SHM_ID(param) = shm->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->shadow_buffer && param_type != TEEC_MEMREF_PARTIAL_OUTPUT)
320 memcpy((char *)shm->shadow_buffer + memref->offset,
321 (char *)shm->buffer + memref->offset, memref->size);
322
323 MEMREF_SHM_ID(param) = shm->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].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->shadow_buffer)
404 memcpy(tmpref->buffer, shm->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->shadow_buffer && MEMREF_SIZE(param) <= shm->size)
424 memcpy(shm->buffer, shm->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->shadow_buffer && MEMREF_SIZE(param) <= memref->size)
444 memcpy((char *)shm->buffer + memref->offset,
445 (char *)shm->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->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->ctx = ctx;
652 session->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->session_id;
674 if (ioctl(session->ctx->fd, TEE_IOC_CLOSE_SESSION, &arg))
675 EMSG("Failed to close session 0x%x", session->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 bm_timestamp();
707
708 buf_data.buf_ptr = (uintptr_t)&buf;
709 buf_data.buf_len = sizeof(buf);
710
711 arg = &buf.arg;
712 arg->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
713 params = (struct tee_ioctl_param *)(arg + 1);
714
715 arg->session = session->session_id;
716 arg->func = cmd_id;
717
718 if (operation) {
719 teec_mutex_lock(&teec_mutex);
720 operation->session = session;
721 teec_mutex_unlock(&teec_mutex);
722 }
723
724 res = teec_pre_process_operation(session->ctx, operation, params, shm);
725 if (res != TEEC_SUCCESS) {
726 eorig = TEEC_ORIGIN_API;
727 goto out_free_temp_refs;
728 }
729
730 rc = ioctl(session->ctx->fd, TEE_IOC_INVOKE, &buf_data);
731 if (rc) {
732 EMSG("TEE_IOC_INVOKE failed");
733 eorig = TEEC_ORIGIN_COMMS;
734 res = ioctl_errno_to_res(errno);
735 goto out_free_temp_refs;
736 }
737
738 res = arg->ret;
739 eorig = arg->ret_origin;
740 teec_post_process_operation(operation, params, shm);
741
742 bm_timestamp();
743
744 out_free_temp_refs:
745 teec_free_temp_refs(operation, shm);
746 out:
747 if (error_origin)
748 *error_origin = eorig;
749 return res;
750 }
751
TEEC_RequestCancellation(TEEC_Operation * operation)752 void TEEC_RequestCancellation(TEEC_Operation *operation)
753 {
754 TEEC_Session *session = NULL;
755 struct tee_ioctl_cancel_arg arg;
756
757 memset(&arg, 0, sizeof(arg));
758
759 if (!operation)
760 return;
761
762 teec_mutex_lock(&teec_mutex);
763 session = operation->session;
764 teec_mutex_unlock(&teec_mutex);
765
766 if (!session)
767 return;
768
769 arg.session = session->session_id;
770 arg.cancel_id = 0;
771
772 if (ioctl(session->ctx->fd, TEE_IOC_CANCEL, &arg))
773 EMSG("TEE_IOC_CANCEL: %s", strerror(errno));
774 }
775
TEEC_RegisterSharedMemory(TEEC_Context * ctx,TEEC_SharedMemory * shm)776 TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm)
777 {
778 TEEC_Result res = TEEC_SUCCESS;
779 int fd = 0;
780 size_t s = 0;
781
782 if (!ctx || !shm)
783 return TEEC_ERROR_BAD_PARAMETERS;
784
785 if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)))
786 return TEEC_ERROR_BAD_PARAMETERS;
787
788 if (!shm->buffer)
789 return TEEC_ERROR_BAD_PARAMETERS;
790
791 s = shm->size;
792 if (!s)
793 s = 8;
794 if (ctx->reg_mem) {
795 fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id);
796 if (fd >= 0) {
797 shm->registered_fd = fd;
798 shm->shadow_buffer = NULL;
799 shm->internal.flags = 0;
800 goto out;
801 }
802
803 /*
804 * If we're here TEE_IOC_SHM_REGISTER failed, probably
805 * because some read-only memory was supplied and the Linux
806 * kernel doesn't like that at the moment.
807 *
808 * The error could also have some other origin. In any case
809 * we're not making matters worse by trying to allocate and
810 * register a shadow buffer before giving up.
811 */
812 shm->shadow_buffer = teec_paged_aligned_alloc(s);
813 if (!shm->shadow_buffer)
814 return TEEC_ERROR_OUT_OF_MEMORY;
815 fd = teec_shm_register(ctx->fd, shm->shadow_buffer, s,
816 &shm->id);
817 if (fd >= 0) {
818 shm->registered_fd = fd;
819 shm->internal.flags = SHM_FLAG_SHADOW_BUFFER_ALLOCED;
820 goto out;
821 }
822
823 if (errno == ENOMEM)
824 res = TEEC_ERROR_OUT_OF_MEMORY;
825 else
826 res = TEEC_ERROR_GENERIC;
827 free(shm->shadow_buffer);
828 shm->shadow_buffer = NULL;
829 return res;
830 } else {
831 fd = teec_shm_alloc(ctx->fd, s, &shm->id);
832 if (fd < 0)
833 return TEEC_ERROR_OUT_OF_MEMORY;
834
835 shm->shadow_buffer = mmap(NULL, s, PROT_READ | PROT_WRITE,
836 MAP_SHARED, fd, 0);
837 close(fd);
838 if (shm->shadow_buffer == (void *)MAP_FAILED) {
839 shm->id = -1;
840 return TEEC_ERROR_OUT_OF_MEMORY;
841 }
842 shm->registered_fd = -1;
843 shm->internal.flags = 0;
844 }
845
846 out:
847 shm->alloced_size = s;
848 return TEEC_SUCCESS;
849 }
850
TEEC_RegisterSharedMemoryFileDescriptor(TEEC_Context * ctx,TEEC_SharedMemory * shm,int fd)851 TEEC_Result TEEC_RegisterSharedMemoryFileDescriptor(TEEC_Context *ctx,
852 TEEC_SharedMemory *shm,
853 int fd)
854 {
855 int rfd = 0;
856 struct tee_ioctl_shm_register_fd_data data;
857
858 memset(&data, 0, sizeof(data));
859
860 if (!ctx || !shm || fd < 0)
861 return TEEC_ERROR_BAD_PARAMETERS;
862
863 if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)))
864 return TEEC_ERROR_BAD_PARAMETERS;
865
866 data.fd = fd;
867 rfd = ioctl(ctx->fd, TEE_IOC_SHM_REGISTER_FD, &data);
868 if (rfd < 0)
869 return TEEC_ERROR_BAD_PARAMETERS;
870
871 shm->buffer = NULL;
872 shm->shadow_buffer = NULL;
873 shm->registered_fd = rfd;
874 shm->id = data.id;
875 shm->size = data.size;
876 return TEEC_SUCCESS;
877 }
878
TEEC_AllocateSharedMemory(TEEC_Context * ctx,TEEC_SharedMemory * shm)879 TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm)
880 {
881 int fd = 0;
882 size_t s = 0;
883
884 if (!ctx || !shm)
885 return TEEC_ERROR_BAD_PARAMETERS;
886
887 if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)))
888 return TEEC_ERROR_BAD_PARAMETERS;
889
890 s = shm->size;
891 if (!s)
892 s = 8;
893
894 if (ctx->reg_mem) {
895 shm->buffer = teec_paged_aligned_alloc(s);
896 if (!shm->buffer)
897 return TEEC_ERROR_OUT_OF_MEMORY;
898
899 fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id);
900 if (fd < 0) {
901 free(shm->buffer);
902 shm->buffer = NULL;
903 return TEEC_ERROR_OUT_OF_MEMORY;
904 }
905 shm->registered_fd = fd;
906 } else {
907 fd = teec_shm_alloc(ctx->fd, s, &shm->id);
908 if (fd < 0)
909 return TEEC_ERROR_OUT_OF_MEMORY;
910
911 shm->buffer = mmap(NULL, s, PROT_READ | PROT_WRITE,
912 MAP_SHARED, fd, 0);
913 close(fd);
914 if (shm->buffer == (void *)MAP_FAILED) {
915 shm->id = -1;
916 return TEEC_ERROR_OUT_OF_MEMORY;
917 }
918 shm->registered_fd = -1;
919 }
920
921 shm->shadow_buffer = NULL;
922 shm->alloced_size = s;
923 shm->internal.flags = SHM_FLAG_BUFFER_ALLOCED;
924 return TEEC_SUCCESS;
925 }
926
TEEC_ReleaseSharedMemory(TEEC_SharedMemory * shm)927 void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *shm)
928 {
929 if (!shm || shm->id == -1)
930 return;
931
932 if (shm->shadow_buffer) {
933 if (shm->registered_fd >= 0) {
934 if (shm->internal.flags &
935 SHM_FLAG_SHADOW_BUFFER_ALLOCED)
936 free(shm->shadow_buffer);
937 close(shm->registered_fd);
938 } else {
939 munmap(shm->shadow_buffer, shm->alloced_size);
940 }
941 } else if (shm->buffer) {
942 if (shm->registered_fd >= 0) {
943 if (shm->internal.flags & SHM_FLAG_BUFFER_ALLOCED)
944 free(shm->buffer);
945 close(shm->registered_fd);
946 } else {
947 munmap(shm->buffer, shm->alloced_size);
948 }
949 } else if (shm->registered_fd >= 0) {
950 close(shm->registered_fd);
951 }
952
953 shm->id = -1;
954 shm->shadow_buffer = NULL;
955 shm->buffer = NULL;
956 shm->registered_fd = -1;
957 shm->internal.flags = 0;
958 }
959