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

LibIPC: Handle partial messages

Since we're using byte streamed Unix sockets for the IPC protocols,
it's possible for the kernel to run out of socket buffer space with
a partial message near the end of the buffer.

Handle this situation in IPC::Connection by buffering the bytes of
what may be a partial message, and prepending them to the incoming
data next time we receive from the peer.

This fixes WindowServer asserting when a peer is spamming it hard.
This commit is contained in:
Andreas Kling 2020-10-25 11:37:42 +01:00
parent ace15e0043
commit 9103471863

View file

@ -160,6 +160,12 @@ protected:
bool drain_messages_from_peer()
{
Vector<u8> bytes;
if (!m_unprocessed_bytes.is_empty()) {
bytes.append(m_unprocessed_bytes.data(), m_unprocessed_bytes.size());
m_unprocessed_bytes.clear();
}
while (m_socket->is_open()) {
u8 buffer[4096];
ssize_t nread = recv(m_socket->fd(), buffer, sizeof(buffer), MSG_DONTWAIT);
@ -192,7 +198,15 @@ protected:
} else if (auto message = PeerEndpoint::decode_message(remaining_bytes, decoded_bytes)) {
m_unprocessed_messages.append(message.release_nonnull());
} else {
ASSERT_NOT_REACHED();
// Sometimes we might receive a partial message. That's okay, just stash away
// the unprocessed bytes and we'll prepend them to the next incoming message
// in the next run of this function.
if (!m_unprocessed_bytes.is_empty()) {
dbg() << *this << "::drain_messages_from_peer: Already have unprocessed bytes";
shutdown();
}
m_unprocessed_bytes = remaining_bytes.isolated_copy();
break;
}
ASSERT(decoded_bytes);
}
@ -233,6 +247,7 @@ protected:
RefPtr<Core::Notifier> m_notifier;
NonnullOwnPtrVector<Message> m_unprocessed_messages;
ByteBuffer m_unprocessed_bytes;
pid_t m_peer_pid { -1 };
};