mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 19:27:35 +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:
parent
cd02144a06
commit
d4195672b7
7 changed files with 127 additions and 2 deletions
|
@ -29,8 +29,8 @@
|
||||||
#include <Kernel/FileSystem/VirtualFileSystem.h>
|
#include <Kernel/FileSystem/VirtualFileSystem.h>
|
||||||
#include <Kernel/Net/LocalSocket.h>
|
#include <Kernel/Net/LocalSocket.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
#include <Kernel/UnixTypes.h>
|
|
||||||
#include <Kernel/StdLib.h>
|
#include <Kernel/StdLib.h>
|
||||||
|
#include <Kernel/UnixTypes.h>
|
||||||
#include <LibC/errno_numbers.h>
|
#include <LibC/errno_numbers.h>
|
||||||
|
|
||||||
//#define DEBUG_LOCAL_SOCKET
|
//#define DEBUG_LOCAL_SOCKET
|
||||||
|
@ -397,4 +397,52 @@ KResult LocalSocket::chown(FileDescription&, uid_t uid, gid_t gid)
|
||||||
return KSuccess;
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,9 @@ public:
|
||||||
static KResultOr<NonnullRefPtr<Socket>> create(int type);
|
static KResultOr<NonnullRefPtr<Socket>> create(int type);
|
||||||
virtual ~LocalSocket() override;
|
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&)>);
|
static void for_each(Function<void(const LocalSocket&)>);
|
||||||
|
|
||||||
StringView socket_path() const;
|
StringView socket_path() const;
|
||||||
|
@ -71,6 +74,8 @@ private:
|
||||||
static Lockable<InlineLinkedList<LocalSocket>>& all_sockets();
|
static Lockable<InlineLinkedList<LocalSocket>>& all_sockets();
|
||||||
DoubleBuffer& receive_buffer_for(FileDescription&);
|
DoubleBuffer& receive_buffer_for(FileDescription&);
|
||||||
DoubleBuffer& send_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.
|
// An open socket file on the filesystem.
|
||||||
RefPtr<FileDescription> m_file;
|
RefPtr<FileDescription> m_file;
|
||||||
|
@ -100,6 +105,9 @@ private:
|
||||||
DoubleBuffer m_for_client;
|
DoubleBuffer m_for_client;
|
||||||
DoubleBuffer m_for_server;
|
DoubleBuffer m_for_server;
|
||||||
|
|
||||||
|
NonnullRefPtrVector<FileDescription> m_fds_for_client;
|
||||||
|
NonnullRefPtrVector<FileDescription> m_fds_for_server;
|
||||||
|
|
||||||
// for InlineLinkedList
|
// for InlineLinkedList
|
||||||
LocalSocket* m_prev { nullptr };
|
LocalSocket* m_prev { nullptr };
|
||||||
LocalSocket* m_next { nullptr };
|
LocalSocket* m_next { nullptr };
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include <Kernel/KSyms.h>
|
#include <Kernel/KSyms.h>
|
||||||
#include <Kernel/Module.h>
|
#include <Kernel/Module.h>
|
||||||
#include <Kernel/Multiboot.h>
|
#include <Kernel/Multiboot.h>
|
||||||
|
#include <Kernel/Net/LocalSocket.h>
|
||||||
#include <Kernel/Net/Socket.h>
|
#include <Kernel/Net/Socket.h>
|
||||||
#include <Kernel/PerformanceEventBuffer.h>
|
#include <Kernel/PerformanceEventBuffer.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
|
@ -5178,4 +5179,52 @@ KResult Process::poke_user_data(u32* address, u32 data)
|
||||||
return KResult(KSuccess);
|
return KResult(KSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Process::sys$sendfd(int sockfd, int fd)
|
||||||
|
{
|
||||||
|
REQUIRE_PROMISE(sendfd);
|
||||||
|
auto socket_description = file_description(sockfd);
|
||||||
|
if (!socket_description)
|
||||||
|
return -EBADF;
|
||||||
|
if (!socket_description->is_socket())
|
||||||
|
return -ENOTSOCK;
|
||||||
|
auto& socket = *socket_description->socket();
|
||||||
|
if (!socket.is_local())
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
if (!socket.is_connected())
|
||||||
|
return -ENOTCONN;
|
||||||
|
|
||||||
|
auto passing_descriptor = file_description(fd);
|
||||||
|
if (!passing_descriptor)
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
auto& local_socket = static_cast<LocalSocket&>(socket);
|
||||||
|
return local_socket.sendfd(*socket_description, *passing_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Process::sys$recvfd(int sockfd)
|
||||||
|
{
|
||||||
|
REQUIRE_PROMISE(recvfd);
|
||||||
|
auto socket_description = file_description(sockfd);
|
||||||
|
if (!socket_description)
|
||||||
|
return -EBADF;
|
||||||
|
if (!socket_description->is_socket())
|
||||||
|
return -ENOTSOCK;
|
||||||
|
auto& socket = *socket_description->socket();
|
||||||
|
if (!socket.is_local())
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
|
||||||
|
int new_fd = alloc_fd();
|
||||||
|
if (new_fd < 0)
|
||||||
|
return new_fd;
|
||||||
|
|
||||||
|
auto& local_socket = static_cast<LocalSocket&>(socket);
|
||||||
|
auto received_descriptor_or_error = local_socket.recvfd(*socket_description);
|
||||||
|
|
||||||
|
if (received_descriptor_or_error.is_error())
|
||||||
|
return received_descriptor_or_error.error();
|
||||||
|
|
||||||
|
m_fds[new_fd].set(*received_descriptor_or_error.value(), 0);
|
||||||
|
return new_fd;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,8 @@ extern VirtualAddress g_return_to_ring3_from_signal_trampoline;
|
||||||
__ENUMERATE_PLEDGE_PROMISE(proc) \
|
__ENUMERATE_PLEDGE_PROMISE(proc) \
|
||||||
__ENUMERATE_PLEDGE_PROMISE(exec) \
|
__ENUMERATE_PLEDGE_PROMISE(exec) \
|
||||||
__ENUMERATE_PLEDGE_PROMISE(unix) \
|
__ENUMERATE_PLEDGE_PROMISE(unix) \
|
||||||
|
__ENUMERATE_PLEDGE_PROMISE(recvfd) \
|
||||||
|
__ENUMERATE_PLEDGE_PROMISE(sendfd) \
|
||||||
__ENUMERATE_PLEDGE_PROMISE(fattr) \
|
__ENUMERATE_PLEDGE_PROMISE(fattr) \
|
||||||
__ENUMERATE_PLEDGE_PROMISE(tty) \
|
__ENUMERATE_PLEDGE_PROMISE(tty) \
|
||||||
__ENUMERATE_PLEDGE_PROMISE(chown) \
|
__ENUMERATE_PLEDGE_PROMISE(chown) \
|
||||||
|
@ -316,6 +318,8 @@ public:
|
||||||
int sys$perf_event(int type, FlatPtr arg1, FlatPtr arg2);
|
int sys$perf_event(int type, FlatPtr arg1, FlatPtr arg2);
|
||||||
int sys$get_stack_bounds(FlatPtr* stack_base, size_t* stack_size);
|
int sys$get_stack_bounds(FlatPtr* stack_base, size_t* stack_size);
|
||||||
int sys$ptrace(const Syscall::SC_ptrace_params*);
|
int sys$ptrace(const Syscall::SC_ptrace_params*);
|
||||||
|
int sys$sendfd(int sockfd, int fd);
|
||||||
|
int sys$recvfd(int sockfd);
|
||||||
|
|
||||||
template<bool sockname, typename Params>
|
template<bool sockname, typename Params>
|
||||||
int get_sock_or_peer_name(const Params&);
|
int get_sock_or_peer_name(const Params&);
|
||||||
|
|
|
@ -189,7 +189,9 @@ namespace Kernel {
|
||||||
__ENUMERATE_SYSCALL(shutdown) \
|
__ENUMERATE_SYSCALL(shutdown) \
|
||||||
__ENUMERATE_SYSCALL(get_stack_bounds) \
|
__ENUMERATE_SYSCALL(get_stack_bounds) \
|
||||||
__ENUMERATE_SYSCALL(ptrace) \
|
__ENUMERATE_SYSCALL(ptrace) \
|
||||||
__ENUMERATE_SYSCALL(minherit)
|
__ENUMERATE_SYSCALL(minherit) \
|
||||||
|
__ENUMERATE_SYSCALL(sendfd) \
|
||||||
|
__ENUMERATE_SYSCALL(recvfd)
|
||||||
|
|
||||||
namespace Syscall {
|
namespace Syscall {
|
||||||
|
|
||||||
|
|
|
@ -119,4 +119,16 @@ int getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
|
||||||
int rc = syscall(SC_getpeername, ¶ms);
|
int rc = syscall(SC_getpeername, ¶ms);
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sendfd(int sockfd, int fd)
|
||||||
|
{
|
||||||
|
int rc = syscall(SC_sendfd, sockfd, fd);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int recvfd(int sockfd)
|
||||||
|
{
|
||||||
|
int rc = syscall(SC_recvfd, sockfd);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,5 +100,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 setsockopt(int sockfd, int level, int option, const void*, socklen_t);
|
||||||
int getsockname(int sockfd, struct sockaddr*, socklen_t*);
|
int getsockname(int sockfd, struct sockaddr*, socklen_t*);
|
||||||
int getpeername(int sockfd, struct sockaddr*, socklen_t*);
|
int getpeername(int sockfd, struct sockaddr*, socklen_t*);
|
||||||
|
int sendfd(int sockfd, int fd);
|
||||||
|
int recvfd(int sockfd);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue