diff options
author | baptr <1522777+baptr@users.noreply.github.com> | 2023-02-14 02:40:06 -0800 |
---|---|---|
committer | baptr <1522777+baptr@users.noreply.github.com> | 2023-02-14 02:46:32 -0800 |
commit | 2eadbe7b78ab299359a8f8c4f9eb5d67e4b4aac9 (patch) | |
tree | 43d9b0d559cb47f08ff4571d3b63fb9eadce9d08 /modules/multiplayer | |
parent | b7723a01d957e6492a3f20bce8a47d3559afe5c5 (diff) |
Fix multiplayer replication crash in on_sync_receive.
A number of early continue cases applied the packet-provided `size`
without validation, allowing large uint32_t values to be treated as
negative offsets and leading to segfaults.
Now, we validate `size` against the buffer length immediately to avoid a
crash.
This could be triggered by receiving sync data for a synchronizer who's
root node had just been removed, since the code path that checked for
unusable sync state failed to advance the offset. Thus the next read
could interpret part of the payload as such an invalid `size`.
Now, we properly advance the read offset in that case (and raise a
better error).
Diffstat (limited to 'modules/multiplayer')
-rw-r--r-- | modules/multiplayer/scene_replication_interface.cpp | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp index 3466cb10df..68b6bc4a24 100644 --- a/modules/multiplayer/scene_replication_interface.cpp +++ b/modules/multiplayer/scene_replication_interface.cpp @@ -742,6 +742,7 @@ Error SceneReplicationInterface::on_sync_receive(int p_from, const uint8_t *p_bu ofs += 4; uint32_t size = decode_uint32(&p_buffer[ofs]); ofs += 4; + ERR_FAIL_COND_V(size > uint32_t(p_buffer_len - ofs), ERR_INVALID_DATA); MultiplayerSynchronizer *sync = nullptr; if (net_id & 0x80000000) { sync = Object::cast_to<MultiplayerSynchronizer>(multiplayer->get_path_cache()->get_cached_object(p_from, net_id & 0x7FFFFFFF)); @@ -756,14 +757,15 @@ Error SceneReplicationInterface::on_sync_receive(int p_from, const uint8_t *p_bu } Node *node = sync->get_root_node(); if (sync->get_multiplayer_authority() != p_from || !node) { - ERR_CONTINUE(true); + // Not valid for me. + ofs += size; + ERR_CONTINUE_MSG(true, "Ignoring sync data from non-authority or for missing node."); } if (!sync->update_inbound_sync_time(time)) { // State is too old. ofs += size; continue; } - ERR_FAIL_COND_V(size > uint32_t(p_buffer_len - ofs), ERR_BUG); const List<NodePath> props = sync->get_replication_config()->get_sync_properties(); Vector<Variant> vars; vars.resize(props.size()); |