From 08a75c06affc840c527ab523f0b48e4d01c9e750 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Thu, 8 Oct 2026 18:06:13 +0200 Subject: [PATCH] plumb: bound 9P message size in recvMsg to fix SIGBUS on desync A corrupt or desynced stream could deliver a size[4] far larger than the negotiated msize. recvMsg trusted it, so bodyLen=int(size)-7 became huge (or negative when size>INT_MAX), and the following b.resize()/readExactly corrupted the heap -> SIGBUS in the PlumbReader edit-port thread. Reject any message whose size exceeds the negotiated msize. --- src/plumb/ninep.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plumb/ninep.cpp b/src/plumb/ninep.cpp index abbbcda..163ed1a 100644 --- a/src/plumb/ninep.cpp +++ b/src/plumb/ninep.cpp @@ -184,6 +184,15 @@ bool NineP::recvMsg(uint8_t *type, uint16_t *tag, QByteArray *body) m_error = QStringLiteral("9P message too short (%1)").arg(size); return false; } + // The negotiated msize is the hard ceiling for any single 9P message. A + // larger size[4] means a desynced or corrupt stream; trusting it would make + // the b.resize()/readExactly() below allocate and write a bogus (possibly + // multi-gigabyte, or negative-when-cast-to-int) buffer, corrupting the heap. + // Reject it instead of crashing. + if (size > m_msize) { + m_error = QStringLiteral("9P message too large (%1 > msize %2)").arg(size).arg(m_msize); + return false; + } *type = uint8_t(hdr[4]); *tag = uint16_t(uint8_t(hdr[5]) | (uint16_t(uint8_t(hdr[6])) << 8)); const int bodyLen = int(size) - 7;