1 /*
2  * Copyright (c) 2017 Linaro Limited
3  * Copyright (c) 2021 Nordic Semiconductor
4  * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved.
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 /* Zephyr headers */
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(net_sock, CONFIG_NET_SOCKETS_LOG_LEVEL);
12 
13 #include <zephyr/kernel.h>
14 #include <zephyr/tracing/tracing.h>
15 #include <zephyr/net/socket.h>
16 #include <zephyr/internal/syscall_handler.h>
17 
18 #include "sockets_internal.h"
19 
20 #define VTABLE_CALL(fn, sock, ...)			     \
21 	({						     \
22 		const struct socket_op_vtable *vtable;	     \
23 		struct k_mutex *lock;			     \
24 		void *obj;				     \
25 		int retval;				     \
26 							     \
27 		obj = get_sock_vtable(sock, &vtable, &lock); \
28 		if (obj == NULL) {			     \
29 			errno = EBADF;			     \
30 			return -1;			     \
31 		}					     \
32 							     \
33 		if (vtable->fn == NULL) {		     \
34 			errno = EOPNOTSUPP;		     \
35 			return -1;			     \
36 		}					     \
37 							     \
38 		(void)k_mutex_lock(lock, K_FOREVER);         \
39 							     \
40 		retval = vtable->fn(obj, __VA_ARGS__);	     \
41 							     \
42 		k_mutex_unlock(lock);                        \
43 							     \
44 		retval;					     \
45 	})
46 
get_sock_vtable(int sock,const struct socket_op_vtable ** vtable,struct k_mutex ** lock)47 static inline void *get_sock_vtable(int sock,
48 				    const struct socket_op_vtable **vtable,
49 				    struct k_mutex **lock)
50 {
51 	void *ctx;
52 
53 	ctx = zvfs_get_fd_obj_and_vtable(sock,
54 				      (const struct fd_op_vtable **)vtable,
55 				      lock);
56 
57 #ifdef CONFIG_USERSPACE
58 	if (ctx != NULL && k_is_in_user_syscall()) {
59 		if (!k_object_is_valid(ctx, K_OBJ_NET_SOCKET)) {
60 			/* Invalidate the context, the caller doesn't have
61 			 * sufficient permission or there was some other
62 			 * problem with the net socket object
63 			 */
64 			ctx = NULL;
65 		}
66 	}
67 #endif /* CONFIG_USERSPACE */
68 
69 	if (ctx == NULL) {
70 		NET_DBG("Invalid access on sock %d by thread %p (%s)", sock,
71 			arch_current_thread(), k_thread_name_get(arch_current_thread()));
72 	}
73 
74 	return ctx;
75 }
76 
msghdr_non_empty_iov_count(const struct msghdr * msg)77 size_t msghdr_non_empty_iov_count(const struct msghdr *msg)
78 {
79 	size_t non_empty_iov_count = 0;
80 
81 	for (size_t i = 0; i < msg->msg_iovlen; i++) {
82 		if (msg->msg_iov[i].iov_len) {
83 			non_empty_iov_count++;
84 		}
85 	}
86 
87 	return non_empty_iov_count;
88 }
89 
z_impl_zsock_get_context_object(int sock)90 void *z_impl_zsock_get_context_object(int sock)
91 {
92 	const struct socket_op_vtable *ignored;
93 
94 	return get_sock_vtable(sock, &ignored, NULL);
95 }
96 
97 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_get_context_object(int sock)98 void *z_vrfy_zsock_get_context_object(int sock)
99 {
100 	/* All checking done in implementation */
101 	return z_impl_zsock_get_context_object(sock);
102 }
103 
104 #include <zephyr/syscalls/zsock_get_context_object_mrsh.c>
105 #endif
106 
z_impl_zsock_socket(int family,int type,int proto)107 int z_impl_zsock_socket(int family, int type, int proto)
108 {
109 	STRUCT_SECTION_FOREACH(net_socket_register, sock_family) {
110 		int ret;
111 
112 		if (sock_family->family != family &&
113 		    sock_family->family != AF_UNSPEC) {
114 			continue;
115 		}
116 
117 		NET_ASSERT(sock_family->is_supported);
118 
119 		if (!sock_family->is_supported(family, type, proto)) {
120 			continue;
121 		}
122 
123 		errno = 0;
124 		ret = sock_family->handler(family, type, proto);
125 
126 		SYS_PORT_TRACING_OBJ_INIT(socket, ret < 0 ? -errno : ret,
127 					  family, type, proto);
128 
129 		(void)sock_obj_core_alloc(ret, sock_family, family, type, proto);
130 
131 		return ret;
132 	}
133 
134 	errno = EAFNOSUPPORT;
135 	SYS_PORT_TRACING_OBJ_INIT(socket, -errno, family, type, proto);
136 	return -1;
137 }
138 
139 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_socket(int family,int type,int proto)140 static inline int z_vrfy_zsock_socket(int family, int type, int proto)
141 {
142 	/* implementation call to net_context_get() should do all necessary
143 	 * checking
144 	 */
145 	return z_impl_zsock_socket(family, type, proto);
146 }
147 #include <zephyr/syscalls/zsock_socket_mrsh.c>
148 #endif /* CONFIG_USERSPACE */
149 
150 extern int zvfs_close(int fd);
151 
z_impl_zsock_close(int sock)152 int z_impl_zsock_close(int sock)
153 {
154 	return zvfs_close(sock);
155 }
156 
157 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_close(int sock)158 static inline int z_vrfy_zsock_close(int sock)
159 {
160 	const struct socket_op_vtable *vtable;
161 	struct k_mutex *lock;
162 	void *ctx;
163 
164 	ctx = get_sock_vtable(sock, &vtable, &lock);
165 	if (ctx == NULL) {
166 		errno = EBADF;
167 		return -1;
168 	}
169 
170 	return z_impl_zsock_close(sock);
171 }
172 #include <zephyr/syscalls/zsock_close_mrsh.c>
173 #endif /* CONFIG_USERSPACE */
174 
z_impl_zsock_shutdown(int sock,int how)175 int z_impl_zsock_shutdown(int sock, int how)
176 {
177 	const struct socket_op_vtable *vtable;
178 	struct k_mutex *lock;
179 	void *ctx;
180 	int ret;
181 
182 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, shutdown, sock, how);
183 
184 	ctx = get_sock_vtable(sock, &vtable, &lock);
185 	if (ctx == NULL) {
186 		errno = EBADF;
187 		SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, shutdown, sock, -errno);
188 		return -1;
189 	}
190 
191 	if (!vtable->shutdown) {
192 		errno = ENOTSUP;
193 		SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, shutdown, sock, -errno);
194 		return -1;
195 	}
196 
197 	(void)k_mutex_lock(lock, K_FOREVER);
198 
199 	NET_DBG("shutdown: ctx=%p, fd=%d, how=%d", ctx, sock, how);
200 
201 	ret = vtable->shutdown(ctx, how);
202 
203 	k_mutex_unlock(lock);
204 
205 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, shutdown, sock, ret < 0 ? -errno : ret);
206 
207 	return ret;
208 }
209 
210 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_shutdown(int sock,int how)211 static inline int z_vrfy_zsock_shutdown(int sock, int how)
212 {
213 	return z_impl_zsock_shutdown(sock, how);
214 }
215 #include <zephyr/syscalls/zsock_shutdown_mrsh.c>
216 #endif /* CONFIG_USERSPACE */
217 
z_impl_zsock_bind(int sock,const struct sockaddr * addr,socklen_t addrlen)218 int z_impl_zsock_bind(int sock, const struct sockaddr *addr, socklen_t addrlen)
219 {
220 	int ret;
221 
222 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, bind, sock, addr, addrlen);
223 
224 	ret = VTABLE_CALL(bind, sock, addr, addrlen);
225 
226 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, bind, sock, ret < 0 ? -errno : ret);
227 
228 	return ret;
229 }
230 
231 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_bind(int sock,const struct sockaddr * addr,socklen_t addrlen)232 static inline int z_vrfy_zsock_bind(int sock, const struct sockaddr *addr,
233 				    socklen_t addrlen)
234 {
235 	struct sockaddr_storage dest_addr_copy;
236 
237 	K_OOPS(K_SYSCALL_VERIFY(addrlen <= sizeof(dest_addr_copy)));
238 	K_OOPS(k_usermode_from_copy(&dest_addr_copy, (void *)addr, addrlen));
239 
240 	return z_impl_zsock_bind(sock, (struct sockaddr *)&dest_addr_copy,
241 				addrlen);
242 }
243 #include <zephyr/syscalls/zsock_bind_mrsh.c>
244 #endif /* CONFIG_USERSPACE */
245 
z_impl_zsock_connect(int sock,const struct sockaddr * addr,socklen_t addrlen)246 int z_impl_zsock_connect(int sock, const struct sockaddr *addr,
247 			socklen_t addrlen)
248 {
249 	int ret;
250 
251 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, connect, sock, addr, addrlen);
252 
253 	ret = VTABLE_CALL(connect, sock, addr, addrlen);
254 
255 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, connect, sock,
256 				       ret < 0 ? -errno : ret);
257 	return ret;
258 }
259 
260 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_connect(int sock,const struct sockaddr * addr,socklen_t addrlen)261 int z_vrfy_zsock_connect(int sock, const struct sockaddr *addr,
262 			socklen_t addrlen)
263 {
264 	struct sockaddr_storage dest_addr_copy;
265 
266 	K_OOPS(K_SYSCALL_VERIFY(addrlen <= sizeof(dest_addr_copy)));
267 	K_OOPS(k_usermode_from_copy(&dest_addr_copy, (void *)addr, addrlen));
268 
269 	return z_impl_zsock_connect(sock, (struct sockaddr *)&dest_addr_copy,
270 				   addrlen);
271 }
272 #include <zephyr/syscalls/zsock_connect_mrsh.c>
273 #endif /* CONFIG_USERSPACE */
274 
z_impl_zsock_listen(int sock,int backlog)275 int z_impl_zsock_listen(int sock, int backlog)
276 {
277 	int ret;
278 
279 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, listen, sock, backlog);
280 
281 	ret = VTABLE_CALL(listen, sock, backlog);
282 
283 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, listen, sock,
284 				       ret < 0 ? -errno : ret);
285 	return ret;
286 }
287 
288 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_listen(int sock,int backlog)289 static inline int z_vrfy_zsock_listen(int sock, int backlog)
290 {
291 	return z_impl_zsock_listen(sock, backlog);
292 }
293 #include <zephyr/syscalls/zsock_listen_mrsh.c>
294 #endif /* CONFIG_USERSPACE */
295 
z_impl_zsock_accept(int sock,struct sockaddr * addr,socklen_t * addrlen)296 int z_impl_zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen)
297 {
298 	int new_sock;
299 
300 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, accept, sock);
301 
302 	new_sock = VTABLE_CALL(accept, sock, addr, addrlen);
303 
304 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, accept, new_sock, addr, addrlen,
305 				       new_sock < 0 ? -errno : 0);
306 
307 	(void)sock_obj_core_alloc_find(sock, new_sock, SOCK_STREAM);
308 
309 	return new_sock;
310 }
311 
312 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_accept(int sock,struct sockaddr * addr,socklen_t * addrlen)313 static inline int z_vrfy_zsock_accept(int sock, struct sockaddr *addr,
314 				      socklen_t *addrlen)
315 {
316 	socklen_t addrlen_copy;
317 	int ret;
318 
319 	K_OOPS(addrlen && k_usermode_from_copy(&addrlen_copy, addrlen,
320 					   sizeof(socklen_t)));
321 	K_OOPS(addr && K_SYSCALL_MEMORY_WRITE(addr, addrlen ? addrlen_copy : 0));
322 
323 	ret = z_impl_zsock_accept(sock, (struct sockaddr *)addr,
324 				  addrlen ? &addrlen_copy : NULL);
325 
326 	K_OOPS(ret >= 0 && addrlen && k_usermode_to_copy(addrlen, &addrlen_copy,
327 						     sizeof(socklen_t)));
328 
329 	return ret;
330 }
331 #include <zephyr/syscalls/zsock_accept_mrsh.c>
332 #endif /* CONFIG_USERSPACE */
333 
z_impl_zsock_sendto(int sock,const void * buf,size_t len,int flags,const struct sockaddr * dest_addr,socklen_t addrlen)334 ssize_t z_impl_zsock_sendto(int sock, const void *buf, size_t len, int flags,
335 			   const struct sockaddr *dest_addr, socklen_t addrlen)
336 {
337 	int bytes_sent;
338 
339 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, sendto, sock, len, flags,
340 					dest_addr, addrlen);
341 
342 	bytes_sent = VTABLE_CALL(sendto, sock, buf, len, flags, dest_addr, addrlen);
343 
344 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, sendto, sock,
345 				       bytes_sent < 0 ? -errno : bytes_sent);
346 
347 	sock_obj_core_update_send_stats(sock, bytes_sent);
348 
349 	return bytes_sent;
350 }
351 
352 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_sendto(int sock,const void * buf,size_t len,int flags,const struct sockaddr * dest_addr,socklen_t addrlen)353 ssize_t z_vrfy_zsock_sendto(int sock, const void *buf, size_t len, int flags,
354 			   const struct sockaddr *dest_addr, socklen_t addrlen)
355 {
356 	struct sockaddr_storage dest_addr_copy;
357 
358 	K_OOPS(K_SYSCALL_MEMORY_READ(buf, len));
359 	if (dest_addr) {
360 		K_OOPS(K_SYSCALL_VERIFY(addrlen <= sizeof(dest_addr_copy)));
361 		K_OOPS(k_usermode_from_copy(&dest_addr_copy, (void *)dest_addr,
362 					addrlen));
363 	}
364 
365 	return z_impl_zsock_sendto(sock, (const void *)buf, len, flags,
366 			dest_addr ? (struct sockaddr *)&dest_addr_copy : NULL,
367 			addrlen);
368 }
369 #include <zephyr/syscalls/zsock_sendto_mrsh.c>
370 #endif /* CONFIG_USERSPACE */
371 
z_impl_zsock_sendmsg(int sock,const struct msghdr * msg,int flags)372 ssize_t z_impl_zsock_sendmsg(int sock, const struct msghdr *msg, int flags)
373 {
374 	int bytes_sent;
375 
376 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, sendmsg, sock, msg, flags);
377 
378 	bytes_sent = VTABLE_CALL(sendmsg, sock, msg, flags);
379 
380 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, sendmsg, sock,
381 				       bytes_sent < 0 ? -errno : bytes_sent);
382 
383 	sock_obj_core_update_send_stats(sock, bytes_sent);
384 
385 	return bytes_sent;
386 }
387 
388 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_sendmsg(int sock,const struct msghdr * msg,int flags)389 static inline ssize_t z_vrfy_zsock_sendmsg(int sock,
390 					   const struct msghdr *msg,
391 					   int flags)
392 {
393 	struct msghdr msg_copy;
394 	size_t i;
395 	int ret;
396 
397 	K_OOPS(k_usermode_from_copy(&msg_copy, (void *)msg, sizeof(msg_copy)));
398 
399 	msg_copy.msg_name = NULL;
400 	msg_copy.msg_control = NULL;
401 
402 	msg_copy.msg_iov = k_usermode_alloc_from_copy(msg->msg_iov,
403 				       msg->msg_iovlen * sizeof(struct iovec));
404 	if (!msg_copy.msg_iov) {
405 		errno = ENOMEM;
406 		goto fail;
407 	}
408 
409 	for (i = 0; i < msg->msg_iovlen; i++) {
410 		msg_copy.msg_iov[i].iov_base =
411 			k_usermode_alloc_from_copy(msg->msg_iov[i].iov_base,
412 					       msg->msg_iov[i].iov_len);
413 		if (!msg_copy.msg_iov[i].iov_base) {
414 			errno = ENOMEM;
415 			goto fail;
416 		}
417 
418 		msg_copy.msg_iov[i].iov_len = msg->msg_iov[i].iov_len;
419 	}
420 
421 	if (msg->msg_namelen > 0) {
422 		msg_copy.msg_name = k_usermode_alloc_from_copy(msg->msg_name,
423 							   msg->msg_namelen);
424 		if (!msg_copy.msg_name) {
425 			errno = ENOMEM;
426 			goto fail;
427 		}
428 	}
429 
430 	if (msg->msg_controllen > 0) {
431 		msg_copy.msg_control = k_usermode_alloc_from_copy(msg->msg_control,
432 							  msg->msg_controllen);
433 		if (!msg_copy.msg_control) {
434 			errno = ENOMEM;
435 			goto fail;
436 		}
437 	}
438 
439 	ret = z_impl_zsock_sendmsg(sock, (const struct msghdr *)&msg_copy,
440 				   flags);
441 
442 	k_free(msg_copy.msg_name);
443 	k_free(msg_copy.msg_control);
444 
445 	for (i = 0; i < msg_copy.msg_iovlen; i++) {
446 		k_free(msg_copy.msg_iov[i].iov_base);
447 	}
448 
449 	k_free(msg_copy.msg_iov);
450 
451 	return ret;
452 
453 fail:
454 	if (msg_copy.msg_name) {
455 		k_free(msg_copy.msg_name);
456 	}
457 
458 	if (msg_copy.msg_control) {
459 		k_free(msg_copy.msg_control);
460 	}
461 
462 	if (msg_copy.msg_iov) {
463 		for (i = 0; i < msg_copy.msg_iovlen; i++) {
464 			if (msg_copy.msg_iov[i].iov_base) {
465 				k_free(msg_copy.msg_iov[i].iov_base);
466 			}
467 		}
468 
469 		k_free(msg_copy.msg_iov);
470 	}
471 
472 	return -1;
473 }
474 #include <zephyr/syscalls/zsock_sendmsg_mrsh.c>
475 #endif /* CONFIG_USERSPACE */
476 
z_impl_zsock_recvfrom(int sock,void * buf,size_t max_len,int flags,struct sockaddr * src_addr,socklen_t * addrlen)477 ssize_t z_impl_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags,
478 			     struct sockaddr *src_addr, socklen_t *addrlen)
479 {
480 	int bytes_received;
481 
482 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, recvfrom, sock, max_len, flags, src_addr, addrlen);
483 
484 	bytes_received = VTABLE_CALL(recvfrom, sock, buf, max_len, flags, src_addr, addrlen);
485 
486 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, recvfrom, sock,
487 				       src_addr, addrlen,
488 				       bytes_received < 0 ? -errno : bytes_received);
489 
490 	sock_obj_core_update_recv_stats(sock, bytes_received);
491 
492 	return bytes_received;
493 }
494 
495 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_recvfrom(int sock,void * buf,size_t max_len,int flags,struct sockaddr * src_addr,socklen_t * addrlen)496 ssize_t z_vrfy_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags,
497 			      struct sockaddr *src_addr, socklen_t *addrlen)
498 {
499 	socklen_t addrlen_copy;
500 	ssize_t ret;
501 
502 	if (K_SYSCALL_MEMORY_WRITE(buf, max_len)) {
503 		errno = EFAULT;
504 		return -1;
505 	}
506 
507 	if (addrlen) {
508 		K_OOPS(k_usermode_from_copy(&addrlen_copy, addrlen,
509 					sizeof(socklen_t)));
510 	}
511 	K_OOPS(src_addr && K_SYSCALL_MEMORY_WRITE(src_addr, addrlen_copy));
512 
513 	ret = z_impl_zsock_recvfrom(sock, (void *)buf, max_len, flags,
514 				   (struct sockaddr *)src_addr,
515 				   addrlen ? &addrlen_copy : NULL);
516 
517 	if (addrlen) {
518 		K_OOPS(k_usermode_to_copy(addrlen, &addrlen_copy,
519 				      sizeof(socklen_t)));
520 	}
521 
522 	return ret;
523 }
524 #include <zephyr/syscalls/zsock_recvfrom_mrsh.c>
525 #endif /* CONFIG_USERSPACE */
526 
z_impl_zsock_recvmsg(int sock,struct msghdr * msg,int flags)527 ssize_t z_impl_zsock_recvmsg(int sock, struct msghdr *msg, int flags)
528 {
529 	int bytes_received;
530 
531 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, recvmsg, sock, msg, flags);
532 
533 	bytes_received = VTABLE_CALL(recvmsg, sock, msg, flags);
534 
535 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, recvmsg, sock, msg,
536 				       bytes_received < 0 ? -errno : bytes_received);
537 
538 	sock_obj_core_update_recv_stats(sock, bytes_received);
539 
540 	return bytes_received;
541 }
542 
543 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_recvmsg(int sock,struct msghdr * msg,int flags)544 ssize_t z_vrfy_zsock_recvmsg(int sock, struct msghdr *msg, int flags)
545 {
546 	struct msghdr msg_copy;
547 	size_t iovlen;
548 	size_t i;
549 	int ret;
550 
551 	if (msg == NULL) {
552 		errno = EINVAL;
553 		return -1;
554 	}
555 
556 	if (msg->msg_iov == NULL) {
557 		errno = ENOMEM;
558 		return -1;
559 	}
560 
561 	K_OOPS(k_usermode_from_copy(&msg_copy, (void *)msg, sizeof(msg_copy)));
562 
563 	k_usermode_from_copy(&iovlen, &msg->msg_iovlen, sizeof(iovlen));
564 
565 	msg_copy.msg_name = NULL;
566 	msg_copy.msg_control = NULL;
567 
568 	msg_copy.msg_iov = k_usermode_alloc_from_copy(msg->msg_iov,
569 				       msg->msg_iovlen * sizeof(struct iovec));
570 	if (!msg_copy.msg_iov) {
571 		errno = ENOMEM;
572 		goto fail;
573 	}
574 
575 	/* Clear the pointers in the copy so that if the allocation in the
576 	 * next loop fails, we do not try to free non allocated memory
577 	 * in fail branch.
578 	 */
579 	memset(msg_copy.msg_iov, 0, msg->msg_iovlen * sizeof(struct iovec));
580 
581 	for (i = 0; i < iovlen; i++) {
582 		/* TODO: In practice we do not need to copy the actual data
583 		 * in msghdr when receiving data but currently there is no
584 		 * ready made function to do just that (unless we want to call
585 		 * relevant malloc function here ourselves). So just use
586 		 * the copying variant for now.
587 		 */
588 		msg_copy.msg_iov[i].iov_base =
589 			k_usermode_alloc_from_copy(msg->msg_iov[i].iov_base,
590 						   msg->msg_iov[i].iov_len);
591 		if (!msg_copy.msg_iov[i].iov_base) {
592 			errno = ENOMEM;
593 			goto fail;
594 		}
595 
596 		msg_copy.msg_iov[i].iov_len = msg->msg_iov[i].iov_len;
597 	}
598 
599 	if (msg->msg_namelen > 0) {
600 		if (msg->msg_name == NULL) {
601 			errno = EINVAL;
602 			goto fail;
603 		}
604 
605 		msg_copy.msg_name = k_usermode_alloc_from_copy(msg->msg_name,
606 							   msg->msg_namelen);
607 		if (msg_copy.msg_name == NULL) {
608 			errno = ENOMEM;
609 			goto fail;
610 		}
611 	}
612 
613 	if (msg->msg_controllen > 0) {
614 		if (msg->msg_control == NULL) {
615 			errno = EINVAL;
616 			goto fail;
617 		}
618 
619 		msg_copy.msg_control =
620 			k_usermode_alloc_from_copy(msg->msg_control,
621 						   msg->msg_controllen);
622 		if (msg_copy.msg_control == NULL) {
623 			errno = ENOMEM;
624 			goto fail;
625 		}
626 	}
627 
628 	ret = z_impl_zsock_recvmsg(sock, &msg_copy, flags);
629 
630 	/* Do not copy anything back if there was an error or nothing was
631 	 * received.
632 	 */
633 	if (ret > 0) {
634 		if (msg->msg_namelen > 0 && msg->msg_name != NULL) {
635 			K_OOPS(k_usermode_to_copy(msg->msg_name,
636 						  msg_copy.msg_name,
637 						  msg_copy.msg_namelen));
638 		}
639 
640 		if (msg->msg_controllen > 0 &&
641 		    msg->msg_control != NULL) {
642 			K_OOPS(k_usermode_to_copy(msg->msg_control,
643 						  msg_copy.msg_control,
644 						  msg_copy.msg_controllen));
645 
646 			msg->msg_controllen = msg_copy.msg_controllen;
647 		} else {
648 			msg->msg_controllen = 0U;
649 		}
650 
651 		k_usermode_to_copy(&msg->msg_iovlen,
652 				   &msg_copy.msg_iovlen,
653 				   sizeof(msg->msg_iovlen));
654 
655 		/* The new iovlen cannot be bigger than the original one */
656 		NET_ASSERT(msg_copy.msg_iovlen <= iovlen);
657 
658 		for (i = 0; i < iovlen; i++) {
659 			if (i < msg_copy.msg_iovlen) {
660 				K_OOPS(k_usermode_to_copy(msg->msg_iov[i].iov_base,
661 							  msg_copy.msg_iov[i].iov_base,
662 							  msg_copy.msg_iov[i].iov_len));
663 				K_OOPS(k_usermode_to_copy(&msg->msg_iov[i].iov_len,
664 							  &msg_copy.msg_iov[i].iov_len,
665 							  sizeof(msg->msg_iov[i].iov_len)));
666 			} else {
667 				/* Clear out those vectors that we could not populate */
668 				msg->msg_iov[i].iov_len = 0;
669 			}
670 		}
671 
672 		k_usermode_to_copy(&msg->msg_flags,
673 				   &msg_copy.msg_flags,
674 				   sizeof(msg->msg_flags));
675 	}
676 
677 	k_free(msg_copy.msg_name);
678 	k_free(msg_copy.msg_control);
679 
680 	/* Note that we need to free according to original iovlen */
681 	for (i = 0; i < iovlen; i++) {
682 		k_free(msg_copy.msg_iov[i].iov_base);
683 	}
684 
685 	k_free(msg_copy.msg_iov);
686 
687 	return ret;
688 
689 fail:
690 	if (msg_copy.msg_name) {
691 		k_free(msg_copy.msg_name);
692 	}
693 
694 	if (msg_copy.msg_control) {
695 		k_free(msg_copy.msg_control);
696 	}
697 
698 	if (msg_copy.msg_iov) {
699 		for (i = 0; i < msg_copy.msg_iovlen; i++) {
700 			if (msg_copy.msg_iov[i].iov_base) {
701 				k_free(msg_copy.msg_iov[i].iov_base);
702 			}
703 		}
704 
705 		k_free(msg_copy.msg_iov);
706 	}
707 
708 	return -1;
709 }
710 #include <zephyr/syscalls/zsock_recvmsg_mrsh.c>
711 #endif /* CONFIG_USERSPACE */
712 
713 /* As this is limited function, we don't follow POSIX signature, with
714  * "..." instead of last arg.
715  */
z_impl_zsock_fcntl_impl(int sock,int cmd,int flags)716 int z_impl_zsock_fcntl_impl(int sock, int cmd, int flags)
717 {
718 	const struct socket_op_vtable *vtable;
719 	struct k_mutex *lock;
720 	void *obj;
721 	int ret;
722 
723 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, fcntl, sock, cmd, flags);
724 
725 	obj = get_sock_vtable(sock, &vtable, &lock);
726 	if (obj == NULL) {
727 		errno = EBADF;
728 		SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, fcntl, sock, -errno);
729 		return -1;
730 	}
731 
732 	(void)k_mutex_lock(lock, K_FOREVER);
733 
734 	ret = zvfs_fdtable_call_ioctl((const struct fd_op_vtable *)vtable,
735 				   obj, cmd, flags);
736 
737 	k_mutex_unlock(lock);
738 
739 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, fcntl, sock,
740 				       ret < 0 ? -errno : ret);
741 	return ret;
742 }
743 
744 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_fcntl_impl(int sock,int cmd,int flags)745 static inline int z_vrfy_zsock_fcntl_impl(int sock, int cmd, int flags)
746 {
747 	return z_impl_zsock_fcntl_impl(sock, cmd, flags);
748 }
749 #include <zephyr/syscalls/zsock_fcntl_impl_mrsh.c>
750 #endif
751 
z_impl_zsock_ioctl_impl(int sock,unsigned long request,va_list args)752 int z_impl_zsock_ioctl_impl(int sock, unsigned long request, va_list args)
753 {
754 	const struct socket_op_vtable *vtable;
755 	struct k_mutex *lock;
756 	void *ctx;
757 	int ret;
758 
759 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, ioctl, sock, request);
760 
761 	ctx = get_sock_vtable(sock, &vtable, &lock);
762 	if (ctx == NULL) {
763 		errno = EBADF;
764 		SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, ioctl, sock, -errno);
765 		return -1;
766 	}
767 
768 	(void)k_mutex_lock(lock, K_FOREVER);
769 
770 	NET_DBG("ioctl: ctx=%p, fd=%d, request=%lu", ctx, sock, request);
771 
772 	ret = vtable->fd_vtable.ioctl(ctx, request, args);
773 
774 	k_mutex_unlock(lock);
775 
776 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, ioctl, sock,
777 				       ret < 0 ? -errno : ret);
778 	return ret;
779 
780 }
781 
782 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_ioctl_impl(int sock,unsigned long request,va_list args)783 static inline int z_vrfy_zsock_ioctl_impl(int sock, unsigned long request, va_list args)
784 {
785 	switch (request) {
786 	case ZFD_IOCTL_FIONBIO:
787 		break;
788 
789 	case ZFD_IOCTL_FIONREAD: {
790 		int *avail;
791 
792 		avail = va_arg(args, int *);
793 		K_OOPS(K_SYSCALL_MEMORY_WRITE(avail, sizeof(*avail)));
794 
795 		break;
796 	}
797 
798 	default:
799 		errno = EOPNOTSUPP;
800 		return -1;
801 	}
802 
803 	return z_impl_zsock_ioctl_impl(sock, request, args);
804 }
805 #include <zephyr/syscalls/zsock_ioctl_impl_mrsh.c>
806 #endif
807 
z_impl_zsock_inet_pton(sa_family_t family,const char * src,void * dst)808 int z_impl_zsock_inet_pton(sa_family_t family, const char *src, void *dst)
809 {
810 	if (net_addr_pton(family, src, dst) == 0) {
811 		return 1;
812 	} else {
813 		return 0;
814 	}
815 }
816 
817 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_inet_pton(sa_family_t family,const char * src,void * dst)818 static inline int z_vrfy_zsock_inet_pton(sa_family_t family,
819 					 const char *src, void *dst)
820 {
821 	int dst_size;
822 	char src_copy[NET_IPV6_ADDR_LEN];
823 	char dst_copy[sizeof(struct in6_addr)];
824 	int ret;
825 
826 	switch (family) {
827 	case AF_INET:
828 		dst_size = sizeof(struct in_addr);
829 		break;
830 	case AF_INET6:
831 		dst_size = sizeof(struct in6_addr);
832 		break;
833 	default:
834 		errno = EAFNOSUPPORT;
835 		return -1;
836 	}
837 
838 	K_OOPS(k_usermode_string_copy(src_copy, (char *)src, sizeof(src_copy)));
839 	ret = z_impl_zsock_inet_pton(family, src_copy, dst_copy);
840 	K_OOPS(k_usermode_to_copy(dst, dst_copy, dst_size));
841 
842 	return ret;
843 }
844 #include <zephyr/syscalls/zsock_inet_pton_mrsh.c>
845 #endif
846 
z_impl_zsock_getsockopt(int sock,int level,int optname,void * optval,socklen_t * optlen)847 int z_impl_zsock_getsockopt(int sock, int level, int optname,
848 			    void *optval, socklen_t *optlen)
849 {
850 	int ret;
851 
852 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, getsockopt, sock, level, optname);
853 
854 	ret = VTABLE_CALL(getsockopt, sock, level, optname, optval, optlen);
855 
856 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, getsockopt, sock, level, optname,
857 				       optval, *optlen, ret < 0 ? -errno : ret);
858 	return ret;
859 }
860 
861 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_getsockopt(int sock,int level,int optname,void * optval,socklen_t * optlen)862 int z_vrfy_zsock_getsockopt(int sock, int level, int optname,
863 			    void *optval, socklen_t *optlen)
864 {
865 	socklen_t kernel_optlen = *(socklen_t *)optlen;
866 	void *kernel_optval;
867 	int ret;
868 
869 	if (K_SYSCALL_MEMORY_WRITE(optval, kernel_optlen)) {
870 		errno = -EPERM;
871 		return -1;
872 	}
873 
874 	kernel_optval = k_usermode_alloc_from_copy((const void *)optval,
875 					       kernel_optlen);
876 	K_OOPS(!kernel_optval);
877 
878 	ret = z_impl_zsock_getsockopt(sock, level, optname,
879 				      kernel_optval, &kernel_optlen);
880 
881 	K_OOPS(k_usermode_to_copy((void *)optval, kernel_optval, kernel_optlen));
882 	K_OOPS(k_usermode_to_copy((void *)optlen, &kernel_optlen,
883 			      sizeof(socklen_t)));
884 
885 	k_free(kernel_optval);
886 
887 	return ret;
888 }
889 #include <zephyr/syscalls/zsock_getsockopt_mrsh.c>
890 #endif /* CONFIG_USERSPACE */
891 
z_impl_zsock_setsockopt(int sock,int level,int optname,const void * optval,socklen_t optlen)892 int z_impl_zsock_setsockopt(int sock, int level, int optname,
893 			    const void *optval, socklen_t optlen)
894 {
895 	int ret;
896 
897 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, setsockopt, sock,
898 					level, optname, optval, optlen);
899 
900 	ret = VTABLE_CALL(setsockopt, sock, level, optname, optval, optlen);
901 
902 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, setsockopt, sock,
903 				       ret < 0 ? -errno : ret);
904 	return ret;
905 }
906 
907 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_setsockopt(int sock,int level,int optname,const void * optval,socklen_t optlen)908 int z_vrfy_zsock_setsockopt(int sock, int level, int optname,
909 			    const void *optval, socklen_t optlen)
910 {
911 	void *kernel_optval;
912 	int ret;
913 
914 	kernel_optval = k_usermode_alloc_from_copy((const void *)optval, optlen);
915 	K_OOPS(!kernel_optval);
916 
917 	ret = z_impl_zsock_setsockopt(sock, level, optname,
918 				      kernel_optval, optlen);
919 
920 	k_free(kernel_optval);
921 
922 	return ret;
923 }
924 #include <zephyr/syscalls/zsock_setsockopt_mrsh.c>
925 #endif /* CONFIG_USERSPACE */
926 
z_impl_zsock_getpeername(int sock,struct sockaddr * addr,socklen_t * addrlen)927 int z_impl_zsock_getpeername(int sock, struct sockaddr *addr,
928 			     socklen_t *addrlen)
929 {
930 	int ret;
931 
932 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, getpeername, sock);
933 
934 	ret = VTABLE_CALL(getpeername, sock, addr, addrlen);
935 
936 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, getpeername, sock,
937 				       addr, addrlen,
938 				       ret < 0 ? -errno : ret);
939 	return ret;
940 }
941 
942 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_getpeername(int sock,struct sockaddr * addr,socklen_t * addrlen)943 static inline int z_vrfy_zsock_getpeername(int sock, struct sockaddr *addr,
944 					   socklen_t *addrlen)
945 {
946 	socklen_t addrlen_copy;
947 	int ret;
948 
949 	K_OOPS(k_usermode_from_copy(&addrlen_copy, (void *)addrlen,
950 				sizeof(socklen_t)));
951 
952 	if (K_SYSCALL_MEMORY_WRITE(addr, addrlen_copy)) {
953 		errno = EFAULT;
954 		return -1;
955 	}
956 
957 	ret = z_impl_zsock_getpeername(sock, (struct sockaddr *)addr,
958 				       &addrlen_copy);
959 
960 	if (ret == 0 &&
961 	    k_usermode_to_copy((void *)addrlen, &addrlen_copy,
962 			   sizeof(socklen_t))) {
963 		errno = EINVAL;
964 		return -1;
965 	}
966 
967 	return ret;
968 }
969 #include <zephyr/syscalls/zsock_getpeername_mrsh.c>
970 #endif /* CONFIG_USERSPACE */
971 
z_impl_zsock_getsockname(int sock,struct sockaddr * addr,socklen_t * addrlen)972 int z_impl_zsock_getsockname(int sock, struct sockaddr *addr,
973 			     socklen_t *addrlen)
974 {
975 	int ret;
976 
977 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, getsockname, sock);
978 
979 	ret = VTABLE_CALL(getsockname, sock, addr, addrlen);
980 
981 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, getsockname, sock,
982 				       addr, addrlen,
983 				       ret < 0 ? -errno : ret);
984 	return ret;
985 }
986 
987 #ifdef CONFIG_USERSPACE
z_vrfy_zsock_getsockname(int sock,struct sockaddr * addr,socklen_t * addrlen)988 static inline int z_vrfy_zsock_getsockname(int sock, struct sockaddr *addr,
989 					   socklen_t *addrlen)
990 {
991 	socklen_t addrlen_copy;
992 	int ret;
993 
994 	K_OOPS(k_usermode_from_copy(&addrlen_copy, (void *)addrlen,
995 				sizeof(socklen_t)));
996 
997 	if (K_SYSCALL_MEMORY_WRITE(addr, addrlen_copy)) {
998 		errno = EFAULT;
999 		return -1;
1000 	}
1001 
1002 	ret = z_impl_zsock_getsockname(sock, (struct sockaddr *)addr,
1003 				       &addrlen_copy);
1004 
1005 	if (ret == 0 &&
1006 	    k_usermode_to_copy((void *)addrlen, &addrlen_copy,
1007 			   sizeof(socklen_t))) {
1008 		errno = EINVAL;
1009 		return -1;
1010 	}
1011 
1012 	return ret;
1013 }
1014 #include <zephyr/syscalls/zsock_getsockname_mrsh.c>
1015 #endif /* CONFIG_USERSPACE */
1016