Bound replicated vector size before resize() - #2893
Conversation
std::vector<T> replication (both the generic sp::io operator>> and BASIC_REPLICATION_VECTOR) resizes to a uint32_t/size_t read directly off the network before reading a single element. A corrupt or hostile packet can announce a size near UINT32_MAX, forcing a multi-gigabyte allocation and crashing/DoS'ing whoever processes the packet. Clamp to a fixed upper bound (1,000,000 elements) and log a warning instead of trusting the announced size unconditionally.
|
This smells AI assisted/generated. I don't mind people using AI, but I do ask that if they did that they be up-front about it. |
|
Hello, I'm Eloy. Yes, that was AI generated, as a little project to learn how to use it in our free time we're doing https://github.com/VaroTv7/espaciokooplagunak. And a very big part of it basically is based on mixing Empty Epsilon and FoundryVTT, as we wanted to make a game that allows us to roleplay DnD while going on a cool spaceship. Anyway, as we were advancing there were some small fixes the AI/QA tools found (stuff like this one, or the CSS one, or some dependencies), so we thought it wouldn't hurt to open a few PRs upstream. But of course it's up to you guys if you want to accept them or not, if it's okay we can keep sending those upstream, and if not we'll just tell the AI to not do that. Best regards! |
Problem
std::vector<T>replication reads a size prefix straight off the network and callsresize()with it before reading a single element — both the genericsp::io::operator>>forstd::vector<T>insrc/multiplayer/basic.hand theBASIC_REPLICATION_VECTORmacro'sReceivecase.A corrupt packet, or a hostile client inside a multiplayer session, can announce a size near
UINT32_MAX, forcing a multi-gigabyte allocation before any bounds/data-availability check happens — a memory-exhaustion DoS / crash for whoever processes the packet (client or server).For contrast, the per-element index in
BASIC_REPLICATION_VECTOR's receive loop is already validated against the vector's current size before writing — this is specifically about the unboundedresize()call itself.Fix
Clamp the announced size to a fixed upper bound (
max_replicated_vector_size = 1'000'000) before resizing, logging a warning when a packet exceeds it, in both places that resize from a wire-provided size.Testing
Built with
WARNING_IS_ERROR=1against a sibling SeriousProton checkout — full clean build succeeds (539/539 targets), no warnings introduced.I did not add an automated regression test for this — I'm not familiar enough with this codebase's network/replication test setup to know where a targeted test would fit; happy to add one if pointed at the right harness.