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