Kernel+LibC: Implement the socketpair() syscall
This commit is contained in:
parent
c841012f56
commit
aa792062cb
Notes:
sideshowbarker
2024-07-18 19:00:23 +09:00
Author: https://github.com/gunnarbeutner Commit: https://github.com/SerenityOS/serenity/commit/aa792062cbb Pull-request: https://github.com/SerenityOS/serenity/pull/6705
11 changed files with 100 additions and 91 deletions
|
@ -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;
|
||||
|
|
|
@ -36,6 +36,31 @@ KResultOr<NonnullRefPtr<Socket>> LocalSocket::create(int type)
|
|||
return adopt_ref(*new LocalSocket(type));
|
||||
}
|
||||
|
||||
KResultOr<SocketPair> 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)
|
||||
{
|
||||
|
|
|
@ -14,12 +14,18 @@ namespace Kernel {
|
|||
|
||||
class FileDescription;
|
||||
|
||||
struct SocketPair {
|
||||
NonnullRefPtr<FileDescription> description1;
|
||||
NonnullRefPtr<FileDescription> description2;
|
||||
};
|
||||
|
||||
class LocalSocket final : public Socket
|
||||
, public InlineLinkedListNode<LocalSocket> {
|
||||
friend class InlineLinkedListNode<LocalSocket>;
|
||||
|
||||
public:
|
||||
static KResultOr<NonnullRefPtr<Socket>> create(int type);
|
||||
static KResultOr<SocketPair> create_connected_pair(int type);
|
||||
virtual ~LocalSocket() override;
|
||||
|
||||
KResult sendfd(const FileDescription& socket_description, FileDescription& passing_description);
|
||||
|
|
|
@ -355,6 +355,7 @@ public:
|
|||
KResultOr<int> sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*>);
|
||||
KResultOr<int> sys$getsockname(Userspace<const Syscall::SC_getsockname_params*>);
|
||||
KResultOr<int> sys$getpeername(Userspace<const Syscall::SC_getpeername_params*>);
|
||||
KResultOr<int> sys$socketpair(Userspace<const Syscall::SC_socketpair_params*>);
|
||||
KResultOr<int> sys$sched_setparam(pid_t pid, Userspace<const struct sched_param*>);
|
||||
KResultOr<int> sys$sched_getparam(pid_t pid, Userspace<struct sched_param*>);
|
||||
KResultOr<int> sys$create_thread(void* (*)(void*), Userspace<const Syscall::SC_create_thread_params*>);
|
||||
|
@ -529,6 +530,8 @@ private:
|
|||
|
||||
void clear_futex_queues_on_exec();
|
||||
|
||||
void setup_socket_fd(int fd, NonnullRefPtr<FileDescription> description, int type);
|
||||
|
||||
inline PerformanceEventBuffer* current_perf_events_buffer()
|
||||
{
|
||||
return g_profiling_all_threads ? g_global_perf_events : m_perf_event_buffer.ptr();
|
||||
|
|
|
@ -20,6 +20,18 @@ namespace Kernel {
|
|||
REQUIRE_PROMISE(unix); \
|
||||
} while (0)
|
||||
|
||||
void Process::setup_socket_fd(int fd, NonnullRefPtr<FileDescription> 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<int> Process::sys$socket(int domain, int type, int protocol)
|
||||
{
|
||||
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(domain);
|
||||
|
@ -35,14 +47,7 @@ KResultOr<int> 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<int> Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_pa
|
|||
return socket.setsockopt(params.level, params.option, user_value, params.value_size);
|
||||
}
|
||||
|
||||
KResultOr<int> Process::sys$socketpair(Userspace<const Syscall::SC_socketpair_params*> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
@ -150,21 +150,6 @@ index 554ceb0b..67464ef2 100644
|
|||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
{
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue