| 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 |
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 --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);