mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibIPC: Support sending file descriptors :^)
It is now possible to use the special IPC::File type in message arguments. In C++, the type is nothing more than a wrapper over a file descriptor. But when serializing/deserializing IPC::File arguments, LibIPC will use the sendfd/recvfd kernel APIs instead of sending the integer inline. This makes it quite convenient to pass files over IPC, and will allow us to significantly tighten sandboxes in the future :^) Closes https://github.com/SerenityOS/serenity/issues/3643
This commit is contained in:
parent
fa2e3e2be4
commit
23dc3ff0c2
Notes:
sideshowbarker
2024-07-19 01:17:44 +09:00
Author: https://github.com/bugaevc Commit: https://github.com/SerenityOS/serenity/commit/23dc3ff0c2d Pull-request: https://github.com/SerenityOS/serenity/pull/4130 Reviewed-by: https://github.com/alimpfard Reviewed-by: https://github.com/awesomekling
9 changed files with 148 additions and 50 deletions
|
@ -217,6 +217,7 @@ int main(int argc, char** argv)
|
|||
#include <LibIPC/Dictionary.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
#include <LibIPC/Endpoint.h>
|
||||
#include <LibIPC/File.h>
|
||||
#include <LibIPC/Message.h>
|
||||
)~~~");
|
||||
|
||||
|
@ -318,9 +319,9 @@ public:
|
|||
static i32 static_message_id() { return (int)MessageID::@message.name@; }
|
||||
virtual const char* message_name() const override { return "@endpoint.name@::@message.name@"; }
|
||||
|
||||
static OwnPtr<@message.name@> decode(InputMemoryStream& stream)
|
||||
static OwnPtr<@message.name@> decode(InputMemoryStream& stream, int sockfd)
|
||||
{
|
||||
IPC::Decoder decoder { stream };
|
||||
IPC::Decoder decoder { stream, sockfd };
|
||||
)~~~");
|
||||
|
||||
for (auto& parameter : parameters) {
|
||||
|
@ -436,7 +437,7 @@ public:
|
|||
static String static_name() { return "@endpoint.name@"; }
|
||||
virtual String name() const override { return "@endpoint.name@"; }
|
||||
|
||||
static OwnPtr<IPC::Message> decode_message(const ByteBuffer& buffer)
|
||||
static OwnPtr<IPC::Message> decode_message(const ByteBuffer& buffer, int sockfd)
|
||||
{
|
||||
InputMemoryStream stream { buffer };
|
||||
i32 message_endpoint_magic = 0;
|
||||
|
@ -488,7 +489,7 @@ public:
|
|||
|
||||
message_generator.append(R"~~~(
|
||||
case (int)Messages::@endpoint.name@::MessageID::@message.name@:
|
||||
message = Messages::@endpoint.name@::@message.name@::decode(stream);
|
||||
message = Messages::@endpoint.name@::@message.name@::decode(stream, sockfd);
|
||||
break;
|
||||
)~~~");
|
||||
};
|
||||
|
|
|
@ -77,12 +77,25 @@ public:
|
|||
|
||||
auto buffer = message.encode();
|
||||
// Prepend the message size.
|
||||
uint32_t message_size = buffer.size();
|
||||
buffer.prepend(reinterpret_cast<const u8*>(&message_size), sizeof(message_size));
|
||||
uint32_t message_size = buffer.data.size();
|
||||
buffer.data.prepend(reinterpret_cast<const u8*>(&message_size), sizeof(message_size));
|
||||
|
||||
#ifdef __serenity__
|
||||
for (int fd : buffer.fds) {
|
||||
auto rc = sendfd(m_socket->fd(), fd);
|
||||
if (rc < 0) {
|
||||
perror("sendfd");
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!buffer.fds.is_empty())
|
||||
warnln("fd passing is not supported on this platform, sorry :(");
|
||||
#endif
|
||||
|
||||
size_t total_nwritten = 0;
|
||||
while (total_nwritten < buffer.size()) {
|
||||
auto nwritten = write(m_socket->fd(), buffer.data() + total_nwritten, buffer.size() - total_nwritten);
|
||||
while (total_nwritten < buffer.data.size()) {
|
||||
auto nwritten = write(m_socket->fd(), buffer.data.data() + total_nwritten, buffer.data.size() - total_nwritten);
|
||||
if (nwritten < 0) {
|
||||
switch (errno) {
|
||||
case EPIPE:
|
||||
|
@ -202,9 +215,9 @@ protected:
|
|||
break;
|
||||
index += sizeof(message_size);
|
||||
auto remaining_bytes = ByteBuffer::wrap(bytes.data() + index, bytes.size() - index);
|
||||
if (auto message = LocalEndpoint::decode_message(remaining_bytes)) {
|
||||
if (auto message = LocalEndpoint::decode_message(remaining_bytes, m_socket->fd())) {
|
||||
m_unprocessed_messages.append(message.release_nonnull());
|
||||
} else if (auto message = PeerEndpoint::decode_message(remaining_bytes)) {
|
||||
} else if (auto message = PeerEndpoint::decode_message(remaining_bytes, m_socket->fd())) {
|
||||
m_unprocessed_messages.append(message.release_nonnull());
|
||||
} else {
|
||||
dbgln("Failed to parse a message");
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#include <AK/URL.h>
|
||||
#include <LibIPC/Decoder.h>
|
||||
#include <LibIPC/Dictionary.h>
|
||||
#include <LibIPC/File.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
namespace IPC {
|
||||
|
||||
|
@ -163,4 +166,21 @@ bool Decoder::decode(Dictionary& dictionary)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Decoder::decode(File& file)
|
||||
{
|
||||
#ifdef __serenity__
|
||||
int fd = recvfd(m_sockfd);
|
||||
if (fd < 0) {
|
||||
dbgln("recvfd: {}", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
file = File(fd);
|
||||
return true;
|
||||
#else
|
||||
(void)file;
|
||||
warnln("fd passing is not supported on this platform, sorry :(");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,8 +44,9 @@ inline bool decode(Decoder&, T&)
|
|||
|
||||
class Decoder {
|
||||
public:
|
||||
explicit Decoder(InputMemoryStream& stream)
|
||||
Decoder(InputMemoryStream& stream, int sockfd)
|
||||
: m_stream(stream)
|
||||
, m_sockfd(sockfd)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -63,6 +64,7 @@ public:
|
|||
bool decode(ByteBuffer&);
|
||||
bool decode(URL&);
|
||||
bool decode(Dictionary&);
|
||||
bool decode(File&);
|
||||
template<typename K, typename V>
|
||||
bool decode(HashMap<K, V>& hashmap)
|
||||
{
|
||||
|
@ -124,6 +126,7 @@ public:
|
|||
|
||||
private:
|
||||
InputMemoryStream& m_stream;
|
||||
int m_sockfd { -1 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <AK/URL.h>
|
||||
#include <LibIPC/Dictionary.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
#include <LibIPC/File.h>
|
||||
|
||||
namespace IPC {
|
||||
|
||||
|
@ -39,77 +40,77 @@ Encoder& Encoder::operator<<(bool value)
|
|||
|
||||
Encoder& Encoder::operator<<(u8 value)
|
||||
{
|
||||
m_buffer.append(value);
|
||||
m_buffer.data.append(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Encoder& Encoder::operator<<(u16 value)
|
||||
{
|
||||
m_buffer.ensure_capacity(m_buffer.size() + 2);
|
||||
m_buffer.unchecked_append((u8)value);
|
||||
m_buffer.unchecked_append((u8)(value >> 8));
|
||||
m_buffer.data.ensure_capacity(m_buffer.data.size() + 2);
|
||||
m_buffer.data.unchecked_append((u8)value);
|
||||
m_buffer.data.unchecked_append((u8)(value >> 8));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Encoder& Encoder::operator<<(u32 value)
|
||||
{
|
||||
m_buffer.ensure_capacity(m_buffer.size() + 4);
|
||||
m_buffer.unchecked_append((u8)value);
|
||||
m_buffer.unchecked_append((u8)(value >> 8));
|
||||
m_buffer.unchecked_append((u8)(value >> 16));
|
||||
m_buffer.unchecked_append((u8)(value >> 24));
|
||||
m_buffer.data.ensure_capacity(m_buffer.data.size() + 4);
|
||||
m_buffer.data.unchecked_append((u8)value);
|
||||
m_buffer.data.unchecked_append((u8)(value >> 8));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 16));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 24));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Encoder& Encoder::operator<<(u64 value)
|
||||
{
|
||||
m_buffer.ensure_capacity(m_buffer.size() + 8);
|
||||
m_buffer.unchecked_append((u8)value);
|
||||
m_buffer.unchecked_append((u8)(value >> 8));
|
||||
m_buffer.unchecked_append((u8)(value >> 16));
|
||||
m_buffer.unchecked_append((u8)(value >> 24));
|
||||
m_buffer.unchecked_append((u8)(value >> 32));
|
||||
m_buffer.unchecked_append((u8)(value >> 40));
|
||||
m_buffer.unchecked_append((u8)(value >> 48));
|
||||
m_buffer.unchecked_append((u8)(value >> 56));
|
||||
m_buffer.data.ensure_capacity(m_buffer.data.size() + 8);
|
||||
m_buffer.data.unchecked_append((u8)value);
|
||||
m_buffer.data.unchecked_append((u8)(value >> 8));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 16));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 24));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 32));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 40));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 48));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 56));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Encoder& Encoder::operator<<(i8 value)
|
||||
{
|
||||
m_buffer.append((u8)value);
|
||||
m_buffer.data.append((u8)value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Encoder& Encoder::operator<<(i16 value)
|
||||
{
|
||||
m_buffer.ensure_capacity(m_buffer.size() + 2);
|
||||
m_buffer.unchecked_append((u8)value);
|
||||
m_buffer.unchecked_append((u8)(value >> 8));
|
||||
m_buffer.data.ensure_capacity(m_buffer.data.size() + 2);
|
||||
m_buffer.data.unchecked_append((u8)value);
|
||||
m_buffer.data.unchecked_append((u8)(value >> 8));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Encoder& Encoder::operator<<(i32 value)
|
||||
{
|
||||
m_buffer.ensure_capacity(m_buffer.size() + 4);
|
||||
m_buffer.unchecked_append((u8)value);
|
||||
m_buffer.unchecked_append((u8)(value >> 8));
|
||||
m_buffer.unchecked_append((u8)(value >> 16));
|
||||
m_buffer.unchecked_append((u8)(value >> 24));
|
||||
m_buffer.data.ensure_capacity(m_buffer.data.size() + 4);
|
||||
m_buffer.data.unchecked_append((u8)value);
|
||||
m_buffer.data.unchecked_append((u8)(value >> 8));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 16));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 24));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Encoder& Encoder::operator<<(i64 value)
|
||||
{
|
||||
m_buffer.ensure_capacity(m_buffer.size() + 8);
|
||||
m_buffer.unchecked_append((u8)value);
|
||||
m_buffer.unchecked_append((u8)(value >> 8));
|
||||
m_buffer.unchecked_append((u8)(value >> 16));
|
||||
m_buffer.unchecked_append((u8)(value >> 24));
|
||||
m_buffer.unchecked_append((u8)(value >> 32));
|
||||
m_buffer.unchecked_append((u8)(value >> 40));
|
||||
m_buffer.unchecked_append((u8)(value >> 48));
|
||||
m_buffer.unchecked_append((u8)(value >> 56));
|
||||
m_buffer.data.ensure_capacity(m_buffer.data.size() + 8);
|
||||
m_buffer.data.unchecked_append((u8)value);
|
||||
m_buffer.data.unchecked_append((u8)(value >> 8));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 16));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 24));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 32));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 40));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 48));
|
||||
m_buffer.data.unchecked_append((u8)(value >> 56));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -130,7 +131,7 @@ Encoder& Encoder::operator<<(const char* value)
|
|||
|
||||
Encoder& Encoder::operator<<(const StringView& value)
|
||||
{
|
||||
m_buffer.append((const u8*)value.characters_without_null_termination(), value.length());
|
||||
m_buffer.data.append((const u8*)value.characters_without_null_termination(), value.length());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -145,7 +146,7 @@ Encoder& Encoder::operator<<(const String& value)
|
|||
Encoder& Encoder::operator<<(const ByteBuffer& value)
|
||||
{
|
||||
*this << static_cast<i32>(value.size());
|
||||
m_buffer.append(value.data(), value.size());
|
||||
m_buffer.data.append(value.data(), value.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -163,4 +164,10 @@ Encoder& Encoder::operator<<(const Dictionary& dictionary)
|
|||
return *this;
|
||||
}
|
||||
|
||||
Encoder& Encoder::operator<<(const File& file)
|
||||
{
|
||||
m_buffer.fds.append(file.fd());
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
Encoder& operator<<(const ByteBuffer&);
|
||||
Encoder& operator<<(const URL&);
|
||||
Encoder& operator<<(const Dictionary&);
|
||||
Encoder& operator<<(const File&);
|
||||
template<typename K, typename V>
|
||||
Encoder& operator<<(const HashMap<K, V>& hashmap)
|
||||
{
|
||||
|
|
49
Libraries/LibIPC/File.h
Normal file
49
Libraries/LibIPC/File.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace IPC {
|
||||
|
||||
class File {
|
||||
public:
|
||||
// Must have a default constructor, because LibIPC
|
||||
// default-constructs arguments prior to decoding them.
|
||||
File() { }
|
||||
|
||||
// Intentionally not `explicit`.
|
||||
File(int fd)
|
||||
: m_fd(fd)
|
||||
{
|
||||
}
|
||||
|
||||
int fd() const { return m_fd; }
|
||||
|
||||
private:
|
||||
int m_fd { -1 };
|
||||
};
|
||||
|
||||
}
|
|
@ -32,5 +32,6 @@ class Decoder;
|
|||
class Dictionary;
|
||||
class Encoder;
|
||||
class Message;
|
||||
class File;
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,10 @@
|
|||
|
||||
namespace IPC {
|
||||
|
||||
typedef Vector<u8, 1024> MessageBuffer;
|
||||
struct MessageBuffer {
|
||||
Vector<u8, 1024> data;
|
||||
Vector<int> fds;
|
||||
};
|
||||
|
||||
class Message {
|
||||
public:
|
||||
|
|
Loading…
Reference in a new issue