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 <[email protected]>
> Signed-off-by: Kyle Evans <[email protected]>
> Signed-off-by: Warner Losh <[email protected]>
> 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 <[email protected]>


Reply via email to