1 /*
2 * Copyright (c) 2016-2017, 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 <assert.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <inttypes.h>
32 #include <limits.h>
33 #include <netdb.h>
34 #include <netinet/in.h>
35 #include <optee_msg_supplicant.h>
36 #include <poll.h>
37 #include <pthread.h>
38 #include <stdint.h>
39 #include <stdlib.h>
40 #include <sys/queue.h>
41 #include <sys/socket.h>
42 #include <tee_client_api.h>
43 #include <teec_trace.h>
44 #include <tee_socket.h>
45 #include <tee_supplicant.h>
46 #include <unistd.h>
47
48 #include "handle.h"
49 #include "__tee_isocket_defines.h"
50 #include "__tee_ipsocket.h"
51 #include "__tee_tcpsocket_defines.h"
52 #include "__tee_tcpsocket_defines_extensions.h"
53 #include "__tee_udpsocket_defines.h"
54
55 #ifndef __aligned
56 #define __aligned(x) __attribute__((__aligned__(x)))
57 #endif
58 #include <linux/tee.h>
59
60 /*
61 * Used when checking how much data we have queued.
62 *
63 * For SOCK_DGRAM we try to be accurate up to 4096 bytes as
64 * that's our arbitrary chosen sensible upper size (with
65 * some margin). Larger size doesn't make much sense since
66 * anything larger than the MTU is bound to cause trouble
67 * on a congested network.
68 *
69 * For SOCK_STREAM we chose the same upper limit for
70 * simplicity. It doesn't matter if there's more queued,
71 * no data will be lost.
72 */
73 #define SUPP_MAX_PEEK_LEN 4096
74
75 struct sock_instance {
76 uint32_t id;
77 struct handle_db db;
78 TAILQ_ENTRY(sock_instance) link;
79 };
80
81 static pthread_mutex_t sock_mutex = PTHREAD_MUTEX_INITIALIZER;
82 TAILQ_HEAD(, sock_instance) sock_instances =
83 TAILQ_HEAD_INITIALIZER(sock_instances);
84
sock_lock(void)85 static void sock_lock(void)
86 {
87 pthread_mutex_lock(&sock_mutex);
88 }
89
sock_unlock(void)90 static void sock_unlock(void)
91 {
92 pthread_mutex_unlock(&sock_mutex);
93 }
94
sock_instance_find(uint32_t instance_id)95 static struct sock_instance *sock_instance_find(uint32_t instance_id)
96 {
97 struct sock_instance *si = NULL;
98
99 TAILQ_FOREACH(si, &sock_instances, link) {
100 if (si->id == instance_id)
101 return si;
102 }
103 return NULL;
104 }
105
fd_to_handle_ptr(int fd)106 static void *fd_to_handle_ptr(int fd)
107 {
108 uintptr_t ptr = 0;
109
110 assert(fd >= 0);
111 ptr = fd + 1;
112 return (void *)ptr;
113 }
114
handle_ptr_to_fd(void * ptr)115 static int handle_ptr_to_fd(void *ptr)
116 {
117 assert(ptr);
118 return (uintptr_t)ptr - 1;
119 }
120
sock_handle_get(uint32_t instance_id,int fd)121 static int sock_handle_get(uint32_t instance_id, int fd)
122 {
123 int handle = -1;
124 struct sock_instance *si = NULL;
125
126 sock_lock();
127
128 si = sock_instance_find(instance_id);
129 if (!si) {
130 si = calloc(1, sizeof(*si));
131 if (!si)
132 goto out;
133 si->id = instance_id;
134 TAILQ_INSERT_TAIL(&sock_instances, si, link);
135 }
136
137 handle = handle_get(&si->db, fd_to_handle_ptr(fd));
138 out:
139 sock_unlock();
140 return handle;
141 }
142
sock_handle_to_fd(uint32_t instance_id,uint32_t handle)143 static int sock_handle_to_fd(uint32_t instance_id, uint32_t handle)
144 {
145 int fd = -1;
146 struct sock_instance *si = NULL;
147
148 sock_lock();
149 si = sock_instance_find(instance_id);
150 if (si)
151 fd = handle_ptr_to_fd(handle_lookup(&si->db, handle));
152 sock_unlock();
153 return fd;
154 }
155
sock_handle_put(uint32_t instance_id,uint32_t handle)156 static void sock_handle_put(uint32_t instance_id, uint32_t handle)
157 {
158 struct sock_instance *si = NULL;
159
160 sock_lock();
161 si = sock_instance_find(instance_id);
162 if (si)
163 handle_put(&si->db, handle);
164 sock_unlock();
165 }
166
chk_pt(struct tee_ioctl_param * param,uint32_t type)167 static bool chk_pt(struct tee_ioctl_param *param, uint32_t type)
168 {
169 return (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) == type;
170 }
171
fd_flags_add(int fd,int flags)172 static int fd_flags_add(int fd, int flags)
173 {
174 int val = 0;
175
176 val = fcntl(fd, F_GETFD, 0);
177 if (val == -1)
178 return -1;
179
180 val |= flags;
181
182 return fcntl(fd, F_SETFL, val);
183 }
184
sock_connect(uint32_t ip_vers,unsigned int protocol,const char * server,uint16_t port,int * ret_fd)185 static TEEC_Result sock_connect(uint32_t ip_vers, unsigned int protocol,
186 const char *server, uint16_t port, int *ret_fd)
187 {
188 TEEC_Result r = TEEC_ERROR_GENERIC;
189 struct addrinfo *res0 = NULL;
190 struct addrinfo *res = NULL;
191 int fd = -1;
192 char port_name[10] = { 0 };
193 struct addrinfo hints;
194
195 memset(&hints, 0, sizeof(hints));
196
197 snprintf(port_name, sizeof(port_name), "%" PRIu16, port);
198
199 switch (ip_vers) {
200 case TEE_IP_VERSION_DC:
201 hints.ai_family = AF_UNSPEC;
202 break;
203 case TEE_IP_VERSION_4:
204 hints.ai_family = AF_INET;
205 break;
206 case TEE_IP_VERSION_6:
207 hints.ai_family = AF_INET6;
208 break;
209 default:
210 return TEEC_ERROR_BAD_PARAMETERS;
211 }
212
213 if (protocol == TEE_ISOCKET_PROTOCOLID_TCP)
214 hints.ai_socktype = SOCK_STREAM;
215 else if (protocol == TEE_ISOCKET_PROTOCOLID_UDP)
216 hints.ai_socktype = SOCK_DGRAM;
217 else
218 return TEEC_ERROR_BAD_PARAMETERS;
219
220 if (getaddrinfo(server, port_name, &hints, &res0))
221 return TEE_ISOCKET_ERROR_HOSTNAME;
222
223 for (res = res0; res; res = res->ai_next) {
224 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
225 if (fd == -1) {
226 if (errno == ENOMEM || errno == ENOBUFS)
227 r = TEE_ISOCKET_ERROR_OUT_OF_RESOURCES;
228 else
229 r = TEEC_ERROR_GENERIC;
230 continue;
231 }
232
233 if (connect(fd, res->ai_addr, res->ai_addrlen)) {
234 if (errno == ETIMEDOUT)
235 r = TEE_ISOCKET_ERROR_TIMEOUT;
236 else
237 r = TEEC_ERROR_COMMUNICATION;
238
239 close(fd);
240 fd = -1;
241 continue;
242 }
243
244 if (fd_flags_add(fd, O_NONBLOCK)) {
245 close(fd);
246 fd = -1;
247 r = TEEC_ERROR_GENERIC;
248 break;
249 }
250
251 r = TEEC_SUCCESS;
252 break;
253 }
254
255 freeaddrinfo(res0);
256 *ret_fd = fd;
257 return r;
258 }
259
tee_socket_open(size_t num_params,struct tee_ioctl_param * params)260 static TEEC_Result tee_socket_open(size_t num_params,
261 struct tee_ioctl_param *params)
262 {
263 TEEC_Result res = TEEC_ERROR_GENERIC;
264 int handle = 0;
265 int fd = 0;
266 uint32_t instance_id = 0;
267 char *server = NULL;
268 uint32_t ip_vers = 0;
269 uint16_t port = 0;
270 uint32_t protocol = 0;
271
272 if (num_params != 4 ||
273 !chk_pt(params + 0, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT) ||
274 !chk_pt(params + 1, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT) ||
275 !chk_pt(params + 2, TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT) ||
276 !chk_pt(params + 3, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT))
277 return TEEC_ERROR_BAD_PARAMETERS;
278
279 instance_id = params[0].b;
280 port = params[1].a;
281 protocol = params[1].b;
282 ip_vers = params[1].c;
283
284 server = tee_supp_param_to_va(params + 2);
285 if (!server || server[MEMREF_SIZE(params + 2) - 1] != '\0')
286 return TEE_ISOCKET_ERROR_HOSTNAME;
287
288 res = sock_connect(ip_vers, protocol, server, port, &fd);
289 if (res != TEEC_SUCCESS)
290 return res;
291
292 handle = sock_handle_get(instance_id, fd);
293 if (handle < 0) {
294 close(fd);
295 return TEEC_ERROR_OUT_OF_MEMORY;
296 }
297
298 params[3].a = handle;
299 return TEEC_SUCCESS;
300 }
301
tee_socket_close(size_t num_params,struct tee_ioctl_param * params)302 static TEEC_Result tee_socket_close(size_t num_params,
303 struct tee_ioctl_param *params)
304 {
305 int handle = 0;
306 uint32_t instance_id = 0;
307 int fd = 0;
308
309 if (num_params != 1 ||
310 !chk_pt(params + 0, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT))
311 return TEEC_ERROR_BAD_PARAMETERS;
312
313 instance_id = params[0].b;
314 handle = params[0].c;
315 fd = sock_handle_to_fd(instance_id, handle);
316 if (fd < 0)
317 return TEEC_ERROR_BAD_PARAMETERS;
318 sock_handle_put(instance_id, handle);
319 if (close(fd)) {
320 EMSG("tee_socket_close: close(%d): %s", fd, strerror(errno));
321 return TEEC_ERROR_GENERIC;
322 }
323 return TEEC_SUCCESS;
324 }
325
sock_close_cb(int handle,void * ptr,void * arg)326 static void sock_close_cb(int handle, void *ptr, void *arg)
327 {
328 struct sock_instance *si = arg;
329 int fd = handle_ptr_to_fd(ptr);
330
331 if (close(fd))
332 EMSG("sock_close_cb instance_id %d handle %d fd %d: %s",
333 si->id, handle, fd, strerror(errno));
334 }
335
tee_socket_close_all(size_t num_params,struct tee_ioctl_param * params)336 static TEEC_Result tee_socket_close_all(size_t num_params,
337 struct tee_ioctl_param *params)
338 {
339 uint32_t instance_id = 0;
340 struct sock_instance *si = NULL;
341
342 if (num_params != 1 ||
343 !chk_pt(params + 0, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT))
344 return TEEC_ERROR_BAD_PARAMETERS;
345
346 instance_id = params[0].b;
347 sock_lock();
348 si = sock_instance_find(instance_id);
349 if (si)
350 handle_foreach_put(&si->db, sock_close_cb, si);
351 sock_unlock();
352
353 return TEEC_SUCCESS;
354 }
355
356 #define TS_NSEC_PER_SEC 1000000000
357
ts_add(const struct timespec * a,const struct timespec * b,struct timespec * res)358 static void ts_add(const struct timespec *a, const struct timespec *b,
359 struct timespec *res)
360 {
361 res->tv_sec = a->tv_sec + b->tv_sec;
362 res->tv_nsec = a->tv_nsec + b->tv_nsec;
363 if (res->tv_nsec >= TS_NSEC_PER_SEC) {
364 res->tv_sec++;
365 res->tv_nsec -= TS_NSEC_PER_SEC;
366 }
367 }
368
ts_diff_to_polltimeout(const struct timespec * a,const struct timespec * b)369 static int ts_diff_to_polltimeout(const struct timespec *a,
370 const struct timespec *b)
371 {
372 struct timespec diff;
373
374 memset(&diff, 0, sizeof(diff));
375
376 diff.tv_sec = a->tv_sec - b->tv_sec;
377 diff.tv_nsec = a->tv_nsec - b->tv_nsec;
378 if (a->tv_nsec < b->tv_nsec) {
379 diff.tv_nsec += TS_NSEC_PER_SEC;
380 diff.tv_sec--;
381 }
382
383 if ((diff.tv_sec - 1) > (INT_MAX / 1000))
384 return INT_MAX;
385 return diff.tv_sec * 1000 + diff.tv_nsec / (TS_NSEC_PER_SEC / 1000);
386 }
387
ts_delay_from_millis(uint32_t millis,struct timespec * res)388 static void ts_delay_from_millis(uint32_t millis, struct timespec *res)
389 {
390 res->tv_sec = millis / 1000;
391 res->tv_nsec = (millis % 1000) * (TS_NSEC_PER_SEC / 1000);
392 }
393
poll_with_timeout(struct pollfd * pfd,nfds_t nfds,uint32_t timeout)394 static TEEC_Result poll_with_timeout(struct pollfd *pfd, nfds_t nfds,
395 uint32_t timeout)
396 {
397 int to = 0;
398 int r = 0;
399 struct timespec now;
400 struct timespec until;
401
402 memset(&now, 0, sizeof(now));
403 memset(&until, 0, sizeof(until));
404
405 if (timeout == OPTEE_MRC_SOCKET_TIMEOUT_BLOCKING) {
406 to = -1;
407 } else {
408 struct timespec delay;
409
410 memset(&delay, 0, sizeof(delay));
411
412 ts_delay_from_millis(timeout, &delay);
413
414 if (clock_gettime(CLOCK_REALTIME, &now))
415 return TEEC_ERROR_GENERIC;
416
417 ts_add(&now, &delay, &until);
418 }
419
420 while (true) {
421 if (to != -1)
422 to = ts_diff_to_polltimeout(&until, &now);
423
424 r = poll(pfd, nfds, to);
425 if (!r)
426 return TEE_ISOCKET_ERROR_TIMEOUT;
427 if (r == -1) {
428 /*
429 * If we're interrupted by a signal treat
430 * recalculate the timeout (if needed) and wait
431 * again.
432 */
433 if (errno == EINTR) {
434 if (to != -1 &&
435 clock_gettime(CLOCK_REALTIME, &now))
436 return TEEC_ERROR_GENERIC;
437 continue;
438 }
439 return TEEC_ERROR_BAD_PARAMETERS;
440 }
441 return TEEC_SUCCESS;
442 }
443 }
444
write_with_timeout(int fd,const void * buf,size_t * blen,uint32_t timeout)445 static TEEC_Result write_with_timeout(int fd, const void *buf, size_t *blen,
446 uint32_t timeout)
447 {
448 TEEC_Result res = TEEC_ERROR_GENERIC;
449 struct pollfd pfd = { .fd = fd, .events = POLLOUT };
450 ssize_t r = 0;
451
452 res = poll_with_timeout(&pfd, 1, timeout);
453 if (res != TEEC_SUCCESS)
454 return res;
455
456 r = write(fd, buf, *blen);
457 if (r == -1) {
458 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
459 return TEE_ISOCKET_ERROR_TIMEOUT;
460 return TEEC_ERROR_BAD_PARAMETERS;
461 }
462 *blen = r;
463 return TEEC_SUCCESS;
464 }
465
tee_socket_send(size_t num_params,struct tee_ioctl_param * params)466 static TEEC_Result tee_socket_send(size_t num_params,
467 struct tee_ioctl_param *params)
468 {
469 TEEC_Result res = TEEC_ERROR_GENERIC;
470 int handle = 0;
471 int fd = 0;
472 uint32_t instance_id = 0;
473 void *buf = NULL;
474 size_t bytes = 0;
475
476 if (num_params != 3 ||
477 !chk_pt(params + 0, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT) ||
478 !chk_pt(params + 1, TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT) ||
479 !chk_pt(params + 2, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT))
480 return TEEC_ERROR_BAD_PARAMETERS;
481
482 instance_id = params[0].b;
483 handle = params[0].c;
484 fd = sock_handle_to_fd(instance_id, handle);
485 if (fd < 0)
486 return TEEC_ERROR_BAD_PARAMETERS;
487
488 buf = tee_supp_param_to_va(params + 1);
489 bytes = MEMREF_SIZE(params + 1);
490 res = write_with_timeout(fd, buf, &bytes, params[2].a);
491 if (res == TEEC_SUCCESS)
492 params[2].b = bytes;
493 return res;
494 }
495
recv_with_out_flags(int fd,void * buf,size_t len,int inflags,int * out_flags)496 static ssize_t recv_with_out_flags(int fd, void *buf, size_t len, int inflags,
497 int *out_flags)
498 {
499 ssize_t r = 0;
500
501 while (true) {
502 struct iovec iov = { .iov_base = buf, .iov_len = len, };
503 struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, };
504
505 r = recvmsg(fd, &msg, inflags);
506 if (r < 0) {
507 /*
508 * If the syscall was just interrupted by a signal
509 * delivery, try again.
510 */
511 if (errno == EINTR)
512 continue;
513 return r;
514 }
515
516 *out_flags = msg.msg_flags;
517 return r;
518 }
519 }
520
read_with_timeout(int fd,void * buf,size_t * blen,uint32_t timeout)521 static TEEC_Result read_with_timeout(int fd, void *buf, size_t *blen,
522 uint32_t timeout)
523 {
524 TEEC_Result res = TEEC_ERROR_GENERIC;
525 struct pollfd pfd = { .fd = fd, .events = POLLIN };
526 int socktype = 0;
527 socklen_t l = sizeof(socktype);
528 size_t peek_len = 0;
529 int out_flags = 0;
530 ssize_t r = 0;
531 int e = 0;
532
533 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &socktype, &l))
534 return TEEC_ERROR_BAD_PARAMETERS;
535
536 if (*blen) {
537 /* If *blen == 0, the timeout parameter has no effect. */
538 res = poll_with_timeout(&pfd, 1, timeout);
539 if (res != TEEC_SUCCESS)
540 return res;
541 }
542
543 if ((socktype == SOCK_DGRAM && *blen < SUPP_MAX_PEEK_LEN) || !*blen) {
544 /* Check how much data we have queued. */
545 void *b = malloc(SUPP_MAX_PEEK_LEN);
546
547 if (!b)
548 return TEEC_ERROR_OUT_OF_MEMORY;
549 r = recv_with_out_flags(fd, b, SUPP_MAX_PEEK_LEN,
550 MSG_PEEK | MSG_DONTWAIT, &out_flags);
551 e = errno;
552 free(b);
553 if (r < 0)
554 goto err;
555
556 /*
557 * If the message was truncated we know that it's at least
558 * one byte larger.
559 */
560 if (out_flags & MSG_TRUNC)
561 r++;
562
563 if (!*blen) {
564 *blen = r;
565 return TEEC_SUCCESS;
566 }
567
568 peek_len = r;
569 }
570
571 r = recv_with_out_flags(fd, buf, *blen, MSG_DONTWAIT, &out_flags);
572 if (r == -1) {
573 e = errno;
574 goto err;
575 }
576 if (socktype == SOCK_DGRAM && (out_flags & MSG_TRUNC)) {
577 /*
578 * The datagram has been truncated, return the best length
579 * we have to indicate that.
580 */
581 if (peek_len > (size_t)r)
582 *blen = peek_len;
583 else
584 *blen = r + 1;
585 } else {
586 *blen = r;
587 }
588 return TEEC_SUCCESS;
589
590 err:
591 if (e == EAGAIN || e == EWOULDBLOCK) {
592 /*
593 * If *blen is supplied as 0 then we're not supposed wait
594 * for data so the call to poll has been skipped. In case
595 * there is no data available recvmsg() will return an
596 * error with errno set to EAGAIN or EWOULDBLOCK.
597 */
598 if (!*blen)
599 return TEEC_SUCCESS;
600 return TEE_ISOCKET_ERROR_TIMEOUT;
601 }
602 return TEEC_ERROR_BAD_PARAMETERS;
603 }
604
tee_socket_recv(size_t num_params,struct tee_ioctl_param * params)605 static TEEC_Result tee_socket_recv(size_t num_params,
606 struct tee_ioctl_param *params)
607 {
608 TEEC_Result res = TEEC_ERROR_GENERIC;
609 int handle = 0;
610 int fd = 0;
611 uint32_t instance_id = 0;
612 void *buf = NULL;
613 size_t bytes = 0;
614
615 if (num_params != 3 ||
616 !chk_pt(params + 0, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT) ||
617 !chk_pt(params + 1, TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT) ||
618 !chk_pt(params + 2, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT))
619 return TEEC_ERROR_BAD_PARAMETERS;
620
621 instance_id = params[0].b;
622 handle = params[0].c;
623 fd = sock_handle_to_fd(instance_id, handle);
624 if (fd < 0)
625 return TEEC_ERROR_BAD_PARAMETERS;
626
627 buf = tee_supp_param_to_va(params + 1);
628
629 bytes = MEMREF_SIZE(params + 1);
630 res = read_with_timeout(fd, buf, &bytes, params[2].a);
631 if (res == TEEC_SUCCESS)
632 MEMREF_SIZE(params + 1) = bytes;
633
634 return res;
635 }
636
tee_socket_ioctl_tcp(int fd,uint32_t command,void * buf,size_t * blen)637 static TEEC_Result tee_socket_ioctl_tcp(int fd, uint32_t command,
638 void *buf, size_t *blen)
639 {
640 switch (command) {
641 case TEE_TCP_SET_RECVBUF:
642 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, buf, *blen))
643 return TEEC_ERROR_BAD_PARAMETERS;
644 return TEEC_SUCCESS;
645 case TEE_TCP_SET_SENDBUF:
646 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, buf, *blen))
647 return TEEC_ERROR_BAD_PARAMETERS;
648 return TEEC_SUCCESS;
649 default:
650 return TEEC_ERROR_NOT_SUPPORTED;
651 }
652 }
653
sa_set_port(struct sockaddr * sa,socklen_t slen,uint16_t port)654 static TEEC_Result sa_set_port(struct sockaddr *sa, socklen_t slen,
655 uint16_t port)
656 {
657 if (sa->sa_family == AF_INET) {
658 struct sockaddr_in *sain = (void *)sa;
659
660 if (slen < (socklen_t)sizeof(*sain))
661 return TEEC_ERROR_BAD_PARAMETERS;
662 sain->sin_port = htons(port);
663
664 return TEEC_SUCCESS;
665 }
666
667 if (sa->sa_family == AF_INET6) {
668 struct sockaddr_in6 *sain6 = (void *)sa;
669
670 if (slen < (socklen_t)sizeof(*sain6))
671 return TEEC_ERROR_BAD_PARAMETERS;
672 sain6->sin6_port = htons(port);
673
674 return TEEC_SUCCESS;
675 }
676
677 return TEEC_ERROR_BAD_PARAMETERS;
678 }
679
sa_get_port(struct sockaddr * sa,socklen_t slen,uint16_t * port)680 static TEEC_Result sa_get_port(struct sockaddr *sa, socklen_t slen,
681 uint16_t *port)
682 {
683 if (sa->sa_family == AF_INET) {
684 struct sockaddr_in *sain = (void *)sa;
685
686 if (slen < (socklen_t)sizeof(*sain))
687 return TEEC_ERROR_BAD_PARAMETERS;
688 *port = ntohs(sain->sin_port);
689
690 return TEEC_SUCCESS;
691 }
692
693 if (sa->sa_family == AF_INET6) {
694 struct sockaddr_in6 *sain6 = (void *)sa;
695
696 if (slen < (socklen_t)sizeof(*sain6))
697 return TEEC_ERROR_BAD_PARAMETERS;
698 *port = ntohs(sain6->sin6_port);
699
700 return TEEC_SUCCESS;
701 }
702
703 return TEEC_ERROR_BAD_PARAMETERS;
704 }
705
udp_changeaddr(int fd,int family,const char * server,uint16_t port)706 static TEEC_Result udp_changeaddr(int fd, int family, const char *server,
707 uint16_t port)
708 {
709 TEEC_Result r = TEE_ISOCKET_ERROR_HOSTNAME;
710 struct addrinfo *res0 = NULL;
711 struct addrinfo *res = NULL;
712 char port_name[10] = { 0 };
713 struct addrinfo hints;
714
715 memset(&hints, 0, sizeof(hints));
716
717 snprintf(port_name, sizeof(port_name), "%" PRIu16, port);
718
719 hints.ai_family = family;
720 hints.ai_socktype = SOCK_DGRAM;
721 if (getaddrinfo(server, port_name, &hints, &res0))
722 return TEE_ISOCKET_ERROR_HOSTNAME;
723 for (res = res0; res; res = res->ai_next) {
724 if (connect(fd, res->ai_addr, res->ai_addrlen)) {
725 if (errno == ETIMEDOUT)
726 r = TEE_ISOCKET_ERROR_TIMEOUT;
727 else
728 r = TEEC_ERROR_COMMUNICATION;
729 continue;
730 }
731 r = TEEC_SUCCESS;
732 break;
733 }
734 freeaddrinfo(res0);
735
736 return r;
737 }
738
tee_socket_ioctl_udp(int fd,uint32_t command,void * buf,size_t * blen)739 static TEEC_Result tee_socket_ioctl_udp(int fd, uint32_t command,
740 void *buf, size_t *blen)
741 {
742 TEEC_Result res = TEEC_ERROR_GENERIC;
743 uint16_t port = 0;
744 struct sockaddr_storage sass;
745 struct sockaddr *sa = (struct sockaddr *)&sass;
746 socklen_t len = sizeof(sass);
747
748 memset(&sass, 0, sizeof(sass));
749
750 if (getpeername(fd, sa, &len))
751 return TEEC_ERROR_BAD_PARAMETERS;
752
753 switch (command) {
754 case TEE_UDP_CHANGEADDR:
755 res = sa_get_port(sa, len, &port);
756 if (res != TEEC_SUCCESS)
757 return res;
758
759 if (!blen || *((char *)buf + *blen - 1) != '\0')
760 return TEE_ISOCKET_ERROR_HOSTNAME;
761
762 return udp_changeaddr(fd, sa->sa_family, buf, port);
763 case TEE_UDP_CHANGEPORT:
764 if (*blen != sizeof(port))
765 return TEEC_ERROR_BAD_PARAMETERS;
766 memcpy(&port, buf, sizeof(port));
767 res = sa_set_port(sa, len, port);
768 if (res != TEEC_SUCCESS)
769 return res;
770 if (connect(fd, sa, len))
771 return TEEC_ERROR_GENERIC;
772 return TEEC_SUCCESS;
773 default:
774 return TEEC_ERROR_NOT_SUPPORTED;
775 }
776 }
777
tee_socket_ioctl(size_t num_params,struct tee_ioctl_param * params)778 static TEEC_Result tee_socket_ioctl(size_t num_params,
779 struct tee_ioctl_param *params)
780 {
781 TEEC_Result res = TEEC_ERROR_GENERIC;
782 int handle = 0;
783 int fd = 0;
784 uint32_t instance_id = 0;
785 uint32_t command = 0;
786 void *buf = NULL;
787 int socktype = 0;
788 socklen_t l = 0;
789 size_t sz = 0;
790
791 if (num_params != 3 ||
792 !chk_pt(params + 0, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT) ||
793 !chk_pt(params + 1, TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT) ||
794 !chk_pt(params + 2, TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT))
795 return TEEC_ERROR_BAD_PARAMETERS;
796
797 instance_id = params[0].b;
798 handle = params[0].c;
799 command = params[2].a;
800 fd = sock_handle_to_fd(instance_id, handle);
801 if (fd < 0)
802 return TEEC_ERROR_BAD_PARAMETERS;
803
804 l = sizeof(socktype);
805 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &socktype, &l))
806 return TEEC_ERROR_BAD_PARAMETERS;
807
808 buf = tee_supp_param_to_va(params + 1);
809
810 switch (socktype) {
811 case SOCK_STREAM:
812 sz = MEMREF_SIZE(params + 1);
813 res = tee_socket_ioctl_tcp(fd, command, buf, &sz);
814 MEMREF_SIZE(params + 1) = sz;
815 return res;
816 case SOCK_DGRAM:
817 sz = MEMREF_SIZE(params + 1);
818 res = tee_socket_ioctl_udp(fd, command, buf, &sz);
819 MEMREF_SIZE(params + 1) = sz;
820 return res;
821 default:
822 return TEEC_ERROR_BAD_PARAMETERS;
823 }
824 }
825
tee_socket_process(size_t num_params,struct tee_ioctl_param * params)826 TEEC_Result tee_socket_process(size_t num_params,
827 struct tee_ioctl_param *params)
828 {
829 if (!num_params || !tee_supp_param_is_value(params))
830 return TEEC_ERROR_BAD_PARAMETERS;
831
832 switch (params->a) {
833 case OPTEE_MRC_SOCKET_OPEN:
834 return tee_socket_open(num_params, params);
835 case OPTEE_MRC_SOCKET_CLOSE:
836 return tee_socket_close(num_params, params);
837 case OPTEE_MRC_SOCKET_CLOSE_ALL:
838 return tee_socket_close_all(num_params, params);
839 case OPTEE_MRC_SOCKET_SEND:
840 return tee_socket_send(num_params, params);
841 case OPTEE_MRC_SOCKET_RECV:
842 return tee_socket_recv(num_params, params);
843 case OPTEE_MRC_SOCKET_IOCTL:
844 return tee_socket_ioctl(num_params, params);
845 default:
846 return TEEC_ERROR_BAD_PARAMETERS;
847 }
848 }
849