new file mode 100644
@@ -0,0 +1,160 @@
+/*
+ * 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)) {
+ host_to_target_sockaddr(target_addr, addr, addrlen);
+ if (put_user_u32(addrlen, target_addrlen_addr)) {
+ 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)) {
+ host_to_target_sockaddr(target_addr, addr, addrlen);
+ 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)) {
+ host_to_target_sockaddr(target_addr, addr, addrlen);
+ if (put_user_u32(addrlen, target_addrlen_addr)) {
+ ret = -TARGET_EFAULT;
+ }
+ }
+ return ret;
+}
+
+#endif /* BSD_SOCKET_H */
@@ -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);