summaryrefslogtreecommitdiff
path: root/components/lwp
diff options
context:
space:
mode:
authorBernard Xiong <[email protected]>2026-08-17 17:15:34 +0800
committerGitHub <[email protected]>2026-08-17 17:15:34 +0800
commit991f0ffca6ca475adcffc7833876bb8151f16e9c (patch)
tree5b69ef28de0b15e1a1d23e53136d37c5e86a8a59 /components/lwp
parentd2acd7587eec680b57f8777c5c7a8dce7369471e (diff)
Add AF_UNIX sockets implementation (#11681)
* components/dfs: support unix socket nodes AF_UNIX pathname binding and descriptor passing require DFSv2 socket nodes and retained open file descriptions across fd tables. Add socket-node creation for tmpfs and devtmpfs, fd reference helpers, and socket F_SETFL forwarding. Impact: DFSv2 socket nodes and descriptor reference handling. Validation: git diff --cached --check. * components/net/sal: support local protocol providers Local IPC protocol families do not have a backing network device. Store the selected provider in each SAL socket and add a local provider registry while preserving netdev checks for Internet sockets. Handle DFSv2 close semantics, socketpair flags, and MSG_CTRUNC for AF_UNIX integration. Impact: SAL protocol dispatch for all socket families. Validation: git diff --cached --check. * components/lwp: support unix socket messages Musl AF_UNIX addresses and ancillary data require explicit ABI and user-memory conversion at the LWP syscall boundary. Add the musl msghdr layout, bounded address and message copying, control-message level conversion, and MSG_CTRUNC translation. Correct receive buffer allocation and copy lengths while handling messages. Impact: LWP socket syscalls when SAL is enabled. Validation: git diff --cached --check. * components/net/af_unix: add local sockets Add an opt-in AF_UNIX provider for pathname-based local IPC without a synthetic network device. Support datagram and stream sockets, blocking and nonblocking I/O, timeouts, poll, socketpair, and SCM_RIGHTS descriptor passing. Include bounded Kconfig settings, component documentation, and utest coverage. Impact: enabled only by RT_USING_AF_UNIX and requires SAL POSIX with DFSv2. Validation: git diff --cached --check. * Fix AF_UNIX CI checks Apply the repository clang-format rules to the affected source lines. Suppress the cppcheck false positive for the devtmpfs list iterator. No functional behavior is changed. * components/lwp: preserve NULL optional msghdr buffers When msg_name or msg_control is NULL, keep the kernel pointer NULL instead of substituting an uninitialized buffer. Reject a NULL control buffer with a nonzero length as EFAULT. Impact: LWP sendmsg/recvmsg conversion on MMU targets. Validation: git diff --cached --check. * components/net/af_unix: fix poll UAF, namespace leak, and SCM_RIGHTS cycles Poll only the local wait queue and wake writers from the receiver. Free namespace entries on detach, and reject AF_UNIX descriptors in SCM_RIGHTS until cycle collection exists. Impact: AF_UNIX poll, bind lifetime, and descriptor passing. Validation: git diff --cached --check. * components/dfs: add DFSv2 AF_UNIX utest suite Add opt-in tests under dfs/utest/v2/af_unix for socket nodes, IPC, poll peer-close, namespace cleanup, and SCM_RIGHTS rejection. Sources are built only when RT_UTEST_TC_USING_DFS_V2_AF_UNIX and the selected test groups are enabled. Impact: DFS utest menu and build; no production AF_UNIX behavior change. Validation: git diff --cached --check.
Diffstat (limited to 'components/lwp')
-rw-r--r--components/lwp/lwp_sys_socket.h27
-rw-r--r--components/lwp/lwp_syscall.c529
2 files changed, 403 insertions, 153 deletions
diff --git a/components/lwp/lwp_sys_socket.h b/components/lwp/lwp_sys_socket.h
index 7f1fc457da..6a690e3cc9 100644
--- a/components/lwp/lwp_sys_socket.h
+++ b/components/lwp/lwp_sys_socket.h
@@ -108,6 +108,33 @@ struct musl_sockaddr
char sa_data[14];
};
+struct musl_msghdr
+{
+ void *msg_name;
+ socklen_t msg_namelen;
+ struct iovec *msg_iov;
+#if defined(ARCH_CPU_64BIT) && defined(__BYTE_ORDER__) && \
+ __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ int padding1;
+#endif
+ int msg_iovlen;
+#if defined(ARCH_CPU_64BIT) && defined(__BYTE_ORDER__) && \
+ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ int padding1;
+#endif
+ void *msg_control;
+#if defined(ARCH_CPU_64BIT) && defined(__BYTE_ORDER__) && \
+ __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ int padding2;
+#endif
+ socklen_t msg_controllen;
+#if defined(ARCH_CPU_64BIT) && defined(__BYTE_ORDER__) && \
+ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ int padding2;
+#endif
+ int msg_flags;
+};
+
struct musl_ifmap {
unsigned long int mem_start;
unsigned long int mem_end;
diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c
index f3538c2cb4..ea096f2a90 100644
--- a/components/lwp/lwp_syscall.c
+++ b/components/lwp/lwp_syscall.c
@@ -299,7 +299,7 @@ static void convert_sockopt(int *level, int *optname)
}
#endif /* RT_USING_SAL */
-#if defined(RT_USING_LWIP) || defined(SAL_USING_UNET)
+#if defined(RT_USING_LWIP) || defined(SAL_USING_UNET) || defined(RT_USING_SAL)
static void sockaddr_tolwip(const struct musl_sockaddr *std, struct sockaddr *lwip)
{
if (std && lwip)
@@ -5065,6 +5065,74 @@ rt_ssize_t sys_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, r
#ifdef RT_USING_SAL
/* network interfaces */
+union lwp_sockaddr_buffer
+{
+ struct sockaddr address;
+ struct sockaddr_un unix_address;
+};
+
+static int lwp_sockaddr_from_user(union lwp_sockaddr_buffer *kernel_address,
+ const struct musl_sockaddr *user_address,
+ socklen_t length)
+{
+ uint16_t family;
+ struct musl_sockaddr musl_address;
+
+ if (user_address == RT_NULL || length < sizeof(family) ||
+ length > sizeof(*kernel_address))
+ {
+ return -EINVAL;
+ }
+ if (!lwp_user_accessable((void *)user_address, length))
+ {
+ return -EFAULT;
+ }
+
+ rt_memset(kernel_address, 0, sizeof(*kernel_address));
+ lwp_get_from_user(&family, (void *)user_address, sizeof(family));
+ if (family == AF_UNIX || family == AF_NETLINK)
+ {
+ lwp_get_from_user(kernel_address, (void *)user_address, length);
+ }
+ else
+ {
+ if (length > sizeof(musl_address))
+ {
+ return -EINVAL;
+ }
+ rt_memset(&musl_address, 0, sizeof(musl_address));
+ lwp_get_from_user(&musl_address, (void *)user_address, length);
+ sockaddr_tolwip(&musl_address, &kernel_address->address);
+ }
+ return 0;
+}
+
+static socklen_t lwp_sockaddr_to_user(
+ struct musl_sockaddr *user_address, socklen_t user_length,
+ const union lwp_sockaddr_buffer *kernel_address,
+ socklen_t kernel_length)
+{
+ socklen_t actual_length;
+ socklen_t copy_length;
+ struct musl_sockaddr musl_address;
+
+ if (kernel_address->unix_address.sa_family == AF_UNIX)
+ {
+ actual_length = kernel_length;
+ copy_length = user_length < actual_length ? user_length : actual_length;
+ lwp_put_to_user(user_address, (void *)kernel_address, copy_length);
+ }
+ else
+ {
+ rt_memset(&musl_address, 0, sizeof(musl_address));
+ sockaddr_tomusl(&kernel_address->address, &musl_address);
+ actual_length = sizeof(musl_address);
+ copy_length = user_length < actual_length ? user_length : actual_length;
+ lwp_put_to_user(user_address, &musl_address, copy_length);
+ }
+ return actual_length;
+}
+
/**
* @brief Accepts a connection on a socket.
*
@@ -5102,8 +5170,7 @@ rt_ssize_t sys_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, r
sysret_t sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen)
{
int ret = -1;
- struct sockaddr ksa;
- struct musl_sockaddr kmusladdr;
+ union lwp_sockaddr_buffer kernel_address;
socklen_t uaddrlen;
socklen_t kaddrlen;
@@ -5125,19 +5192,16 @@ sysret_t sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen)
}
}
- kaddrlen = sizeof(struct sockaddr);
- ret = accept(socket, &ksa, &kaddrlen);
+ rt_memset(&kernel_address, 0, sizeof(kernel_address));
+ kaddrlen = sizeof(kernel_address);
+ ret = accept(socket, &kernel_address.address, &kaddrlen);
if (ret >= 0)
{
if (addr)
{
- sockaddr_tomusl(&ksa, &kmusladdr);
- if (uaddrlen > sizeof(struct musl_sockaddr))
- {
- uaddrlen = sizeof(struct musl_sockaddr);
- }
- lwp_put_to_user(addr, &kmusladdr, uaddrlen);
- lwp_put_to_user(addrlen, &uaddrlen, sizeof(socklen_t));
+ kaddrlen = lwp_sockaddr_to_user(addr, uaddrlen,
+ &kernel_address, kaddrlen);
+ lwp_put_to_user(addrlen, &kaddrlen, sizeof(socklen_t));
}
}
return ret;
@@ -5171,34 +5235,15 @@ sysret_t sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen)
*/
sysret_t sys_bind(int socket, const struct musl_sockaddr *name, socklen_t namelen)
{
- rt_err_t ret = 0;
- struct sockaddr sa;
- struct sockaddr_un un_addr;
- struct musl_sockaddr kname;
- rt_uint16_t family = 0;
-
- if (!lwp_user_accessable((void *)name, namelen))
- {
- return -EFAULT;
- }
+ int ret;
+ union lwp_sockaddr_buffer kernel_address;
- lwp_get_from_user(&family, (void *)name, 2);
- if (family == AF_UNIX)
- {
- lwp_get_from_user(&un_addr, (void *)name, sizeof(struct sockaddr_un));
- ret = bind(socket, (struct sockaddr *)&un_addr, namelen);
- }
- else if (family == AF_NETLINK)
- {
- lwp_get_from_user(&sa, (void *)name, namelen);
- ret = bind(socket, &sa, namelen);
- }
- else
+ ret = lwp_sockaddr_from_user(&kernel_address, name, namelen);
+ if (ret < 0)
{
- lwp_get_from_user(&kname, (void *)name, namelen);
- sockaddr_tolwip(&kname, &sa);
- ret = bind(socket, &sa, namelen);
+ return ret;
}
+ ret = bind(socket, &kernel_address.address, namelen);
return (ret < 0 ? GET_ERRNO() : ret);
}
@@ -5263,8 +5308,7 @@ sysret_t sys_shutdown(int socket, int how)
sysret_t sys_getpeername(int socket, struct musl_sockaddr *name, socklen_t *namelen)
{
int ret = -1;
- struct sockaddr sa;
- struct musl_sockaddr kname;
+ union lwp_sockaddr_buffer kernel_address;
socklen_t unamelen;
socklen_t knamelen;
@@ -5283,18 +5327,15 @@ sysret_t sys_getpeername(int socket, struct musl_sockaddr *name, socklen_t *name
return -EFAULT;
}
- knamelen = sizeof(struct sockaddr);
- ret = getpeername(socket, &sa, &knamelen);
+ rt_memset(&kernel_address, 0, sizeof(kernel_address));
+ knamelen = sizeof(kernel_address);
+ ret = getpeername(socket, &kernel_address.address, &knamelen);
if (ret == 0)
{
- sockaddr_tomusl(&sa, &kname);
- if (unamelen > sizeof(struct musl_sockaddr))
- {
- unamelen = sizeof(struct musl_sockaddr);
- }
- lwp_put_to_user(name, &kname, unamelen);
- lwp_put_to_user(namelen, &unamelen, sizeof(socklen_t));
+ knamelen = lwp_sockaddr_to_user(name, unamelen,
+ &kernel_address, knamelen);
+ lwp_put_to_user(namelen, &knamelen, sizeof(socklen_t));
}
else
{
@@ -5331,8 +5372,7 @@ sysret_t sys_getpeername(int socket, struct musl_sockaddr *name, socklen_t *name
sysret_t sys_getsockname(int socket, struct musl_sockaddr *name, socklen_t *namelen)
{
int ret = -1;
- struct sockaddr sa;
- struct musl_sockaddr kname;
+ union lwp_sockaddr_buffer kernel_address;
socklen_t unamelen;
socklen_t knamelen;
@@ -5351,17 +5391,14 @@ sysret_t sys_getsockname(int socket, struct musl_sockaddr *name, socklen_t *name
return -EFAULT;
}
- knamelen = sizeof(struct sockaddr);
- ret = getsockname(socket, &sa, &knamelen);
+ rt_memset(&kernel_address, 0, sizeof(kernel_address));
+ knamelen = sizeof(kernel_address);
+ ret = getsockname(socket, &kernel_address.address, &knamelen);
if (ret == 0)
{
- sockaddr_tomusl(&sa, &kname);
- if (unamelen > sizeof(struct musl_sockaddr))
- {
- unamelen = sizeof(struct musl_sockaddr);
- }
- lwp_put_to_user(name, &kname, unamelen);
- lwp_put_to_user(namelen, &unamelen, sizeof(socklen_t));
+ knamelen = lwp_sockaddr_to_user(name, unamelen,
+ &kernel_address, knamelen);
+ lwp_put_to_user(namelen, &knamelen, sizeof(socklen_t));
}
else
{
@@ -5517,36 +5554,16 @@ sysret_t sys_setsockopt(int socket, int level, int optname, const void *optval,
*/
sysret_t sys_connect(int socket, const struct musl_sockaddr *name, socklen_t namelen)
{
- int ret = 0;
- rt_uint16_t family = 0;
- struct sockaddr sa;
- struct musl_sockaddr kname;
- struct sockaddr_un addr_un;
-
- if (!lwp_user_accessable((void *)name, namelen))
- {
- return -EFAULT;
- }
-
- lwp_get_from_user(&family, (void *)name, 2);
- if (family == AF_UNIX)
- {
- if (!lwp_user_accessable((void *)name, sizeof(struct sockaddr_un)))
- {
- return -EFAULT;
- }
+ int ret;
+ union lwp_sockaddr_buffer kernel_address;
- lwp_get_from_user(&addr_un, (void *)name, sizeof(struct sockaddr_un));
- ret = connect(socket, (struct sockaddr *)(&addr_un), namelen);
- }
- else
+ ret = lwp_sockaddr_from_user(&kernel_address, name, namelen);
+ if (ret < 0)
{
- lwp_get_from_user(&kname, (void *)name, namelen);
- sockaddr_tolwip(&kname, &sa);
- ret = connect(socket, &sa, namelen);
+ return ret;
}
-
- return ret;
+ ret = connect(socket, &kernel_address.address, namelen);
+ return (ret < 0 ? GET_ERRNO() : ret);
}
/**
@@ -5577,6 +5594,7 @@ sysret_t sys_listen(int socket, int backlog)
#define MUSLC_MSG_OOB 0x0001
#define MUSLC_MSG_PEEK 0x0002
+#define MUSLC_MSG_CTRUNC 0x0008
#define MUSLC_MSG_DONTWAIT 0x0040
#define MUSLC_MSG_WAITALL 0x0100
#define MUSLC_MSG_MORE 0x8000
@@ -5613,21 +5631,106 @@ static int netflags_muslc_2_lwip(int flags)
return flgs;
}
+static int netflags_lwip_2_muslc(int flags)
+{
+ int flgs = 0;
+
+ if (flags & MSG_CTRUNC)
+ {
+ flgs |= MUSLC_MSG_CTRUNC;
+ }
+ return flgs;
+}
+
+static void cmsg_level_muslc_2_lwip(struct msghdr *message)
+{
+ struct cmsghdr *cmsg;
+
+ for_each_cmsghdr(cmsg, message)
+ {
+ if (!CMSG_OK(message, cmsg))
+ {
+ break;
+ }
+ if (cmsg->cmsg_level == INTF_SOL_SOCKET)
+ {
+ cmsg->cmsg_level = IMPL_SOL_SOCKET;
+ }
+ }
+}
+
+static void cmsg_level_lwip_2_muslc(struct msghdr *message)
+{
+ struct cmsghdr *cmsg;
+
+ for_each_cmsghdr(cmsg, message)
+ {
+ if (!CMSG_OK(message, cmsg))
+ {
+ break;
+ }
+ if (cmsg->cmsg_level == IMPL_SOL_SOCKET)
+ {
+ cmsg->cmsg_level = INTF_SOL_SOCKET;
+ }
+ }
+}
+
#ifdef ARCH_MM_MMU
-static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg,
- struct iovec **out_iov, void **out_msg_control)
+static int copy_msghdr_from_user(struct msghdr *kmsg,
+ struct musl_msghdr *umsg,
+ struct iovec **out_iov, void **out_msg_control,
+ void **out_msg_name, void **out_buffer)
{
+ int index;
size_t iovs_size;
+ struct musl_msghdr user_message;
struct iovec *uiov, *kiov;
size_t iovs_buffer_size = 0;
- void *iovs_buffer;
+ char *iovs_buffer;
+ char *buffer_cursor;
- if (!lwp_user_accessable(umsg, sizeof(*umsg)))
+ if (!lwp_user_accessable(umsg, sizeof(user_message)))
{
return -EFAULT;
}
- lwp_get_from_user(kmsg, umsg, sizeof(*kmsg));
+ lwp_get_from_user(&user_message, umsg, sizeof(user_message));
+ kmsg->msg_name = user_message.msg_name;
+ kmsg->msg_namelen = user_message.msg_namelen;
+ kmsg->msg_iov = user_message.msg_iov;
+ kmsg->msg_iovlen = user_message.msg_iovlen;
+ kmsg->msg_control = user_message.msg_control;
+ kmsg->msg_controllen = user_message.msg_controllen;
+ kmsg->msg_flags = user_message.msg_flags;
+
+ if (kmsg->msg_iovlen < 0 ||
+ (size_t)kmsg->msg_iovlen > SIZE_MAX / sizeof(*kmsg->msg_iov) ||
+ kmsg->msg_namelen > sizeof(union lwp_sockaddr_buffer))
+ {
+ return -EINVAL;
+ }
+ if (kmsg->msg_name != RT_NULL &&
+ !lwp_user_accessable(kmsg->msg_name, kmsg->msg_namelen))
+ {
+ return -EFAULT;
+ }
+ if (kmsg->msg_control != RT_NULL &&
+ !lwp_user_accessable(kmsg->msg_control, kmsg->msg_controllen))
+ {
+ return -EFAULT;
+ }
+ if (kmsg->msg_control == RT_NULL)
+ {
+ if (kmsg->msg_controllen != 0)
+ {
+ return -EFAULT;
+ }
+ }
+ if (kmsg->msg_name == RT_NULL)
+ {
+ kmsg->msg_namelen = 0;
+ }
iovs_size = sizeof(*kmsg->msg_iov) * kmsg->msg_iovlen;
if (!lwp_user_accessable(kmsg->msg_iov, iovs_size))
@@ -5651,7 +5754,7 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg,
}
kmsg->msg_iov = kiov;
- for (int i = 0; i < kmsg->msg_iovlen; ++i)
+ for (index = 0; index < kmsg->msg_iovlen; ++index)
{
/*
* We MUST check we can copy data to user after socket done in uiov
@@ -5664,6 +5767,11 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg,
return -EPERM;
}
+ if (SIZE_MAX - iovs_buffer_size < uiov->iov_len)
+ {
+ kmem_put(kmsg->msg_iov);
+ return -EINVAL;
+ }
iovs_buffer_size += uiov->iov_len;
kiov->iov_len = uiov->iov_len;
@@ -5672,7 +5780,15 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg,
}
/* msg_iov and msg_control */
- iovs_buffer = kmem_get(iovs_buffer_size + kmsg->msg_controllen);
+ if (SIZE_MAX - iovs_buffer_size < kmsg->msg_controllen ||
+ SIZE_MAX - iovs_buffer_size - kmsg->msg_controllen <
+ kmsg->msg_namelen)
+ {
+ kmem_put(kmsg->msg_iov);
+ return -EINVAL;
+ }
+ iovs_buffer = kmem_get(iovs_buffer_size + kmsg->msg_controllen +
+ kmsg->msg_namelen);
if (!iovs_buffer)
{
@@ -5681,18 +5797,33 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg,
return -ENOMEM;
}
+ *out_buffer = iovs_buffer;
+ buffer_cursor = iovs_buffer;
kiov = kmsg->msg_iov;
- for (int i = 0; i < kmsg->msg_iovlen; ++i)
+ for (index = 0; index < kmsg->msg_iovlen; ++index)
{
- kiov->iov_base = iovs_buffer;
- iovs_buffer += kiov->iov_len;
+ kiov->iov_base = buffer_cursor;
+ buffer_cursor += kiov->iov_len;
++kiov;
}
*out_msg_control = kmsg->msg_control;
- /* msg_control is the end of the iovs_buffer */
- kmsg->msg_control = iovs_buffer;
+ if (kmsg->msg_control != RT_NULL)
+ {
+ kmsg->msg_control = buffer_cursor;
+ buffer_cursor += kmsg->msg_controllen;
+ }
+ *out_msg_name = kmsg->msg_name;
+ if (kmsg->msg_name != RT_NULL && kmsg->msg_namelen != 0)
+ {
+ kmsg->msg_name = buffer_cursor;
+ }
+ else
+ {
+ kmsg->msg_name = RT_NULL;
+ kmsg->msg_namelen = 0;
+ }
return 0;
}
@@ -5728,12 +5859,17 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg,
*
* @see sys_sendmsg()
*/
-sysret_t sys_recvmsg(int socket, struct msghdr *msg, int flags)
+sysret_t sys_recvmsg(int socket, struct musl_msghdr *msg, int flags)
{
int flgs, ret = -1;
struct msghdr kmsg;
#ifdef ARCH_MM_MMU
+ int index;
+ size_t remaining;
+ socklen_t user_name_length;
+ void *buffer;
void *msg_control;
+ void *msg_name;
struct iovec *uiov, *kiov;
#endif
@@ -5745,10 +5881,12 @@ sysret_t sys_recvmsg(int socket, struct msghdr *msg, int flags)
flgs = netflags_muslc_2_lwip(flags);
#ifdef ARCH_MM_MMU
- ret = copy_msghdr_from_user(&kmsg, msg, &uiov, &msg_control);
+ ret = copy_msghdr_from_user(&kmsg, msg, &uiov, &msg_control,
+ &msg_name, &buffer);
if (!ret)
{
+ user_name_length = kmsg.msg_namelen;
ret = recvmsg(socket, &kmsg, flgs);
if (ret < 0)
@@ -5757,24 +5895,57 @@ sysret_t sys_recvmsg(int socket, struct msghdr *msg, int flags)
}
kiov = kmsg.msg_iov;
+ remaining = (size_t)ret;
- for (int i = 0; i < kmsg.msg_iovlen; ++i)
+ for (index = 0; index < kmsg.msg_iovlen && remaining != 0; ++index)
{
- lwp_put_to_user(uiov->iov_base, kiov->iov_base, kiov->iov_len);
+ size_t copy_length = kiov->iov_len;
+
+ if (copy_length > remaining)
+ {
+ copy_length = remaining;
+ }
+ lwp_put_to_user(uiov->iov_base, kiov->iov_base, copy_length);
+ remaining -= copy_length;
++kiov;
++uiov;
}
- lwp_put_to_user(msg_control, kmsg.msg_control, kmsg.msg_controllen);
+ if (msg_control != RT_NULL && kmsg.msg_controllen != 0)
+ {
+ cmsg_level_lwip_2_muslc(&kmsg);
+ lwp_put_to_user(msg_control, kmsg.msg_control,
+ kmsg.msg_controllen);
+ }
+ if (msg_name != RT_NULL && kmsg.msg_name != RT_NULL)
+ {
+ socklen_t name_length;
+
+ name_length = lwp_sockaddr_to_user(
+ (struct musl_sockaddr *)msg_name, user_name_length,
+ (const union lwp_sockaddr_buffer *)kmsg.msg_name,
+ kmsg.msg_namelen);
+ lwp_put_to_user(&msg->msg_namelen, &name_length,
+ sizeof(name_length));
+ }
+ kmsg.msg_flags = netflags_lwip_2_muslc(kmsg.msg_flags);
lwp_put_to_user(&msg->msg_flags, &kmsg.msg_flags, sizeof(kmsg.msg_flags));
+ lwp_put_to_user(&msg->msg_controllen, &kmsg.msg_controllen,
+ sizeof(kmsg.msg_controllen));
_free_res:
- kmem_put(kmsg.msg_iov->iov_base);
+ kmem_put(buffer);
kmem_put(kmsg.msg_iov);
}
#else
- rt_memcpy(&kmsg, msg, sizeof(kmsg));
+ kmsg.msg_name = msg->msg_name;
+ kmsg.msg_namelen = msg->msg_namelen;
+ kmsg.msg_iov = msg->msg_iov;
+ kmsg.msg_iovlen = msg->msg_iovlen;
+ kmsg.msg_control = msg->msg_control;
+ kmsg.msg_controllen = msg->msg_controllen;
+ kmsg.msg_flags = msg->msg_flags;
ret = recvmsg(socket, &kmsg, flgs);
@@ -5825,18 +5996,33 @@ sysret_t sys_recvfrom(int socket, void *mem, size_t len, int flags,
struct musl_sockaddr *from, socklen_t *fromlen)
{
int flgs = 0;
-#ifdef ARCH_MM_MMU
int ret = -1;
+ socklen_t user_from_length = 0;
+ socklen_t kernel_from_length = 0;
+ union lwp_sockaddr_buffer kernel_address;
+#ifdef ARCH_MM_MMU
void *kmem = RT_NULL;
#endif
flgs = netflags_muslc_2_lwip(flags);
-#ifdef ARCH_MM_MMU
- if (!len)
+ if (from != RT_NULL)
{
- return -EINVAL;
+ if (fromlen == RT_NULL ||
+ !lwp_user_accessable(fromlen, sizeof(*fromlen)))
+ {
+ return -EFAULT;
+ }
+ lwp_get_from_user(&user_from_length, fromlen,
+ sizeof(user_from_length));
+ if (user_from_length == 0 ||
+ !lwp_user_accessable(from, user_from_length))
+ {
+ return -EFAULT;
+ }
+ rt_memset(&kernel_address, 0, sizeof(kernel_address));
+ kernel_from_length = sizeof(kernel_address);
}
-
+#ifdef ARCH_MM_MMU
if (!lwp_user_accessable((void *)mem, len))
{
return -EFAULT;
@@ -5848,26 +6034,30 @@ sysret_t sys_recvfrom(int socket, void *mem, size_t len, int flags,
return -ENOMEM;
}
- if (flags == 0x2)
- {
- flags = 0x1;
- }
-
if (from)
{
- struct sockaddr sa;
-
- ret = recvfrom(socket, kmem, len, flgs, &sa, fromlen);
- sockaddr_tomusl(&sa, from);
+ ret = recvfrom(socket, kmem, len, flgs,
+ &kernel_address.address, &kernel_from_length);
}
else
{
ret = recvfrom(socket, kmem, len, flgs, NULL, NULL);
}
- if (ret > 0)
+ if (ret >= 0)
{
- lwp_put_to_user(mem, kmem, len);
+ if (ret > 0)
+ {
+ lwp_put_to_user(mem, kmem, ret);
+ }
+ if (from != RT_NULL)
+ {
+ kernel_from_length = lwp_sockaddr_to_user(
+ from, user_from_length, &kernel_address,
+ kernel_from_length);
+ lwp_put_to_user(fromlen, &kernel_from_length,
+ sizeof(kernel_from_length));
+ }
}
if (ret < 0)
@@ -5879,17 +6069,22 @@ sysret_t sys_recvfrom(int socket, void *mem, size_t len, int flags,
return ret;
#else
- int ret = -1;
if (from)
{
- struct sockaddr sa = { 0 };
-
- ret = recvfrom(socket, mem, len, flgs, &sa, fromlen);
- sockaddr_tomusl(&sa, from);
+ ret = recvfrom(socket, mem, len, flgs,
+ &kernel_address.address, &kernel_from_length);
+ if (ret >= 0)
+ {
+ kernel_from_length = lwp_sockaddr_to_user(
+ from, user_from_length, &kernel_address,
+ kernel_from_length);
+ lwp_put_to_user(fromlen, &kernel_from_length,
+ sizeof(kernel_from_length));
+ }
}
else
{
- ret = recvfrom(socket, mem, len, flags, NULL, NULL);
+ ret = recvfrom(socket, mem, len, flgs, NULL, NULL);
}
return (ret < 0 ? GET_ERRNO() : ret);
#endif
@@ -5930,7 +6125,7 @@ sysret_t sys_recv(int socket, void *mem, size_t len, int flags)
if (!lwp_user_accessable((void *)mem, len))
return -EFAULT;
- kmem = kmem_get(sizeof(*kmem));
+ kmem = kmem_get(len);
if (kmem == RT_NULL)
{
return -ENOMEM;
@@ -5939,7 +6134,10 @@ sysret_t sys_recv(int socket, void *mem, size_t len, int flags)
flgs = netflags_muslc_2_lwip(flags);
ret = recvfrom(socket, kmem, len, flgs, NULL, NULL);
- lwp_put_to_user((void *)mem, kmem, len);
+ if (ret > 0)
+ {
+ lwp_put_to_user((void *)mem, kmem, ret);
+ }
kmem_put(kmem);
return (ret < 0 ? GET_ERRNO() : ret);
@@ -5977,12 +6175,15 @@ sysret_t sys_recv(int socket, void *mem, size_t len, int flags)
*
* @see sys_send(), sys_sendto(), sys_recvmsg()
*/
-sysret_t sys_sendmsg(int socket, const struct msghdr *msg, int flags)
+sysret_t sys_sendmsg(int socket, const struct musl_msghdr *msg, int flags)
{
int flgs, ret = -1;
struct msghdr kmsg;
#ifdef ARCH_MM_MMU
+ int index;
+ void *buffer;
void *msg_control;
+ void *msg_name;
struct iovec *uiov, *kiov;
#endif
if (!msg)
@@ -5993,13 +6194,14 @@ sysret_t sys_sendmsg(int socket, const struct msghdr *msg, int flags)
flgs = netflags_muslc_2_lwip(flags);
#ifdef ARCH_MM_MMU
- ret = copy_msghdr_from_user(&kmsg, (struct msghdr *)msg, &uiov, &msg_control);
+ ret = copy_msghdr_from_user(&kmsg, (struct musl_msghdr *)msg, &uiov,
+ &msg_control, &msg_name, &buffer);
if (!ret)
{
kiov = kmsg.msg_iov;
- for (int i = 0; i < kmsg.msg_iovlen; ++i)
+ for (index = 0; index < kmsg.msg_iovlen; ++index)
{
lwp_get_from_user(kiov->iov_base, uiov->iov_base, kiov->iov_len);
@@ -6007,22 +6209,44 @@ sysret_t sys_sendmsg(int socket, const struct msghdr *msg, int flags)
++uiov;
}
- lwp_get_from_user(kmsg.msg_control, msg_control, kmsg.msg_controllen);
+ if (msg_control != RT_NULL && kmsg.msg_controllen != 0)
+ {
+ lwp_get_from_user(kmsg.msg_control, msg_control,
+ kmsg.msg_controllen);
+ cmsg_level_muslc_2_lwip(&kmsg);
+ }
+ if (msg_name != RT_NULL && kmsg.msg_namelen != 0)
+ {
+ union lwp_sockaddr_buffer kernel_address;
+
+ ret = lwp_sockaddr_from_user(&kernel_address,
+ (struct musl_sockaddr *)msg_name,
+ kmsg.msg_namelen);
+ if (ret < 0)
+ {
+ kmem_put(buffer);
+ kmem_put(kmsg.msg_iov);
+ return ret;
+ }
+ rt_memcpy(kmsg.msg_name, &kernel_address, kmsg.msg_namelen);
+ }
ret = sendmsg(socket, &kmsg, flgs);
- kmem_put(kmsg.msg_iov->iov_base);
+ kmem_put(buffer);
kmem_put(kmsg.msg_iov);
}
#else
- rt_memcpy(&kmsg, msg, sizeof(kmsg));
+ kmsg.msg_name = msg->msg_name;
+ kmsg.msg_namelen = msg->msg_namelen;
+ kmsg.msg_iov = msg->msg_iov;
+ kmsg.msg_iovlen = msg->msg_iovlen;
+ kmsg.msg_control = msg->msg_control;
+ kmsg.msg_controllen = msg->msg_controllen;
+ kmsg.msg_flags = msg->msg_flags;
ret = sendmsg(socket, &kmsg, flgs);
- if (!ret)
- {
- msg->msg_flags = kmsg.msg_flags;
- }
#endif /* ARCH_MM_MMU */
return (ret < 0 ? GET_ERRNO() : ret);
@@ -6061,18 +6285,22 @@ sysret_t sys_sendto(int socket, const void *dataptr, size_t size, int flags,
const struct musl_sockaddr *to, socklen_t tolen)
{
int flgs = 0;
-#ifdef ARCH_MM_MMU
int ret = -1;
+ union lwp_sockaddr_buffer kernel_address;
+#ifdef ARCH_MM_MMU
void *kmem = RT_NULL;
#endif
flgs = netflags_muslc_2_lwip(flags);
-#ifdef ARCH_MM_MMU
- if (!size)
+ if (to != RT_NULL)
{
- return -EINVAL;
+ ret = lwp_sockaddr_from_user(&kernel_address, to, tolen);
+ if (ret < 0)
+ {
+ return ret;
+ }
}
-
+#ifdef ARCH_MM_MMU
if (!lwp_user_accessable((void *)dataptr, size))
{
return -EFAULT;
@@ -6088,10 +6316,8 @@ sysret_t sys_sendto(int socket, const void *dataptr, size_t size, int flags,
if (to)
{
- struct sockaddr sa;
- sockaddr_tolwip(to, &sa);
-
- ret = sendto(socket, kmem, size, flgs, &sa, tolen);
+ ret = sendto(socket, kmem, size, flgs,
+ &kernel_address.address, tolen);
}
else
{
@@ -6107,13 +6333,10 @@ sysret_t sys_sendto(int socket, const void *dataptr, size_t size, int flags,
return ret;
#else
- int ret;
if (to)
{
- struct sockaddr sa;
- sockaddr_tolwip(to, &sa);
-
- ret = sendto(socket, dataptr, size, flgs, &sa, tolen);
+ ret = sendto(socket, dataptr, size, flgs,
+ &kernel_address.address, tolen);
}
else
{