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.
This commit is contained in:
Levi Neely 2026-10-08 18:06:13 +02:00
parent f503c53dfc
commit 08a75c06af
1 changed files with 9 additions and 0 deletions

View File

@ -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); m_error = QStringLiteral("9P message too short (%1)").arg(size);
return false; 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]); *type = uint8_t(hdr[4]);
*tag = uint16_t(uint8_t(hdr[5]) | (uint16_t(uint8_t(hdr[6])) << 8)); *tag = uint16_t(uint8_t(hdr[5]) | (uint16_t(uint8_t(hdr[6])) << 8));
const int bodyLen = int(size) - 7; const int bodyLen = int(size) - 7;