diff mbox series

[v2,09/37] bsd-user: Add bsd-socket.h with bind through getsockname

Message ID 20260518-misc-2026q2-v2-9-6c16fe448301@bsdimp.com
State New
Headers show
Series bsd-user: Upstream most of the remaining system calls | expand

Commit Message

Warner Losh May 18, 2026, 9:27 p.m. UTC
Add the first set of socket system call shims: bind, connect,
accept, getpeername, and getsockname. Also add safe_syscall wrappers
for sendto, recvfrom, select, pselect, recvmsg, and sendmsg.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
Assisted-by: Claude Opus 4.6 (1M context)
---
 bsd-user/bsd-socket.h         | 167 ++++++++++++++++++++++++++++++++++++++++++
 bsd-user/freebsd/os-syscall.c |  15 ++++
 2 files changed, 182 insertions(+)

Comments

Pierrick Bouvier May 22, 2026, 11:04 p.m. UTC | #1
On 5/18/2026 2:27 PM, Warner Losh wrote:
> Add the first set of socket system call shims: bind, connect,
> accept, getpeername, and getsockname. Also add safe_syscall wrappers
> for sendto, recvfrom, select, pselect, recvmsg, and sendmsg.
> 
> Signed-off-by: Stacey Son <sson@FreeBSD.org>
> Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
> Signed-off-by: Warner Losh <imp@bsdimp.com>
> Assisted-by: Claude Opus 4.6 (1M context)
> ---
>  bsd-user/bsd-socket.h         | 167 ++++++++++++++++++++++++++++++++++++++++++
>  bsd-user/freebsd/os-syscall.c |  15 ++++
>  2 files changed, 182 insertions(+)
> 
> diff --git a/bsd-user/bsd-socket.h b/bsd-user/bsd-socket.h
> new file mode 100644
> index 0000000000..c786d6717a
> --- /dev/null
> +++ b/bsd-user/bsd-socket.h
> @@ -0,0 +1,167 @@
> +/*
> + * socket related system call shims
> + *
> + * Copyright (c) 2013 Stacey D. Son
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +#ifndef BSD_SOCKET_H
> +#define BSD_SOCKET_H
> +
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +#include <netinet/in.h>
> +
> +#include "qemu-bsd.h"
> +
> +ssize_t safe_recvfrom(int s, void *buf, size_t len, int flags,
> +    struct sockaddr *restrict from, socklen_t *restrict fromlen);
> +ssize_t safe_sendto(int s, const void *buf, size_t len, int flags,
> +    const struct sockaddr *to, socklen_t tolen);
> +int safe_select(int nfds, fd_set *readfs, fd_set *writefds, fd_set *exceptfds,
> +    struct timeval *timeout);
> +int safe_pselect(int nfds, fd_set *restrict readfds,
> +    fd_set *restrict writefds, fd_set *restrict exceptfds,
> +    const struct timespec *restrict timeout,
> +    const sigset_t *restrict newsigmask);
> +
> +/* bind(2) */
> +static inline abi_long do_bsd_bind(int sockfd, abi_ulong target_addr,
> +                                   socklen_t addrlen)
> +{
> +    abi_long ret;
> +    void *addr;
> +
> +    if ((int)addrlen < 0) {
> +        return -TARGET_EINVAL;
> +    }
> +
> +    addr = alloca(addrlen + 1);
> +    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
> +    if (is_error(ret)) {
> +        return ret;
> +    }
> +
> +    return get_errno(bind(sockfd, addr, addrlen));
> +}
> +
> +/* connect(2) */
> +static inline abi_long do_bsd_connect(int sockfd, abi_ulong target_addr,
> +                                      socklen_t addrlen)
> +{
> +    abi_long ret;
> +    void *addr;
> +
> +    if ((int)addrlen < 0) {
> +        return -TARGET_EINVAL;
> +    }
> +    addr = alloca(addrlen + 1);
> +
> +    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
> +
> +    if (is_error(ret)) {
> +        return ret;
> +    }
> +
> +    return get_errno(connect(sockfd, addr, addrlen));
> +}
> +
> +/* accept(2) */
> +static inline abi_long do_bsd_accept(int fd, abi_ulong target_addr,
> +                                     abi_ulong target_addrlen_addr)
> +{
> +    socklen_t addrlen;
> +    void *addr;
> +    abi_long ret;
> +
> +    if (target_addr == 0) {
> +        return get_errno(accept(fd, NULL, NULL));
> +    }
> +    /* return EINVAL if addrlen pointer is invalid */
> +    if (get_user_u32(addrlen, target_addrlen_addr)) {
> +        return -TARGET_EINVAL;
> +    }
> +    if ((int)addrlen < 0) {
> +        return -TARGET_EINVAL;
> +    }
> +    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
> +        return -TARGET_EINVAL;
> +    }
> +    addr = alloca(addrlen);
> +
> +    ret = get_errno(accept(fd, addr, &addrlen));
> +    if (!is_error(ret)) {
> +        if (is_error(host_to_target_sockaddr(target_addr, addr, addrlen))) {
> +            close(ret);
> +            ret = -TARGET_EFAULT;
> +        } else if (put_user_u32(addrlen, target_addrlen_addr)) {
> +            close(ret);
> +            ret = -TARGET_EFAULT;
> +        }
> +    }
> +    return ret;
> +}
> +
> +/* getpeername(2) */
> +static inline abi_long do_bsd_getpeername(int fd, abi_ulong target_addr,
> +                                          abi_ulong target_addrlen_addr)
> +{
> +    socklen_t addrlen;
> +    void *addr;
> +    abi_long ret;
> +
> +    if (get_user_u32(addrlen, target_addrlen_addr)) {
> +        return -TARGET_EFAULT;
> +    }
> +    if ((int)addrlen < 0) {
> +        return -TARGET_EINVAL;
> +    }
> +    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
> +        return -TARGET_EFAULT;
> +    }
> +    addr = alloca(addrlen);
> +    ret = get_errno(getpeername(fd, addr, &addrlen));
> +    if (!is_error(ret)) {
> +        ret = host_to_target_sockaddr(target_addr, addr, addrlen);
> +        if (is_error(ret)) {
> +            ret = -TARGET_EFAULT;
> +        } else if (put_user_u32(addrlen, target_addrlen_addr)) {
> +            ret = -TARGET_EFAULT;
> +        }
> +    }
> +    return ret;
> +}
> +
> +/* getsockname(2) */
> +static inline abi_long do_bsd_getsockname(int fd, abi_ulong target_addr,
> +                                          abi_ulong target_addrlen_addr)
> +{
> +    socklen_t addrlen;
> +    void *addr;
> +    abi_long ret;
> +
> +    if (get_user_u32(addrlen, target_addrlen_addr)) {
> +        return -TARGET_EFAULT;
> +    }
> +    if ((int)addrlen < 0) {
> +        return -TARGET_EINVAL;
> +    }
> +    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
> +        return -TARGET_EFAULT;
> +    }
> +    addr = alloca(addrlen);
> +
> +    ret = get_errno(getsockname(fd, addr, &addrlen));
> +    if (!is_error(ret)) {
> +        ret = host_to_target_sockaddr(target_addr, addr, addrlen);
> +        if (is_error(ret)) {
> +            ret = -TARGET_EFAULT;
> +        } else if (put_user_u32(addrlen, target_addrlen_addr)) {
> +            ret = -TARGET_EFAULT;
> +        }
> +    }
> +    return ret;
> +}
> +
> +#endif /* BSD_SOCKET_H */
> diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
> index 228daed4c4..737de36514 100644
> --- a/bsd-user/freebsd/os-syscall.c
> +++ b/bsd-user/freebsd/os-syscall.c
> @@ -40,6 +40,7 @@
>  #include "bsd-proc.h"
>  #include "bsd-misc.h"
>  #include "bsd-signal.h"
> +#include "bsd-socket.h"
>  
>  /* BSD dependent syscall shims */
>  #include "os-stat.h"
> @@ -73,6 +74,20 @@ safe_syscall4(int, ppoll, struct pollfd *, fds, nfds_t, nfds,
>  safe_syscall6(ssize_t, copy_file_range, int, infd, off_t *, inoffp, int, outfd,
>      off_t *, outoffp, size_t, len, unsigned int, flags);
>  
> +/* used in bsd-socket */
> +safe_syscall5(int, select, int, nfds, fd_set *, readfs, fd_set *, writefds,
> +    fd_set *, exceptfds, struct timeval *, timeout);
> +safe_syscall6(int, pselect, int, nfds, fd_set *restrict, readfs,
> +    fd_set *restrict, writefds, fd_set *restrict, exceptfds,
> +    const struct timespec *restrict, timeout, const sigset_t *restrict,
> +    newsigmask);
> +safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len, int, flags,
> +    struct sockaddr *restrict, from, socklen_t *restrict, fromlen);
> +safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, int,
> +    flags, const struct sockaddr *, to, socklen_t, tolen);
> +safe_syscall3(ssize_t, recvmsg, int, s, struct msghdr *, msg, int, flags);
> +safe_syscall3(ssize_t, sendmsg, int, s, const struct msghdr *, msg, int, flags);
> +
>  /* used in os-proc */
>  safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options,
>      struct rusage *, rusage);
> 

I'm really not fond of seeing alloca, especially used with a random
parameter for the size. Seems like linux-user uses it to implement those
functions though.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
diff mbox series

Patch

diff --git a/bsd-user/bsd-socket.h b/bsd-user/bsd-socket.h
new file mode 100644
index 0000000000..c786d6717a
--- /dev/null
+++ b/bsd-user/bsd-socket.h
@@ -0,0 +1,167 @@ 
+/*
+ * socket related system call shims
+ *
+ * Copyright (c) 2013 Stacey D. Son
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef BSD_SOCKET_H
+#define BSD_SOCKET_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include "qemu-bsd.h"
+
+ssize_t safe_recvfrom(int s, void *buf, size_t len, int flags,
+    struct sockaddr *restrict from, socklen_t *restrict fromlen);
+ssize_t safe_sendto(int s, const void *buf, size_t len, int flags,
+    const struct sockaddr *to, socklen_t tolen);
+int safe_select(int nfds, fd_set *readfs, fd_set *writefds, fd_set *exceptfds,
+    struct timeval *timeout);
+int safe_pselect(int nfds, fd_set *restrict readfds,
+    fd_set *restrict writefds, fd_set *restrict exceptfds,
+    const struct timespec *restrict timeout,
+    const sigset_t *restrict newsigmask);
+
+/* bind(2) */
+static inline abi_long do_bsd_bind(int sockfd, abi_ulong target_addr,
+                                   socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+
+    addr = alloca(addrlen + 1);
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(bind(sockfd, addr, addrlen));
+}
+
+/* connect(2) */
+static inline abi_long do_bsd_connect(int sockfd, abi_ulong target_addr,
+                                      socklen_t addrlen)
+{
+    abi_long ret;
+    void *addr;
+
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen + 1);
+
+    ret = target_to_host_sockaddr(addr, target_addr, addrlen);
+
+    if (is_error(ret)) {
+        return ret;
+    }
+
+    return get_errno(connect(sockfd, addr, addrlen));
+}
+
+/* accept(2) */
+static inline abi_long do_bsd_accept(int fd, abi_ulong target_addr,
+                                     abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (target_addr == 0) {
+        return get_errno(accept(fd, NULL, NULL));
+    }
+    /* return EINVAL if addrlen pointer is invalid */
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EINVAL;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EINVAL;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(accept(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        if (is_error(host_to_target_sockaddr(target_addr, addr, addrlen))) {
+            close(ret);
+            ret = -TARGET_EFAULT;
+        } else if (put_user_u32(addrlen, target_addrlen_addr)) {
+            close(ret);
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getpeername(2) */
+static inline abi_long do_bsd_getpeername(int fd, abi_ulong target_addr,
+                                          abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EFAULT;
+    }
+    addr = alloca(addrlen);
+    ret = get_errno(getpeername(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        ret = host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (is_error(ret)) {
+            ret = -TARGET_EFAULT;
+        } else if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+/* getsockname(2) */
+static inline abi_long do_bsd_getsockname(int fd, abi_ulong target_addr,
+                                          abi_ulong target_addrlen_addr)
+{
+    socklen_t addrlen;
+    void *addr;
+    abi_long ret;
+
+    if (get_user_u32(addrlen, target_addrlen_addr)) {
+        return -TARGET_EFAULT;
+    }
+    if ((int)addrlen < 0) {
+        return -TARGET_EINVAL;
+    }
+    if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) {
+        return -TARGET_EFAULT;
+    }
+    addr = alloca(addrlen);
+
+    ret = get_errno(getsockname(fd, addr, &addrlen));
+    if (!is_error(ret)) {
+        ret = host_to_target_sockaddr(target_addr, addr, addrlen);
+        if (is_error(ret)) {
+            ret = -TARGET_EFAULT;
+        } else if (put_user_u32(addrlen, target_addrlen_addr)) {
+            ret = -TARGET_EFAULT;
+        }
+    }
+    return ret;
+}
+
+#endif /* BSD_SOCKET_H */
diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c
index 228daed4c4..737de36514 100644
--- a/bsd-user/freebsd/os-syscall.c
+++ b/bsd-user/freebsd/os-syscall.c
@@ -40,6 +40,7 @@ 
 #include "bsd-proc.h"
 #include "bsd-misc.h"
 #include "bsd-signal.h"
+#include "bsd-socket.h"
 
 /* BSD dependent syscall shims */
 #include "os-stat.h"
@@ -73,6 +74,20 @@  safe_syscall4(int, ppoll, struct pollfd *, fds, nfds_t, nfds,
 safe_syscall6(ssize_t, copy_file_range, int, infd, off_t *, inoffp, int, outfd,
     off_t *, outoffp, size_t, len, unsigned int, flags);
 
+/* used in bsd-socket */
+safe_syscall5(int, select, int, nfds, fd_set *, readfs, fd_set *, writefds,
+    fd_set *, exceptfds, struct timeval *, timeout);
+safe_syscall6(int, pselect, int, nfds, fd_set *restrict, readfs,
+    fd_set *restrict, writefds, fd_set *restrict, exceptfds,
+    const struct timespec *restrict, timeout, const sigset_t *restrict,
+    newsigmask);
+safe_syscall6(ssize_t, recvfrom, int, fd, void *, buf, size_t, len, int, flags,
+    struct sockaddr *restrict, from, socklen_t *restrict, fromlen);
+safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, int,
+    flags, const struct sockaddr *, to, socklen_t, tolen);
+safe_syscall3(ssize_t, recvmsg, int, s, struct msghdr *, msg, int, flags);
+safe_syscall3(ssize_t, sendmsg, int, s, const struct msghdr *, msg, int, flags);
+
 /* used in os-proc */
 safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options,
     struct rusage *, rusage);