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