1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 03:57:44 +00:00

Kernel+LibC: Add sys$recvfd() and sys$sendfd() for fd passing

These new syscalls allow you to send and receive file descriptors over
a local domain socket. This will enable various privilege separation
techniques and other good stuff. :^)
This commit is contained in:
Andreas Kling 2020-06-24 22:57:37 +02:00
parent cd02144a06
commit d4195672b7
7 changed files with 127 additions and 2 deletions

View file

@ -29,8 +29,8 @@
#include <Kernel/FileSystem/VirtualFileSystem.h>
#include <Kernel/Net/LocalSocket.h>
#include <Kernel/Process.h>
#include <Kernel/UnixTypes.h>
#include <Kernel/StdLib.h>
#include <Kernel/UnixTypes.h>
#include <LibC/errno_numbers.h>
//#define DEBUG_LOCAL_SOCKET
@ -397,4 +397,52 @@ KResult LocalSocket::chown(FileDescription&, uid_t uid, gid_t gid)
return KSuccess;
}
NonnullRefPtrVector<FileDescription>& LocalSocket::recvfd_queue_for(FileDescription& description)
{
auto role = this->role(description);
if (role == Role::Connected)
return m_fds_for_client;
if (role == Role::Accepted)
return m_fds_for_server;
ASSERT_NOT_REACHED();
}
NonnullRefPtrVector<FileDescription>& LocalSocket::sendfd_queue_for(FileDescription& description)
{
auto role = this->role(description);
if (role == Role::Connected)
return m_fds_for_server;
if (role == Role::Accepted)
return m_fds_for_client;
ASSERT_NOT_REACHED();
}
KResult LocalSocket::sendfd(FileDescription& socket_description, NonnullRefPtr<FileDescription> passing_description)
{
LOCKER(lock());
auto role = this->role(socket_description);
if (role != Role::Connected && role != Role::Accepted)
return KResult(-EINVAL);
auto& queue = sendfd_queue_for(socket_description);
// FIXME: Figure out how we should limit this properly.
if (queue.size() > 16)
return KResult(-EBUSY);
queue.append(move(passing_description));
return KSuccess;
}
KResultOr<NonnullRefPtr<FileDescription>> LocalSocket::recvfd(FileDescription& socket_description)
{
LOCKER(lock());
auto role = this->role(socket_description);
if (role != Role::Connected && role != Role::Accepted)
return KResult(-EINVAL);
auto& queue = recvfd_queue_for(socket_description);
if (queue.is_empty()) {
// FIXME: Figure out the perfect error code for this.
return KResult(-EAGAIN);
}
return queue.take_first();
}
}

View file

@ -42,6 +42,9 @@ public:
static KResultOr<NonnullRefPtr<Socket>> create(int type);
virtual ~LocalSocket() override;
KResult sendfd(FileDescription& socket_description, NonnullRefPtr<FileDescription> passing_description);
KResultOr<NonnullRefPtr<FileDescription>> recvfd(FileDescription& socket_description);
static void for_each(Function<void(const LocalSocket&)>);
StringView socket_path() const;
@ -71,6 +74,8 @@ private:
static Lockable<InlineLinkedList<LocalSocket>>& all_sockets();
DoubleBuffer& receive_buffer_for(FileDescription&);
DoubleBuffer& send_buffer_for(FileDescription&);
NonnullRefPtrVector<FileDescription>& sendfd_queue_for(FileDescription&);
NonnullRefPtrVector<FileDescription>& recvfd_queue_for(FileDescription&);
// An open socket file on the filesystem.
RefPtr<FileDescription> m_file;
@ -100,6 +105,9 @@ private:
DoubleBuffer m_for_client;
DoubleBuffer m_for_server;
NonnullRefPtrVector<FileDescription> m_fds_for_client;
NonnullRefPtrVector<FileDescription> m_fds_for_server;
// for InlineLinkedList
LocalSocket* m_prev { nullptr };
LocalSocket* m_next { nullptr };