diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index ec9c032a80..1ca6d4278c 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -120,6 +120,7 @@ namespace Kernel { S(beep) \ S(getsockname) \ S(getpeername) \ + S(socketpair) \ S(sched_setparam) \ S(sched_getparam) \ S(fchown) \ @@ -293,6 +294,13 @@ struct SC_getpeername_params { socklen_t* addrlen; }; +struct SC_socketpair_params { + int domain; + int type; + int protocol; + int* sv; +}; + struct SC_futex_params { u32* userspace_address; int futex_op; diff --git a/Kernel/Net/LocalSocket.cpp b/Kernel/Net/LocalSocket.cpp index bb7b1cbe86..70ab9d7b3c 100644 --- a/Kernel/Net/LocalSocket.cpp +++ b/Kernel/Net/LocalSocket.cpp @@ -36,6 +36,31 @@ KResultOr> LocalSocket::create(int type) return adopt_ref(*new LocalSocket(type)); } +KResultOr LocalSocket::create_connected_pair(int type) +{ + auto socket = adopt_ref(*new LocalSocket(type)); + + auto description1_result = FileDescription::create(*socket); + if (description1_result.is_error()) + return description1_result.error(); + + socket->m_address.sun_family = AF_LOCAL; + memcpy(socket->m_address.sun_path, "[socketpair]", 13); + + auto& process = *Process::current(); + socket->m_acceptor = { process.pid().value(), process.uid(), process.gid() }; + + socket->set_connected(true); + socket->set_connect_side_role(Role::Connected); + socket->m_role = Role::Accepted; + + auto description2_result = FileDescription::create(*socket); + if (description2_result.is_error()) + return description2_result.error(); + + return SocketPair { description1_result.release_value(), description2_result.release_value() }; +} + LocalSocket::LocalSocket(int type) : Socket(AF_LOCAL, type, 0) { diff --git a/Kernel/Net/LocalSocket.h b/Kernel/Net/LocalSocket.h index 362cc42cf1..54412c829f 100644 --- a/Kernel/Net/LocalSocket.h +++ b/Kernel/Net/LocalSocket.h @@ -14,12 +14,18 @@ namespace Kernel { class FileDescription; +struct SocketPair { + NonnullRefPtr description1; + NonnullRefPtr description2; +}; + class LocalSocket final : public Socket , public InlineLinkedListNode { friend class InlineLinkedListNode; public: static KResultOr> create(int type); + static KResultOr create_connected_pair(int type); virtual ~LocalSocket() override; KResult sendfd(const FileDescription& socket_description, FileDescription& passing_description); diff --git a/Kernel/Process.h b/Kernel/Process.h index 34e9d3bf8a..8908f9ca93 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -355,6 +355,7 @@ public: KResultOr sys$setsockopt(Userspace); KResultOr sys$getsockname(Userspace); KResultOr sys$getpeername(Userspace); + KResultOr sys$socketpair(Userspace); KResultOr sys$sched_setparam(pid_t pid, Userspace); KResultOr sys$sched_getparam(pid_t pid, Userspace); KResultOr sys$create_thread(void* (*)(void*), Userspace); @@ -529,6 +530,8 @@ private: void clear_futex_queues_on_exec(); + void setup_socket_fd(int fd, NonnullRefPtr description, int type); + inline PerformanceEventBuffer* current_perf_events_buffer() { return g_profiling_all_threads ? g_global_perf_events : m_perf_event_buffer.ptr(); diff --git a/Kernel/Syscalls/socket.cpp b/Kernel/Syscalls/socket.cpp index 9edf7b6d8e..e858898693 100644 --- a/Kernel/Syscalls/socket.cpp +++ b/Kernel/Syscalls/socket.cpp @@ -20,6 +20,18 @@ namespace Kernel { REQUIRE_PROMISE(unix); \ } while (0) +void Process::setup_socket_fd(int fd, NonnullRefPtr description, int type) +{ + description->set_readable(true); + description->set_writable(true); + unsigned flags = 0; + if (type & SOCK_CLOEXEC) + flags |= FD_CLOEXEC; + if (type & SOCK_NONBLOCK) + description->set_blocking(false); + m_fds[fd].set(*description, flags); +} + KResultOr Process::sys$socket(int domain, int type, int protocol) { REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(domain); @@ -35,14 +47,7 @@ KResultOr Process::sys$socket(int domain, int type, int protocol) auto description_result = FileDescription::create(*result.value()); if (description_result.is_error()) return description_result.error(); - description_result.value()->set_readable(true); - description_result.value()->set_writable(true); - unsigned flags = 0; - if (type & SOCK_CLOEXEC) - flags |= FD_CLOEXEC; - if (type & SOCK_NONBLOCK) - description_result.value()->set_blocking(false); - m_fds[fd].set(description_result.release_value(), flags); + setup_socket_fd(fd, description_result.value(), type); return fd; } @@ -362,4 +367,41 @@ KResultOr Process::sys$setsockopt(Userspace Process::sys$socketpair(Userspace user_params) +{ + Syscall::SC_socketpair_params params; + if (!copy_from_user(¶ms, user_params)) + return EFAULT; + + if (params.domain != AF_LOCAL) + return EINVAL; + + if (params.protocol != 0 && params.protocol != PF_LOCAL) + return EINVAL; + + auto result = LocalSocket::create_connected_pair(params.type & SOCK_TYPE_MASK); + if (result.is_error()) + return result.error(); + auto pair = result.value(); + + int fds[2]; + fds[0] = alloc_fd(); + if (fds[0] < 0) + return ENFILE; + setup_socket_fd(fds[0], pair.description1, params.type); + + fds[1] = alloc_fd(); + if (fds[1] < 0) { + // FIXME: This leaks fds[0] + return ENFILE; + } + setup_socket_fd(fds[1], pair.description2, params.type); + + if (!copy_to_user(params.sv, fds, sizeof(fds))) { + // FIXME: This leaks both file descriptors + return EFAULT; + } + + return KSuccess; +} } diff --git a/Ports/libassuan/patches/socketpair.patch b/Ports/libassuan/patches/socketpair.patch deleted file mode 100644 index 61d318bac4..0000000000 --- a/Ports/libassuan/patches/socketpair.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff -Naur libassuan-2.5.5/src/system-posix.c libassuan-2.5.5.serenity/src/system-posix.c ---- libassuan-2.5.5/src/system-posix.c 2021-04-14 02:40:14.020341296 +0200 -+++ libassuan-2.5.5.serenity/src/system-posix.c 2021-04-14 02:39:56.823341349 +0200 -@@ -412,7 +412,12 @@ - __assuan_socketpair (assuan_context_t ctx, int namespace, int style, - int protocol, assuan_fd_t filedes[2]) - { -+#ifndef __serenity__ - return socketpair (namespace, style, protocol, filedes); -+#else -+ errno = ENOTSUP; -+ return -1; -+#endif - } - - diff --git a/Ports/openssh/patches/missing_functionality.patch b/Ports/openssh/patches/missing_functionality.patch index e4ba95fe6d..5c7cecf808 100644 --- a/Ports/openssh/patches/missing_functionality.patch +++ b/Ports/openssh/patches/missing_functionality.patch @@ -150,21 +150,6 @@ index 554ceb0b..67464ef2 100644 #include #include #include -diff --git a/monitor.c b/monitor.c -index b6e855d5..bde8f383 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -1752,8 +1752,10 @@ monitor_openfds(struct monitor *mon, int do_logfds) - int on = 1; - #endif - -+#ifndef __serenity__ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) - fatal("%s: socketpair: %s", __func__, strerror(errno)); -+#endif - #ifdef SO_ZEROIZE - if (setsockopt(pair[0], SOL_SOCKET, SO_ZEROIZE, &on, sizeof(on)) == -1) - error("setsockopt SO_ZEROIZE(0): %.100s", strerror(errno)); diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c index 059b6d3b..2a248c81 100644 --- a/openbsd-compat/bsd-misc.c @@ -588,27 +573,6 @@ index af08be41..9e748a23 100644 r = check_host_key(host, hostaddr, options.port, host_key, RDRW, options.user_hostfiles, options.num_user_hostfiles, options.system_hostfiles, options.num_system_hostfiles); -diff --git a/sshd.c b/sshd.c -index 6f8f11a3..1ecf3e32 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -1231,6 +1231,8 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) - continue; - } - -+// FIXME: socketpair is seemingly required for SSHD to work, but doesn't current exist. -+#ifndef __serenity__ - if (rexec_flag && socketpair(AF_UNIX, - SOCK_STREAM, 0, config_s) == -1) { - error("reexec socketpair: %s", -@@ -1240,6 +1242,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) - close(startup_p[1]); - continue; - } -+#endif - - for (j = 0; j < options.max_startups; j++) - if (startup_pipes[j] == -1) { diff --git a/sshkey.c b/sshkey.c index 1571e3d9..2b5c611c 100644 --- a/sshkey.c diff --git a/Ports/openssh/patches/sftp_pipes.patch b/Ports/openssh/patches/sftp_pipes.patch deleted file mode 100644 index 10838cdc9d..0000000000 --- a/Ports/openssh/patches/sftp_pipes.patch +++ /dev/null @@ -1,16 +0,0 @@ -e5a0b5cc530260b1ee94105e8c989ba21856b4a2 Use pipes instead of socketpair in SFTP -diff --git a/sftp.c b/sftp.c -index 2799e4a1..9ce7055a 100644 ---- a/sftp.c -+++ b/sftp.c -@@ -2296,6 +2296,10 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) - return (err >= 0 ? 0 : -1); - } - -+#ifdef __serenity__ -+#define USE_PIPES 1 -+#endif -+ - static void - connect_to_server(char *path, char **args, int *in, int *out) - { diff --git a/Ports/stress-ng/patches/0003-missing-networking-functionality.patch b/Ports/stress-ng/patches/0003-missing-networking-functionality.patch index 792e2a6433..436d349bf9 100644 --- a/Ports/stress-ng/patches/0003-missing-networking-functionality.patch +++ b/Ports/stress-ng/patches/0003-missing-networking-functionality.patch @@ -79,18 +79,3 @@ diff -ur a/stress-resources.c b/stress-resources.c static const int types[] = { SOCK_STREAM, SOCK_DGRAM }; static stress_info_t info[MAX_LOOPS]; #if defined(O_NOATIME) -@@ -309,11 +309,13 @@ - if (!keep_stressing_flag()) - break; - -+#if 0 - if (socketpair(AF_UNIX, SOCK_STREAM, 0, - info[i].fd_socketpair) < 0) { - info[i].fd_socketpair[0] = -1; - info[i].fd_socketpair[1] = -1; - } -+#endif - - #if defined(HAVE_USERFAULTFD) - info[i].fd_uf = shim_userfaultfd(0); -d diff --git a/Userland/Libraries/LibC/sys/socket.cpp b/Userland/Libraries/LibC/sys/socket.cpp index 83934ae0fd..96211141b1 100644 --- a/Userland/Libraries/LibC/sys/socket.cpp +++ b/Userland/Libraries/LibC/sys/socket.cpp @@ -125,6 +125,13 @@ int getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen) __RETURN_WITH_ERRNO(rc, rc, -1); } +int socketpair(int domain, int type, int protocol, int sv[2]) +{ + Syscall::SC_socketpair_params params { domain, type, protocol, sv }; + int rc = syscall(SC_socketpair, ¶ms); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + int sendfd(int sockfd, int fd) { int rc = syscall(SC_sendfd, sockfd, fd); diff --git a/Userland/Libraries/LibC/sys/socket.h b/Userland/Libraries/LibC/sys/socket.h index 414cd7c515..8e34091063 100644 --- a/Userland/Libraries/LibC/sys/socket.h +++ b/Userland/Libraries/LibC/sys/socket.h @@ -138,6 +138,7 @@ int getsockopt(int sockfd, int level, int option, void*, socklen_t*); int setsockopt(int sockfd, int level, int option, const void*, socklen_t); int getsockname(int sockfd, struct sockaddr*, socklen_t*); int getpeername(int sockfd, struct sockaddr*, socklen_t*); +int socketpair(int domain, int type, int protocol, int sv[2]); int sendfd(int sockfd, int fd); int recvfd(int sockfd, int options);