1 /*
2 * Copyright (c) 2014, STMicroelectronics International N.V.
3 * All rights reserved.
4 * Copyright (c) 2015, Linaro Limited
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <assert.h>
31 #include <dirent.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <getopt.h>
35 #include <inttypes.h>
36 #include <prof.h>
37 #include <plugin.h>
38 #include <pthread.h>
39 #include <rpmb.h>
40 #include <stdbool.h>
41 #include <stdint.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/ioctl.h>
46 #include <sys/mman.h>
47 #include <sys/stat.h>
48 #include <sys/time.h>
49 #include <sys/types.h>
50 #include <tee_client_api.h>
51 #include <teec_ta_load.h>
52 #include <teec_trace.h>
53 #include <tee_socket.h>
54 #include <tee_supp_fs.h>
55 #include <tee_supplicant.h>
56 #include <unistd.h>
57
58 #include "optee_msg_supplicant.h"
59
60 #ifndef __aligned
61 #define __aligned(x) __attribute__((__aligned__(x)))
62 #endif
63 #include <linux/tee.h>
64
65 #define RPC_NUM_PARAMS 5
66
67 #define RPC_BUF_SIZE (sizeof(struct tee_iocl_supp_send_arg) + \
68 RPC_NUM_PARAMS * sizeof(struct tee_ioctl_param))
69
70 char **ta_path;
71 char *ta_path_str;
72
73 union tee_rpc_invoke {
74 uint64_t buf[(RPC_BUF_SIZE - 1) / sizeof(uint64_t) + 1];
75 struct tee_iocl_supp_recv_arg recv;
76 struct tee_iocl_supp_send_arg send;
77 };
78
79 struct tee_shm {
80 int id;
81 void *p;
82 size_t size;
83 bool registered;
84 int fd;
85 struct tee_shm *next;
86 };
87
88 struct thread_arg {
89 int fd;
90 uint32_t gen_caps;
91 bool abort;
92 size_t num_waiters;
93 pthread_mutex_t mutex;
94 };
95
96 struct param_value {
97 uint64_t a;
98 uint64_t b;
99 uint64_t c;
100 };
101
102 static pthread_mutex_t shm_mutex = PTHREAD_MUTEX_INITIALIZER;
103 static struct tee_shm *shm_head;
104
105 struct tee_supplicant_params supplicant_params = {
106 .ta_dir = "optee_armtz",
107 #ifdef TEE_PLUGIN_LOAD_PATH
108 .plugin_load_path = TEE_PLUGIN_LOAD_PATH,
109 #endif
110 .fs_parent_path = TEE_FS_PARENT_PATH,
111 };
112
113 static void *thread_main(void *a);
114
num_waiters_inc(struct thread_arg * arg)115 static size_t num_waiters_inc(struct thread_arg *arg)
116 {
117 size_t ret = 0;
118
119 tee_supp_mutex_lock(&arg->mutex);
120 arg->num_waiters++;
121 assert(arg->num_waiters);
122 ret = arg->num_waiters;
123 tee_supp_mutex_unlock(&arg->mutex);
124
125 return ret;
126 }
127
num_waiters_dec(struct thread_arg * arg)128 static size_t num_waiters_dec(struct thread_arg *arg)
129 {
130 size_t ret = 0;
131
132 tee_supp_mutex_lock(&arg->mutex);
133 assert(arg->num_waiters);
134 arg->num_waiters--;
135 ret = arg->num_waiters;
136 tee_supp_mutex_unlock(&arg->mutex);
137
138 return ret;
139 }
140
paged_aligned_alloc(size_t sz)141 static void *paged_aligned_alloc(size_t sz)
142 {
143 void *p = NULL;
144
145 if (!posix_memalign(&p, sysconf(_SC_PAGESIZE), sz))
146 return p;
147
148 return NULL;
149 }
150
get_value(size_t num_params,struct tee_ioctl_param * params,const uint32_t idx,struct param_value ** value)151 static int get_value(size_t num_params, struct tee_ioctl_param *params,
152 const uint32_t idx, struct param_value **value)
153 {
154 if (idx >= num_params)
155 return -1;
156
157 switch (params[idx].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
158 case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
159 case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
160 case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
161 *value = (void *)¶ms[idx].a;
162 return 0;
163 default:
164 return -1;
165 }
166 }
167
find_tshm(int id)168 static struct tee_shm *find_tshm(int id)
169 {
170 struct tee_shm *tshm = NULL;
171
172 tee_supp_mutex_lock(&shm_mutex);
173
174 tshm = shm_head;
175 while (tshm && tshm->id != id)
176 tshm = tshm->next;
177
178 tee_supp_mutex_unlock(&shm_mutex);
179
180 return tshm;
181 }
182
pop_tshm(int id)183 static struct tee_shm *pop_tshm(int id)
184 {
185 struct tee_shm *tshm = NULL;
186 struct tee_shm *prev = NULL;
187
188 tee_supp_mutex_lock(&shm_mutex);
189
190 tshm = shm_head;
191 if (!tshm)
192 goto out;
193
194 if (tshm->id == id) {
195 shm_head = tshm->next;
196 goto out;
197 }
198
199 do {
200 prev = tshm;
201 tshm = tshm->next;
202 if (!tshm)
203 goto out;
204 } while (tshm->id != id);
205 prev->next = tshm->next;
206
207 out:
208 tee_supp_mutex_unlock(&shm_mutex);
209
210 return tshm;
211 }
212
push_tshm(struct tee_shm * tshm)213 static void push_tshm(struct tee_shm *tshm)
214 {
215 tee_supp_mutex_lock(&shm_mutex);
216
217 tshm->next = shm_head;
218 shm_head = tshm;
219
220 tee_supp_mutex_unlock(&shm_mutex);
221 }
222
223 /* Get parameter allocated by secure world */
get_param(size_t num_params,struct tee_ioctl_param * params,const uint32_t idx,TEEC_SharedMemory * shm)224 static int get_param(size_t num_params, struct tee_ioctl_param *params,
225 const uint32_t idx, TEEC_SharedMemory *shm)
226 {
227 struct tee_shm *tshm = NULL;
228 size_t offs = 0;
229 size_t sz = 0;
230
231 if (idx >= num_params)
232 return -1;
233
234 switch (params[idx].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
235 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
236 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
237 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
238 break;
239 default:
240 return -1;
241 }
242
243 memset(shm, 0, sizeof(*shm));
244
245 tshm = find_tshm(MEMREF_SHM_ID(params + idx));
246 if (!tshm) {
247 /*
248 * It doesn't make sense to query required size of an
249 * input buffer.
250 */
251 if ((params[idx].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) ==
252 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
253 return -1;
254
255 /*
256 * Buffer isn't found, the caller is querying required size
257 * of the buffer.
258 */
259 return 0;
260 }
261
262 sz = MEMREF_SIZE(params + idx);
263 offs = MEMREF_SHM_OFFS(params + idx);
264 if ((sz + offs) < sz)
265 return -1;
266 if ((sz + offs) > tshm->size)
267 return -1;
268
269 shm->flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
270 shm->size = sz;
271 shm->id = MEMREF_SHM_ID(params + idx);
272 shm->buffer = (uint8_t *)tshm->p + offs;
273
274 return 0;
275 }
276
uuid_from_octets(TEEC_UUID * d,const uint8_t s[TEE_IOCTL_UUID_LEN])277 static void uuid_from_octets(TEEC_UUID *d, const uint8_t s[TEE_IOCTL_UUID_LEN])
278 {
279 d->timeLow = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
280 d->timeMid = (s[4] << 8) | s[5];
281 d->timeHiAndVersion = (s[6] << 8) | s[7];
282 memcpy(d->clockSeqAndNode, s + 8, sizeof(d->clockSeqAndNode));
283 }
284
load_ta(size_t num_params,struct tee_ioctl_param * params)285 static uint32_t load_ta(size_t num_params, struct tee_ioctl_param *params)
286 {
287 int ta_found = 0;
288 size_t size = 0;
289 struct param_value *val_cmd = NULL;
290 TEEC_UUID uuid;
291 TEEC_SharedMemory shm_ta;
292
293 memset(&uuid, 0, sizeof(uuid));
294 memset(&shm_ta, 0, sizeof(shm_ta));
295
296 if (num_params != 2 || get_value(num_params, params, 0, &val_cmd) ||
297 get_param(num_params, params, 1, &shm_ta))
298 return TEEC_ERROR_BAD_PARAMETERS;
299
300 uuid_from_octets(&uuid, (void *)val_cmd);
301
302 size = shm_ta.size;
303 ta_found = TEECI_LoadSecureModule(supplicant_params.ta_dir, &uuid, shm_ta.buffer, &size);
304 if (ta_found != TA_BINARY_FOUND) {
305 EMSG(" TA not found");
306 return TEEC_ERROR_ITEM_NOT_FOUND;
307 }
308
309 MEMREF_SIZE(params + 1) = size;
310
311 /*
312 * If a buffer wasn't provided, just tell which size it should be.
313 * If it was provided but isn't big enough, report an error.
314 */
315 if (shm_ta.buffer && size > shm_ta.size)
316 return TEEC_ERROR_SHORT_BUFFER;
317
318 return TEEC_SUCCESS;
319 }
320
alloc_shm(int fd,size_t size)321 static struct tee_shm *alloc_shm(int fd, size_t size)
322 {
323 struct tee_shm *shm = NULL;
324 struct tee_ioctl_shm_alloc_data data;
325
326 memset(&data, 0, sizeof(data));
327
328 shm = calloc(1, sizeof(*shm));
329 if (!shm)
330 return NULL;
331
332 data.size = size;
333 shm->fd = ioctl(fd, TEE_IOC_SHM_ALLOC, &data);
334 if (shm->fd < 0) {
335 free(shm);
336 return NULL;
337 }
338
339 shm->p = mmap(NULL, data.size, PROT_READ | PROT_WRITE, MAP_SHARED,
340 shm->fd, 0);
341 if (shm->p == (void *)MAP_FAILED) {
342 close(shm->fd);
343 free(shm);
344 return NULL;
345 }
346
347 shm->id = data.id;
348 shm->registered = false;
349 return shm;
350 }
351
register_local_shm(int fd,size_t size)352 static struct tee_shm *register_local_shm(int fd, size_t size)
353 {
354 struct tee_shm *shm = NULL;
355 void *buf = NULL;
356 struct tee_ioctl_shm_register_data data;
357
358 memset(&data, 0, sizeof(data));
359
360 buf = paged_aligned_alloc(size);
361 if (!buf)
362 return NULL;
363
364 shm = calloc(1, sizeof(*shm));
365 if (!shm) {
366 free(buf);
367 return NULL;
368 }
369
370 data.addr = (uintptr_t)buf;
371 data.length = size;
372
373 shm->fd = ioctl(fd, TEE_IOC_SHM_REGISTER, &data);
374 if (shm->fd < 0) {
375 free(shm);
376 free(buf);
377 return NULL;
378 }
379
380 shm->p = buf;
381 shm->registered = true;
382 shm->id = data.id;
383
384 return shm;
385 }
386
process_alloc(struct thread_arg * arg,size_t num_params,struct tee_ioctl_param * params)387 static uint32_t process_alloc(struct thread_arg *arg, size_t num_params,
388 struct tee_ioctl_param *params)
389 {
390 struct param_value *val = NULL;
391 struct tee_shm *shm = NULL;
392
393 if (num_params != 1 || get_value(num_params, params, 0, &val))
394 return TEEC_ERROR_BAD_PARAMETERS;
395
396 if (arg->gen_caps & TEE_GEN_CAP_REG_MEM)
397 shm = register_local_shm(arg->fd, val->b);
398 else
399 shm = alloc_shm(arg->fd, val->b);
400
401 if (!shm)
402 return TEEC_ERROR_OUT_OF_MEMORY;
403
404 shm->size = val->b;
405 val->c = shm->id;
406 push_tshm(shm);
407
408 return TEEC_SUCCESS;
409 }
410
process_free(size_t num_params,struct tee_ioctl_param * params)411 static uint32_t process_free(size_t num_params, struct tee_ioctl_param *params)
412 {
413 struct param_value *val = NULL;
414 struct tee_shm *shm = NULL;
415 int id = 0;
416
417 if (num_params != 1 || get_value(num_params, params, 0, &val))
418 return TEEC_ERROR_BAD_PARAMETERS;
419
420 id = val->b;
421
422 shm = pop_tshm(id);
423 if (!shm)
424 return TEEC_ERROR_BAD_PARAMETERS;
425
426 close(shm->fd);
427 if (shm->registered) {
428 free(shm->p);
429 } else {
430 if (munmap(shm->p, shm->size) != 0) {
431 EMSG("munmap(%p, %zu) failed - Error = %s",
432 shm->p, shm->size, strerror(errno));
433 free(shm);
434 return TEEC_ERROR_BAD_PARAMETERS;
435 }
436 }
437
438 free(shm);
439 return TEEC_SUCCESS;
440 }
441
442
443
444 /* How many device sequence numbers will be tried before giving up */
445 #define MAX_DEV_SEQ 10
446
open_dev(const char * devname,uint32_t * gen_caps)447 static int open_dev(const char *devname, uint32_t *gen_caps)
448 {
449 int fd = 0;
450 struct tee_ioctl_version_data vers;
451
452 memset(&vers, 0, sizeof(vers));
453
454 fd = open(devname, O_RDWR);
455 if (fd < 0)
456 return -1;
457
458 if (ioctl(fd, TEE_IOC_VERSION, &vers))
459 goto err;
460
461 /* Only OP-TEE supported */
462 if (vers.impl_id != TEE_IMPL_ID_OPTEE)
463 goto err;
464
465 if (gen_caps)
466 *gen_caps = vers.gen_caps;
467
468 DMSG("using device \"%s\"", devname);
469 return fd;
470 err:
471 close(fd);
472 return -1;
473 }
474
get_dev_fd(uint32_t * gen_caps)475 static int get_dev_fd(uint32_t *gen_caps)
476 {
477 int fd = 0;
478 char name[PATH_MAX] = { 0 };
479 size_t n = 0;
480
481 for (n = 0; n < MAX_DEV_SEQ; n++) {
482 snprintf(name, sizeof(name), "/dev/teepriv%zu", n);
483 fd = open_dev(name, gen_caps);
484 if (fd >= 0)
485 return fd;
486 }
487 return -1;
488 }
489
usage(int status)490 static int usage(int status)
491 {
492 fprintf(stderr, "Usage: tee-supplicant [options] [<device-name>]\n");
493 fprintf(stderr, "\t-h, --help: this help\n");
494 fprintf(stderr, "\t-d, --daemonize: run as a daemon (fork and return "
495 "after child has opened the TEE device or on error)\n");
496 fprintf(stderr, "\t-f, --fs-parent-path: secure fs parent path [%s]\n",
497 supplicant_params.fs_parent_path);
498 fprintf(stderr, "\t-t, --ta-dir: TAs dirname under %s [%s]\n", TEEC_LOAD_PATH,
499 supplicant_params.ta_dir);
500 fprintf(stderr, "\t-p, --plugin-path: plugin load path [%s]\n",
501 supplicant_params.plugin_load_path);
502 fprintf(stderr, "\t-r, --rpmb-cid: RPMB device identification register "
503 "(CID) in hexadecimal\n");
504 return status;
505 }
506
process_rpmb(size_t num_params,struct tee_ioctl_param * params)507 static uint32_t process_rpmb(size_t num_params, struct tee_ioctl_param *params)
508 {
509 TEEC_SharedMemory req;
510 TEEC_SharedMemory rsp;
511
512 memset(&req, 0, sizeof(req));
513 memset(&rsp, 0, sizeof(rsp));
514
515 if (get_param(num_params, params, 0, &req) ||
516 get_param(num_params, params, 1, &rsp))
517 return TEEC_ERROR_BAD_PARAMETERS;
518
519 return rpmb_process_request(req.buffer, req.size, rsp.buffer, rsp.size);
520 }
521
read_request(int fd,union tee_rpc_invoke * request)522 static bool read_request(int fd, union tee_rpc_invoke *request)
523 {
524 struct tee_ioctl_buf_data data;
525
526 memset(&data, 0, sizeof(data));
527
528 data.buf_ptr = (uintptr_t)request;
529 data.buf_len = sizeof(*request);
530 if (ioctl(fd, TEE_IOC_SUPPL_RECV, &data)) {
531 EMSG("TEE_IOC_SUPPL_RECV: %s", strerror(errno));
532 return false;
533 }
534 return true;
535 }
536
write_response(int fd,union tee_rpc_invoke * request)537 static bool write_response(int fd, union tee_rpc_invoke *request)
538 {
539 struct tee_ioctl_buf_data data;
540
541 memset(&data, 0, sizeof(data));
542
543 data.buf_ptr = (uintptr_t)&request->send;
544 data.buf_len = sizeof(struct tee_iocl_supp_send_arg) +
545 sizeof(struct tee_ioctl_param) *
546 (__u64)request->send.num_params;
547 if (ioctl(fd, TEE_IOC_SUPPL_SEND, &data)) {
548 EMSG("TEE_IOC_SUPPL_SEND: %s", strerror(errno));
549 return false;
550 }
551 return true;
552 }
553
find_params(union tee_rpc_invoke * request,uint32_t * func,size_t * num_params,struct tee_ioctl_param ** params,size_t * num_meta)554 static bool find_params(union tee_rpc_invoke *request, uint32_t *func,
555 size_t *num_params, struct tee_ioctl_param **params,
556 size_t *num_meta)
557 {
558 struct tee_ioctl_param *p = NULL;
559 size_t n = 0;
560
561 p = (struct tee_ioctl_param *)(&request->recv + 1);
562
563 /* Skip meta parameters in the front */
564 for (n = 0; n < request->recv.num_params; n++)
565 if (!(p[n].attr & TEE_IOCTL_PARAM_ATTR_META))
566 break;
567
568 *func = request->recv.func;
569 *num_params = request->recv.num_params - n;
570 *params = p + n;
571 *num_meta = n;
572
573 /* Make sure that no meta parameters follows a non-meta parameter */
574 for (; n < request->recv.num_params; n++) {
575 if (p[n].attr & TEE_IOCTL_PARAM_ATTR_META) {
576 EMSG("Unexpected meta parameter");
577 return false;
578 }
579 }
580
581 return true;
582 }
583
spawn_thread(struct thread_arg * arg)584 static bool spawn_thread(struct thread_arg *arg)
585 {
586 int e = 0;
587 pthread_t tid;
588
589 memset(&tid, 0, sizeof(tid));
590
591 DMSG("Spawning a new thread");
592
593 /*
594 * Increase number of waiters now to avoid starting another thread
595 * before this thread has been scheduled.
596 */
597 num_waiters_inc(arg);
598
599 e = pthread_create(&tid, NULL, thread_main, arg);
600 if (e) {
601 EMSG("pthread_create: %s", strerror(e));
602 num_waiters_dec(arg);
603 return false;
604 }
605
606 e = pthread_detach(tid);
607 if (e)
608 EMSG("pthread_detach: %s", strerror(e));
609
610 return true;
611 }
612
process_one_request(struct thread_arg * arg)613 static bool process_one_request(struct thread_arg *arg)
614 {
615 size_t num_params = 0;
616 size_t num_meta = 0;
617 struct tee_ioctl_param *params = NULL;
618 uint32_t func = 0;
619 uint32_t ret = 0;
620 union tee_rpc_invoke request;
621
622 memset(&request, 0, sizeof(request));
623
624 DMSG("looping");
625 request.recv.num_params = RPC_NUM_PARAMS;
626
627 /* Let it be known that we can deal with meta parameters */
628 params = (struct tee_ioctl_param *)(&request.send + 1);
629 params->attr = TEE_IOCTL_PARAM_ATTR_META;
630
631 num_waiters_inc(arg);
632
633 if (!read_request(arg->fd, &request))
634 return false;
635
636 if (!find_params(&request, &func, &num_params, ¶ms, &num_meta))
637 return false;
638
639 if (num_meta && !num_waiters_dec(arg) && !spawn_thread(arg))
640 return false;
641
642 switch (func) {
643 case OPTEE_MSG_RPC_CMD_LOAD_TA:
644 ret = load_ta(num_params, params);
645 break;
646 case OPTEE_MSG_RPC_CMD_FS:
647 ret = tee_supp_fs_process(num_params, params);
648 break;
649 case OPTEE_MSG_RPC_CMD_RPMB:
650 ret = process_rpmb(num_params, params);
651 break;
652 case OPTEE_MSG_RPC_CMD_SHM_ALLOC:
653 ret = process_alloc(arg, num_params, params);
654 break;
655 case OPTEE_MSG_RPC_CMD_SHM_FREE:
656 ret = process_free(num_params, params);
657 break;
658 case OPTEE_MSG_RPC_CMD_GPROF:
659 ret = prof_process(num_params, params, "gmon-");
660 break;
661 case OPTEE_MSG_RPC_CMD_SOCKET:
662 ret = tee_socket_process(num_params, params);
663 break;
664 case OPTEE_MSG_RPC_CMD_FTRACE:
665 ret = prof_process(num_params, params, "ftrace-");
666 break;
667 case OPTEE_MSG_RPC_CMD_PLUGIN:
668 ret = plugin_process(num_params, params);
669 break;
670 default:
671 EMSG("Cmd [0x%" PRIx32 "] not supported", func);
672 /* Not supported. */
673 ret = TEEC_ERROR_NOT_SUPPORTED;
674 break;
675 }
676
677 request.send.ret = ret;
678 return write_response(arg->fd, &request);
679 }
680
thread_main(void * a)681 static void *thread_main(void *a)
682 {
683 struct thread_arg *arg = a;
684
685 /*
686 * Now that this thread has been scheduled, compensate for the
687 * initial increase in spawn_thread() before.
688 */
689 num_waiters_dec(arg);
690
691 while (!arg->abort) {
692 if (!process_one_request(arg))
693 arg->abort = true;
694 }
695
696 return NULL;
697 }
698
699 #define TEEC_TEST_LOAD_PATH "/foo:/bar::/baz"
700
set_ta_path(void)701 static void set_ta_path(void)
702 {
703 char *p = NULL;
704 char *saveptr = NULL;
705 const char *path = (char *)
706 #ifdef TEEC_TEST_LOAD_PATH
707 TEEC_TEST_LOAD_PATH ":"
708 #endif
709 TEEC_LOAD_PATH;
710 size_t n = 0;
711
712 ta_path_str = strdup(path);
713 if (!ta_path_str)
714 goto err;
715
716 p = ta_path_str;
717 while (strtok_r(p, ":", &saveptr)) {
718 p = NULL;
719 n++;
720 }
721 n++; /* NULL terminator */
722
723 ta_path = malloc(n * sizeof(char *));
724 if (!ta_path)
725 goto err;
726
727 n = 0;
728 strcpy(ta_path_str, path);
729 p = ta_path_str;
730 while ((ta_path[n++] = strtok_r(p, ":", &saveptr)))
731 p = NULL;
732
733 return;
734 err:
735 EMSG("out of memory");
736 exit(EXIT_FAILURE);
737 }
738
739 /*
740 * Similar to the standard libc function daemon(0, 0) but the parent process
741 * issues a blocking read on pipefd[0] before exiting.
742 * Returns 0 on success, <0 on error.
743 */
make_daemon(int pipefd[2])744 static int make_daemon(int pipefd[2])
745 {
746 int fd = 0;
747 char c = 0;
748 int n = 0;
749
750 switch (fork()) {
751 case -1:
752 return -1;
753 case 0:
754 /* In child */
755 close(pipefd[0]);
756 break;
757 default:
758 /* In parent */
759 close(pipefd[1]);
760 n = read(pipefd[0], &c, 1);
761 close(pipefd[0]);
762 if (!n) {
763 /*
764 * Nothing has been read: child has closed without
765 * writing (either exited on error or crashed)
766 */
767 return -1;
768 }
769 /* Child is done with the opening of the TEE device */
770 _exit(EXIT_SUCCESS);
771 }
772
773 if (setsid() < 0)
774 return -2;
775
776 if (chdir("/") < 0)
777 return -3;
778
779 fd = open("/dev/null", O_RDWR);
780 if (fd < 0)
781 return -4;
782 dup2(fd, 0);
783 dup2(fd, 1);
784 dup2(fd, 2);
785 close(fd);
786
787 return 0;
788 }
789
main(int argc,char * argv[])790 int main(int argc, char *argv[])
791 {
792 struct thread_arg arg = { .fd = -1 };
793 int pipefd[2] = { 0, };
794 bool daemonize = false;
795 char *dev = NULL;
796 int e = 0;
797 int long_index = 0;
798 int opt = 0;
799
800 e = pthread_mutex_init(&arg.mutex, NULL);
801 if (e) {
802 EMSG("pthread_mutex_init: %s", strerror(e));
803 EMSG("terminating...");
804 exit(EXIT_FAILURE);
805 }
806
807 static struct option long_options[] = {
808 /* long name | has argument | flag | short value */
809 { "help", no_argument, 0, 'h' },
810 { "daemonize", no_argument, 0, 'd' },
811 { "fs-parent-path", required_argument, 0, 'f' },
812 { "ta-dir", required_argument, 0, 't' },
813 { "plugin-path", required_argument, 0, 'p' },
814 { "rpmb-cid", required_argument, 0, 'r' },
815 { 0, 0, 0, 0 }
816 };
817
818 while ((opt = getopt_long(argc, argv, "hdf:t:p:r:",
819 long_options, &long_index )) != -1) {
820 switch (opt) {
821 case 'h' :
822 return usage(EXIT_SUCCESS);
823 break;
824 case 'd':
825 daemonize = true;
826 break;
827 case 'f':
828 supplicant_params.fs_parent_path = optarg;
829 break;
830 case 't':
831 supplicant_params.ta_dir = optarg;
832 break;
833 case 'p':
834 supplicant_params.plugin_load_path = optarg;
835 break;
836 case 'r':
837 supplicant_params.rpmb_cid = optarg;
838 break;
839 default:
840 return usage(EXIT_FAILURE);
841 }
842 }
843 /* check for non option argument, which is device name */
844 if (argv[optind]) {
845 fprintf(stderr, "Using device %s.\n", argv[optind]);
846 dev = argv[optind];
847 /* check that we do not have too many arguments */
848 if (argv[optind + 1]) {
849 fprintf(stderr, "Too many arguments passed: extra argument: %s.\n",
850 argv[optind+1]);
851 return usage(EXIT_FAILURE);
852 }
853 }
854
855
856 set_ta_path();
857
858 if (plugin_load_all() != 0) {
859 EMSG("failed to load plugins");
860 exit(EXIT_FAILURE);
861 }
862
863 if (daemonize) {
864 if (pipe(pipefd) < 0) {
865 EMSG("pipe(): %s", strerror(errno));
866 exit(EXIT_FAILURE);
867 }
868 e = make_daemon(pipefd);
869 if (e < 0) {
870 EMSG("make_daemon(): %d", e);
871 exit(EXIT_FAILURE);
872 }
873 }
874
875 if (dev) {
876 arg.fd = open_dev(dev, &arg.gen_caps);
877 if (arg.fd < 0) {
878 EMSG("failed to open \"%s\"", argv[1]);
879 exit(EXIT_FAILURE);
880 }
881 } else {
882 arg.fd = get_dev_fd(&arg.gen_caps);
883 if (arg.fd < 0) {
884 EMSG("failed to find an OP-TEE supplicant device");
885 exit(EXIT_FAILURE);
886 }
887 }
888
889 if (daemonize) {
890 /* Release parent */
891 if (write(pipefd[1], "", 1) != 1) {
892 EMSG("write(): %s", strerror(errno));
893 exit(EXIT_FAILURE);
894 }
895 close(pipefd[1]);
896 }
897
898 while (!arg.abort) {
899 if (!process_one_request(&arg))
900 arg.abort = true;
901 }
902
903 close(arg.fd);
904
905 return EXIT_FAILURE;
906 }
907
tee_supp_param_is_memref(struct tee_ioctl_param * param)908 bool tee_supp_param_is_memref(struct tee_ioctl_param *param)
909 {
910 switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
911 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
912 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
913 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
914 return true;
915 default:
916 return false;
917 }
918 }
919
tee_supp_param_is_value(struct tee_ioctl_param * param)920 bool tee_supp_param_is_value(struct tee_ioctl_param *param)
921 {
922 switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
923 case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
924 case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
925 case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
926 return true;
927 default:
928 return false;
929 }
930 }
931
tee_supp_param_to_va(struct tee_ioctl_param * param)932 void *tee_supp_param_to_va(struct tee_ioctl_param *param)
933 {
934 struct tee_shm *tshm = NULL;
935 size_t end_offs = 0;
936
937 if (!tee_supp_param_is_memref(param))
938 return NULL;
939
940 end_offs = MEMREF_SIZE(param) + MEMREF_SHM_OFFS(param);
941 if (end_offs < MEMREF_SIZE(param) || end_offs < MEMREF_SHM_OFFS(param))
942 return NULL;
943
944 tshm = find_tshm(MEMREF_SHM_ID(param));
945 if (!tshm)
946 return NULL;
947
948 if (end_offs > tshm->size)
949 return NULL;
950
951 return (uint8_t *)tshm->p + MEMREF_SHM_OFFS(param);
952 }
953
tee_supp_mutex_lock(pthread_mutex_t * mu)954 void tee_supp_mutex_lock(pthread_mutex_t *mu)
955 {
956 int e = pthread_mutex_lock(mu);
957
958 if (e) {
959 EMSG("pthread_mutex_lock: %s", strerror(e));
960 EMSG("terminating...");
961 exit(EXIT_FAILURE);
962 }
963 }
964
tee_supp_mutex_unlock(pthread_mutex_t * mu)965 void tee_supp_mutex_unlock(pthread_mutex_t *mu)
966 {
967 int e = pthread_mutex_unlock(mu);
968
969 if (e) {
970 EMSG("pthread_mutex_unlock: %s", strerror(e));
971 EMSG("terminating...");
972 exit(EXIT_FAILURE);
973 }
974 }
975