From 91034718637aedbdfddacaec7babeec76077f262 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 25 Oct 2020 11:37:42 +0100 Subject: [PATCH] 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. --- Libraries/LibIPC/Connection.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Libraries/LibIPC/Connection.h b/Libraries/LibIPC/Connection.h index 016669aa3d..4db21a6dc7 100644 --- a/Libraries/LibIPC/Connection.h +++ b/Libraries/LibIPC/Connection.h @@ -160,6 +160,12 @@ protected: bool drain_messages_from_peer() { Vector 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 m_notifier; NonnullOwnPtrVector m_unprocessed_messages; + ByteBuffer m_unprocessed_bytes; pid_t m_peer_pid { -1 }; };