/* * Copyright (c) 2017 Linaro Limited * Copyright (c) 2021 Nordic Semiconductor * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ /* Zephyr headers */ #include LOG_MODULE_REGISTER(net_sock, CONFIG_NET_SOCKETS_LOG_LEVEL); #include #include #include #include #include "sockets_internal.h" #define VTABLE_CALL(fn, sock, ...) \ ({ \ const struct socket_op_vtable *vtable; \ struct k_mutex *lock; \ void *obj; \ int retval; \ \ obj = get_sock_vtable(sock, &vtable, &lock); \ if (obj == NULL) { \ errno = EBADF; \ return -1; \ } \ \ if (vtable->fn == NULL) { \ errno = EOPNOTSUPP; \ return -1; \ } \ \ (void)k_mutex_lock(lock, K_FOREVER); \ \ retval = vtable->fn(obj, __VA_ARGS__); \ \ k_mutex_unlock(lock); \ \ retval; \ }) static inline void *get_sock_vtable(int sock, const struct socket_op_vtable **vtable, struct k_mutex **lock) { void *ctx; ctx = zvfs_get_fd_obj_and_vtable(sock, (const struct fd_op_vtable **)vtable, lock); #ifdef CONFIG_USERSPACE if (ctx != NULL && k_is_in_user_syscall()) { if (!k_object_is_valid(ctx, K_OBJ_NET_SOCKET)) { /* Invalidate the context, the caller doesn't have * sufficient permission or there was some other * problem with the net socket object */ ctx = NULL; } } #endif /* CONFIG_USERSPACE */ if (ctx == NULL) { NET_DBG("Invalid access on sock %d by thread %p (%s)", sock, _current, k_thread_name_get(_current)); } return ctx; } size_t msghdr_non_empty_iov_count(const struct msghdr *msg) { size_t non_empty_iov_count = 0; for (size_t i = 0; i < msg->msg_iovlen; i++) { if (msg->msg_iov[i].iov_len) { non_empty_iov_count++; } } return non_empty_iov_count; } void *z_impl_zsock_get_context_object(int sock) { const struct socket_op_vtable *ignored; return get_sock_vtable(sock, &ignored, NULL); } #ifdef CONFIG_USERSPACE void *z_vrfy_zsock_get_context_object(int sock) { /* All checking done in implementation */ return z_impl_zsock_get_context_object(sock); } #include #endif int z_impl_zsock_socket(int family, int type, int proto) { STRUCT_SECTION_FOREACH(net_socket_register, sock_family) { int ret; if (sock_family->family != family && sock_family->family != AF_UNSPEC) { continue; } NET_ASSERT(sock_family->is_supported); if (!sock_family->is_supported(family, type, proto)) { continue; } errno = 0; ret = sock_family->handler(family, type, proto); SYS_PORT_TRACING_OBJ_INIT(socket, ret < 0 ? -errno : ret, family, type, proto); (void)sock_obj_core_alloc(ret, sock_family, family, type, proto); return ret; } errno = EAFNOSUPPORT; SYS_PORT_TRACING_OBJ_INIT(socket, -errno, family, type, proto); return -1; } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_socket(int family, int type, int proto) { /* implementation call to net_context_get() should do all necessary * checking */ return z_impl_zsock_socket(family, type, proto); } #include #endif /* CONFIG_USERSPACE */ extern int zvfs_close(int fd); int z_impl_zsock_close(int sock) { return zvfs_close(sock); } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_close(int sock) { const struct socket_op_vtable *vtable; struct k_mutex *lock; void *ctx; ctx = get_sock_vtable(sock, &vtable, &lock); if (ctx == NULL) { errno = EBADF; return -1; } return z_impl_zsock_close(sock); } #include #endif /* CONFIG_USERSPACE */ int z_impl_zsock_shutdown(int sock, int how) { const struct socket_op_vtable *vtable; struct k_mutex *lock; void *ctx; int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, shutdown, sock, how); ctx = get_sock_vtable(sock, &vtable, &lock); if (ctx == NULL) { errno = EBADF; SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, shutdown, sock, -errno); return -1; } if (!vtable->shutdown) { errno = ENOTSUP; SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, shutdown, sock, -errno); return -1; } (void)k_mutex_lock(lock, K_FOREVER); NET_DBG("shutdown: ctx=%p, fd=%d, how=%d", ctx, sock, how); ret = vtable->shutdown(ctx, how); k_mutex_unlock(lock); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, shutdown, sock, ret < 0 ? -errno : ret); return ret; } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_shutdown(int sock, int how) { return z_impl_zsock_shutdown(sock, how); } #include #endif /* CONFIG_USERSPACE */ int z_impl_zsock_bind(int sock, const struct sockaddr *addr, socklen_t addrlen) { int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, bind, sock, addr, addrlen); ret = VTABLE_CALL(bind, sock, addr, addrlen); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, bind, sock, ret < 0 ? -errno : ret); return ret; } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_bind(int sock, const struct sockaddr *addr, socklen_t addrlen) { struct sockaddr_storage dest_addr_copy; K_OOPS(K_SYSCALL_VERIFY(addrlen <= sizeof(dest_addr_copy))); K_OOPS(k_usermode_from_copy(&dest_addr_copy, (void *)addr, addrlen)); return z_impl_zsock_bind(sock, (struct sockaddr *)&dest_addr_copy, addrlen); } #include #endif /* CONFIG_USERSPACE */ int z_impl_zsock_connect(int sock, const struct sockaddr *addr, socklen_t addrlen) { int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, connect, sock, addr, addrlen); ret = VTABLE_CALL(connect, sock, addr, addrlen); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, connect, sock, ret < 0 ? -errno : ret); return ret; } #ifdef CONFIG_USERSPACE int z_vrfy_zsock_connect(int sock, const struct sockaddr *addr, socklen_t addrlen) { struct sockaddr_storage dest_addr_copy; K_OOPS(K_SYSCALL_VERIFY(addrlen <= sizeof(dest_addr_copy))); K_OOPS(k_usermode_from_copy(&dest_addr_copy, (void *)addr, addrlen)); return z_impl_zsock_connect(sock, (struct sockaddr *)&dest_addr_copy, addrlen); } #include #endif /* CONFIG_USERSPACE */ int z_impl_zsock_listen(int sock, int backlog) { int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, listen, sock, backlog); ret = VTABLE_CALL(listen, sock, backlog); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, listen, sock, ret < 0 ? -errno : ret); return ret; } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_listen(int sock, int backlog) { return z_impl_zsock_listen(sock, backlog); } #include #endif /* CONFIG_USERSPACE */ int z_impl_zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen) { int new_sock; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, accept, sock); new_sock = VTABLE_CALL(accept, sock, addr, addrlen); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, accept, new_sock, addr, addrlen, new_sock < 0 ? -errno : 0); (void)sock_obj_core_alloc_find(sock, new_sock, SOCK_STREAM); return new_sock; } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen) { socklen_t addrlen_copy; int ret; K_OOPS(addrlen && k_usermode_from_copy(&addrlen_copy, addrlen, sizeof(socklen_t))); K_OOPS(addr && K_SYSCALL_MEMORY_WRITE(addr, addrlen ? addrlen_copy : 0)); ret = z_impl_zsock_accept(sock, (struct sockaddr *)addr, addrlen ? &addrlen_copy : NULL); K_OOPS(ret >= 0 && addrlen && k_usermode_to_copy(addrlen, &addrlen_copy, sizeof(socklen_t))); return ret; } #include #endif /* CONFIG_USERSPACE */ ssize_t z_impl_zsock_sendto(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { int bytes_sent; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, sendto, sock, len, flags, dest_addr, addrlen); bytes_sent = VTABLE_CALL(sendto, sock, buf, len, flags, dest_addr, addrlen); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, sendto, sock, bytes_sent < 0 ? -errno : bytes_sent); sock_obj_core_update_send_stats(sock, bytes_sent); return bytes_sent; } #ifdef CONFIG_USERSPACE ssize_t z_vrfy_zsock_sendto(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { struct sockaddr_storage dest_addr_copy; K_OOPS(K_SYSCALL_MEMORY_READ(buf, len)); if (dest_addr) { K_OOPS(K_SYSCALL_VERIFY(addrlen <= sizeof(dest_addr_copy))); K_OOPS(k_usermode_from_copy(&dest_addr_copy, (void *)dest_addr, addrlen)); } return z_impl_zsock_sendto(sock, (const void *)buf, len, flags, dest_addr ? (struct sockaddr *)&dest_addr_copy : NULL, addrlen); } #include #endif /* CONFIG_USERSPACE */ ssize_t z_impl_zsock_sendmsg(int sock, const struct msghdr *msg, int flags) { int bytes_sent; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, sendmsg, sock, msg, flags); bytes_sent = VTABLE_CALL(sendmsg, sock, msg, flags); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, sendmsg, sock, bytes_sent < 0 ? -errno : bytes_sent); sock_obj_core_update_send_stats(sock, bytes_sent); return bytes_sent; } #ifdef CONFIG_USERSPACE static inline ssize_t z_vrfy_zsock_sendmsg(int sock, const struct msghdr *msg, int flags) { struct msghdr msg_copy; size_t i; int ret; K_OOPS(k_usermode_from_copy(&msg_copy, (void *)msg, sizeof(msg_copy))); msg_copy.msg_name = NULL; msg_copy.msg_control = NULL; msg_copy.msg_iov = k_usermode_alloc_from_copy(msg->msg_iov, msg->msg_iovlen * sizeof(struct iovec)); if (!msg_copy.msg_iov) { errno = ENOMEM; goto fail; } for (i = 0; i < msg->msg_iovlen; i++) { msg_copy.msg_iov[i].iov_base = k_usermode_alloc_from_copy(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); if (!msg_copy.msg_iov[i].iov_base) { errno = ENOMEM; goto fail; } msg_copy.msg_iov[i].iov_len = msg->msg_iov[i].iov_len; } if (msg->msg_namelen > 0) { msg_copy.msg_name = k_usermode_alloc_from_copy(msg->msg_name, msg->msg_namelen); if (!msg_copy.msg_name) { errno = ENOMEM; goto fail; } } if (msg->msg_controllen > 0) { msg_copy.msg_control = k_usermode_alloc_from_copy(msg->msg_control, msg->msg_controllen); if (!msg_copy.msg_control) { errno = ENOMEM; goto fail; } } ret = z_impl_zsock_sendmsg(sock, (const struct msghdr *)&msg_copy, flags); k_free(msg_copy.msg_name); k_free(msg_copy.msg_control); for (i = 0; i < msg_copy.msg_iovlen; i++) { k_free(msg_copy.msg_iov[i].iov_base); } k_free(msg_copy.msg_iov); return ret; fail: if (msg_copy.msg_name) { k_free(msg_copy.msg_name); } if (msg_copy.msg_control) { k_free(msg_copy.msg_control); } if (msg_copy.msg_iov) { for (i = 0; i < msg_copy.msg_iovlen; i++) { if (msg_copy.msg_iov[i].iov_base) { k_free(msg_copy.msg_iov[i].iov_base); } } k_free(msg_copy.msg_iov); } return -1; } #include #endif /* CONFIG_USERSPACE */ ssize_t z_impl_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { int bytes_received; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, recvfrom, sock, max_len, flags, src_addr, addrlen); bytes_received = VTABLE_CALL(recvfrom, sock, buf, max_len, flags, src_addr, addrlen); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, recvfrom, sock, src_addr, addrlen, bytes_received < 0 ? -errno : bytes_received); sock_obj_core_update_recv_stats(sock, bytes_received); return bytes_received; } #ifdef CONFIG_USERSPACE ssize_t z_vrfy_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { socklen_t addrlen_copy; ssize_t ret; if (K_SYSCALL_MEMORY_WRITE(buf, max_len)) { errno = EFAULT; return -1; } if (addrlen) { K_OOPS(k_usermode_from_copy(&addrlen_copy, addrlen, sizeof(socklen_t))); } K_OOPS(src_addr && K_SYSCALL_MEMORY_WRITE(src_addr, addrlen_copy)); ret = z_impl_zsock_recvfrom(sock, (void *)buf, max_len, flags, (struct sockaddr *)src_addr, addrlen ? &addrlen_copy : NULL); if (addrlen) { K_OOPS(k_usermode_to_copy(addrlen, &addrlen_copy, sizeof(socklen_t))); } return ret; } #include #endif /* CONFIG_USERSPACE */ ssize_t z_impl_zsock_recvmsg(int sock, struct msghdr *msg, int flags) { int bytes_received; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, recvmsg, sock, msg, flags); bytes_received = VTABLE_CALL(recvmsg, sock, msg, flags); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, recvmsg, sock, msg, bytes_received < 0 ? -errno : bytes_received); sock_obj_core_update_recv_stats(sock, bytes_received); return bytes_received; } #ifdef CONFIG_USERSPACE ssize_t z_vrfy_zsock_recvmsg(int sock, struct msghdr *msg, int flags) { struct msghdr msg_copy; size_t iovlen; size_t i; int ret; if (msg == NULL) { errno = EINVAL; return -1; } if (msg->msg_iov == NULL) { errno = ENOMEM; return -1; } K_OOPS(k_usermode_from_copy(&msg_copy, (void *)msg, sizeof(msg_copy))); k_usermode_from_copy(&iovlen, &msg->msg_iovlen, sizeof(iovlen)); msg_copy.msg_name = NULL; msg_copy.msg_control = NULL; msg_copy.msg_iov = k_usermode_alloc_from_copy(msg->msg_iov, msg->msg_iovlen * sizeof(struct iovec)); if (!msg_copy.msg_iov) { errno = ENOMEM; goto fail; } /* Clear the pointers in the copy so that if the allocation in the * next loop fails, we do not try to free non allocated memory * in fail branch. */ memset(msg_copy.msg_iov, 0, msg->msg_iovlen * sizeof(struct iovec)); for (i = 0; i < iovlen; i++) { /* TODO: In practice we do not need to copy the actual data * in msghdr when receiving data but currently there is no * ready made function to do just that (unless we want to call * relevant malloc function here ourselves). So just use * the copying variant for now. */ msg_copy.msg_iov[i].iov_base = k_usermode_alloc_from_copy(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); if (!msg_copy.msg_iov[i].iov_base) { errno = ENOMEM; goto fail; } msg_copy.msg_iov[i].iov_len = msg->msg_iov[i].iov_len; } if (msg->msg_namelen > 0) { if (msg->msg_name == NULL) { errno = EINVAL; goto fail; } msg_copy.msg_name = k_usermode_alloc_from_copy(msg->msg_name, msg->msg_namelen); if (msg_copy.msg_name == NULL) { errno = ENOMEM; goto fail; } } if (msg->msg_controllen > 0) { if (msg->msg_control == NULL) { errno = EINVAL; goto fail; } msg_copy.msg_control = k_usermode_alloc_from_copy(msg->msg_control, msg->msg_controllen); if (msg_copy.msg_control == NULL) { errno = ENOMEM; goto fail; } } ret = z_impl_zsock_recvmsg(sock, &msg_copy, flags); /* Do not copy anything back if there was an error or nothing was * received. */ if (ret > 0) { if (msg->msg_namelen > 0 && msg->msg_name != NULL) { K_OOPS(k_usermode_to_copy(msg->msg_name, msg_copy.msg_name, msg_copy.msg_namelen)); } if (msg->msg_controllen > 0 && msg->msg_control != NULL) { K_OOPS(k_usermode_to_copy(msg->msg_control, msg_copy.msg_control, msg_copy.msg_controllen)); msg->msg_controllen = msg_copy.msg_controllen; } else { msg->msg_controllen = 0U; } k_usermode_to_copy(&msg->msg_iovlen, &msg_copy.msg_iovlen, sizeof(msg->msg_iovlen)); /* The new iovlen cannot be bigger than the original one */ NET_ASSERT(msg_copy.msg_iovlen <= iovlen); for (i = 0; i < iovlen; i++) { if (i < msg_copy.msg_iovlen) { K_OOPS(k_usermode_to_copy(msg->msg_iov[i].iov_base, msg_copy.msg_iov[i].iov_base, msg_copy.msg_iov[i].iov_len)); K_OOPS(k_usermode_to_copy(&msg->msg_iov[i].iov_len, &msg_copy.msg_iov[i].iov_len, sizeof(msg->msg_iov[i].iov_len))); } else { /* Clear out those vectors that we could not populate */ msg->msg_iov[i].iov_len = 0; } } k_usermode_to_copy(&msg->msg_flags, &msg_copy.msg_flags, sizeof(msg->msg_flags)); } k_free(msg_copy.msg_name); k_free(msg_copy.msg_control); /* Note that we need to free according to original iovlen */ for (i = 0; i < iovlen; i++) { k_free(msg_copy.msg_iov[i].iov_base); } k_free(msg_copy.msg_iov); return ret; fail: if (msg_copy.msg_name) { k_free(msg_copy.msg_name); } if (msg_copy.msg_control) { k_free(msg_copy.msg_control); } if (msg_copy.msg_iov) { for (i = 0; i < msg_copy.msg_iovlen; i++) { if (msg_copy.msg_iov[i].iov_base) { k_free(msg_copy.msg_iov[i].iov_base); } } k_free(msg_copy.msg_iov); } return -1; } #include #endif /* CONFIG_USERSPACE */ /* As this is limited function, we don't follow POSIX signature, with * "..." instead of last arg. */ int z_impl_zsock_fcntl_impl(int sock, int cmd, int flags) { const struct socket_op_vtable *vtable; struct k_mutex *lock; void *obj; int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, fcntl, sock, cmd, flags); obj = get_sock_vtable(sock, &vtable, &lock); if (obj == NULL) { errno = EBADF; SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, fcntl, sock, -errno); return -1; } (void)k_mutex_lock(lock, K_FOREVER); ret = zvfs_fdtable_call_ioctl((const struct fd_op_vtable *)vtable, obj, cmd, flags); k_mutex_unlock(lock); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, fcntl, sock, ret < 0 ? -errno : ret); return ret; } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_fcntl_impl(int sock, int cmd, int flags) { return z_impl_zsock_fcntl_impl(sock, cmd, flags); } #include #endif int z_impl_zsock_ioctl_impl(int sock, unsigned long request, va_list args) { const struct socket_op_vtable *vtable; struct k_mutex *lock; void *ctx; int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, ioctl, sock, request); ctx = get_sock_vtable(sock, &vtable, &lock); if (ctx == NULL) { errno = EBADF; SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, ioctl, sock, -errno); return -1; } (void)k_mutex_lock(lock, K_FOREVER); NET_DBG("ioctl: ctx=%p, fd=%d, request=%lu", ctx, sock, request); ret = vtable->fd_vtable.ioctl(ctx, request, args); k_mutex_unlock(lock); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, ioctl, sock, ret < 0 ? -errno : ret); return ret; } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_ioctl_impl(int sock, unsigned long request, va_list args) { switch (request) { case ZFD_IOCTL_FIONBIO: break; case ZFD_IOCTL_FIONREAD: { int *avail; avail = va_arg(args, int *); K_OOPS(K_SYSCALL_MEMORY_WRITE(avail, sizeof(*avail))); break; } default: errno = EOPNOTSUPP; return -1; } return z_impl_zsock_ioctl_impl(sock, request, args); } #include #endif int z_impl_zsock_inet_pton(sa_family_t family, const char *src, void *dst) { if (net_addr_pton(family, src, dst) == 0) { return 1; } else { return 0; } } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_inet_pton(sa_family_t family, const char *src, void *dst) { int dst_size; char src_copy[NET_IPV6_ADDR_LEN]; char dst_copy[sizeof(struct in6_addr)]; int ret; switch (family) { case AF_INET: dst_size = sizeof(struct in_addr); break; case AF_INET6: dst_size = sizeof(struct in6_addr); break; default: errno = EAFNOSUPPORT; return -1; } K_OOPS(k_usermode_string_copy(src_copy, (char *)src, sizeof(src_copy))); ret = z_impl_zsock_inet_pton(family, src_copy, dst_copy); K_OOPS(k_usermode_to_copy(dst, dst_copy, dst_size)); return ret; } #include #endif int z_impl_zsock_getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen) { int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, getsockopt, sock, level, optname); ret = VTABLE_CALL(getsockopt, sock, level, optname, optval, optlen); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, getsockopt, sock, level, optname, optval, *optlen, ret < 0 ? -errno : ret); return ret; } #ifdef CONFIG_USERSPACE int z_vrfy_zsock_getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen) { socklen_t kernel_optlen = *(socklen_t *)optlen; void *kernel_optval; int ret; if (K_SYSCALL_MEMORY_WRITE(optval, kernel_optlen)) { errno = -EPERM; return -1; } kernel_optval = k_usermode_alloc_from_copy((const void *)optval, kernel_optlen); K_OOPS(!kernel_optval); ret = z_impl_zsock_getsockopt(sock, level, optname, kernel_optval, &kernel_optlen); K_OOPS(k_usermode_to_copy((void *)optval, kernel_optval, kernel_optlen)); K_OOPS(k_usermode_to_copy((void *)optlen, &kernel_optlen, sizeof(socklen_t))); k_free(kernel_optval); return ret; } #include #endif /* CONFIG_USERSPACE */ int z_impl_zsock_setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen) { int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, setsockopt, sock, level, optname, optval, optlen); ret = VTABLE_CALL(setsockopt, sock, level, optname, optval, optlen); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, setsockopt, sock, ret < 0 ? -errno : ret); return ret; } #ifdef CONFIG_USERSPACE int z_vrfy_zsock_setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen) { void *kernel_optval; int ret; kernel_optval = k_usermode_alloc_from_copy((const void *)optval, optlen); K_OOPS(!kernel_optval); ret = z_impl_zsock_setsockopt(sock, level, optname, kernel_optval, optlen); k_free(kernel_optval); return ret; } #include #endif /* CONFIG_USERSPACE */ int z_impl_zsock_getpeername(int sock, struct sockaddr *addr, socklen_t *addrlen) { int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, getpeername, sock); ret = VTABLE_CALL(getpeername, sock, addr, addrlen); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, getpeername, sock, addr, addrlen, ret < 0 ? -errno : ret); return ret; } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_getpeername(int sock, struct sockaddr *addr, socklen_t *addrlen) { socklen_t addrlen_copy; int ret; K_OOPS(k_usermode_from_copy(&addrlen_copy, (void *)addrlen, sizeof(socklen_t))); if (K_SYSCALL_MEMORY_WRITE(addr, addrlen_copy)) { errno = EFAULT; return -1; } ret = z_impl_zsock_getpeername(sock, (struct sockaddr *)addr, &addrlen_copy); if (ret == 0 && k_usermode_to_copy((void *)addrlen, &addrlen_copy, sizeof(socklen_t))) { errno = EINVAL; return -1; } return ret; } #include #endif /* CONFIG_USERSPACE */ int z_impl_zsock_getsockname(int sock, struct sockaddr *addr, socklen_t *addrlen) { int ret; SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, getsockname, sock); ret = VTABLE_CALL(getsockname, sock, addr, addrlen); SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, getsockname, sock, addr, addrlen, ret < 0 ? -errno : ret); return ret; } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zsock_getsockname(int sock, struct sockaddr *addr, socklen_t *addrlen) { socklen_t addrlen_copy; int ret; K_OOPS(k_usermode_from_copy(&addrlen_copy, (void *)addrlen, sizeof(socklen_t))); if (K_SYSCALL_MEMORY_WRITE(addr, addrlen_copy)) { errno = EFAULT; return -1; } ret = z_impl_zsock_getsockname(sock, (struct sockaddr *)addr, &addrlen_copy); if (ret == 0 && k_usermode_to_copy((void *)addrlen, &addrlen_copy, sizeof(socklen_t))) { errno = EINVAL; return -1; } return ret; } #include #endif /* CONFIG_USERSPACE */