Harden MotdParser and UpdateObjectParser against truncated packets

- MotdParser: cap lineCount to 64 to prevent unbounded memory allocation,
  add bounds check before each string read
- UpdateObjectParser: add bounds validation before each update mask block
  and field value read to prevent reading past packet boundary
This commit is contained in:
Kelsi 2026-03-11 14:41:25 -07:00
parent 6fa1e49cb2
commit 2c67331bc3

View file

@ -666,12 +666,24 @@ bool MotdParser::parse(network::Packet& packet, MotdData& data) {
uint32_t lineCount = packet.readUInt32();
// Cap lineCount to prevent unbounded memory allocation
const uint32_t MAX_MOTD_LINES = 64;
if (lineCount > MAX_MOTD_LINES) {
LOG_WARNING("MotdParser: lineCount capped (requested=", lineCount, ")");
lineCount = MAX_MOTD_LINES;
}
LOG_INFO("Parsed SMSG_MOTD: ", lineCount, " line(s)");
data.lines.clear();
data.lines.reserve(lineCount);
for (uint32_t i = 0; i < lineCount; ++i) {
// Validate at least 1 byte available for the string
if (packet.getReadPos() >= packet.getSize()) {
LOG_WARNING("MotdParser: truncated at line ", i + 1);
break;
}
std::string line = packet.readString();
data.lines.push_back(line);
LOG_DEBUG(" MOTD[", i + 1, "]: ", line);
@ -1182,6 +1194,11 @@ bool UpdateObjectParser::parseUpdateFields(network::Packet& packet, UpdateBlock&
static thread_local std::vector<uint32_t> updateMask;
updateMask.resize(blockCount);
for (int i = 0; i < blockCount; ++i) {
// Validate 4 bytes available before each block read
if (packet.getReadPos() + 4 > packet.getSize()) {
LOG_WARNING("UpdateObjectParser: truncated update mask at block ", i);
return false;
}
updateMask[i] = packet.readUInt32();
}
@ -1206,6 +1223,11 @@ bool UpdateObjectParser::parseUpdateFields(network::Packet& packet, UpdateBlock&
if (fieldIndex > highestSetBit) {
highestSetBit = fieldIndex;
}
// Validate 4 bytes available before reading field value
if (packet.getReadPos() + 4 > packet.getSize()) {
LOG_WARNING("UpdateObjectParser: truncated field value at field ", fieldIndex);
return false;
}
uint32_t value = packet.readUInt32();
// fieldIndex is monotonically increasing here, so end() is a good insertion hint.
block.fields.emplace_hint(block.fields.end(), fieldIndex, value);