Add pointCount cap to SMSG_MONSTER_MOVE spline parsing

Improve robustness of monster move spline parsing by capping the pointCount
field to prevent excessive iteration from malformed or malicious packets.

- WotLK: Cap pointCount to 1000 waypoints (realistic maximum for movement)
- Vanilla (Turtle): Reduce existing cap from 16384 to 1000 and add warning
  logging when cap is applied
- Both variants now log warnings when cap is exceeded, including guid context

A malicious or corrupted server sending an unrealistic pointCount value (e.g.
uint32_max) could previously cause the client to allocate excessive memory or
iterate excessively. The 1000-waypoint cap aligns with realistic movement
paths while protecting against DoS vectors.

Part of ongoing Tier 2 work to improve multi-expansion packet parsing robustness.
This commit is contained in:
Kelsi 2026-03-11 14:13:09 -07:00
parent 73abbc2a08
commit e464300346

View file

@ -2723,6 +2723,14 @@ bool MonsterMoveParser::parse(network::Packet& packet, MonsterMoveData& data) {
if (pointCount == 0) return true;
// Cap pointCount to prevent excessive iteration from malformed packets
constexpr uint32_t kMaxSplinePoints = 1000;
if (pointCount > kMaxSplinePoints) {
LOG_WARNING("SMSG_MONSTER_MOVE: pointCount=", pointCount, " exceeds max ", kMaxSplinePoints,
" (guid=0x", std::hex, data.guid, std::dec, "), capping");
pointCount = kMaxSplinePoints;
}
// Catmullrom or Flying → all waypoints stored as absolute float3 (uncompressed).
// Otherwise: first float3 is final destination, remaining are packed deltas.
bool uncompressed = (data.splineFlags & (0x00080000 | 0x00002000)) != 0;
@ -2824,7 +2832,14 @@ bool MonsterMoveParser::parseVanilla(network::Packet& packet, MonsterMoveData& d
uint32_t pointCount = packet.readUInt32();
if (pointCount == 0) return true;
if (pointCount > 16384) return false; // sanity
// Cap pointCount to prevent excessive iteration from malformed packets
constexpr uint32_t kMaxSplinePoints = 1000;
if (pointCount > kMaxSplinePoints) {
LOG_WARNING("SMSG_MONSTER_MOVE(Vanilla): pointCount=", pointCount, " exceeds max ", kMaxSplinePoints,
" (guid=0x", std::hex, data.guid, std::dec, "), capping");
pointCount = kMaxSplinePoints;
}
// First float[3] is destination.
if (packet.getReadPos() + 12 > packet.getSize()) return true;