diff options
author | SmallJoker <SmallJoker@users.noreply.github.com> | 2023-04-07 12:49:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-07 12:49:23 +0200 |
commit | d975ebdcb98512c8b7c17af4a95481238a520078 (patch) | |
tree | 105210a2aa250badbaf8b1cc4dd22479cf570459 | |
parent | 7048fc25dd963490552214e15d5e9a4c612d6b18 (diff) | |
download | minetest-d975ebdcb98512c8b7c17af4a95481238a520078.tar.xz |
Limit formspec fields to 640K (#13380)
Fixes an issue where long inputs could cause issues when dealing with formspecs.
The expected data is usually below 1 KiB, however that's not a technical limit.
-rw-r--r-- | src/network/serverpackethandler.cpp | 56 |
1 files changed, 36 insertions, 20 deletions
diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 89e2e2a1c..237c7805c 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1342,21 +1342,26 @@ void Server::handleCommand_RemovedSounds(NetworkPacket* pkt) } } -void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt) +static bool pkt_read_formspec_fields(NetworkPacket *pkt, StringMap &fields) { - v3s16 p; - std::string formname; - u16 num; - - *pkt >> p >> formname >> num; + u16 field_count; + *pkt >> field_count; - StringMap fields; - for (u16 k = 0; k < num; k++) { + u64 length = 0; + for (u16 k = 0; k < field_count; k++) { std::string fieldname; *pkt >> fieldname; fields[fieldname] = pkt->readLongString(); + + length += fieldname.size(); + length += fields[fieldname].size(); } + // 640K ought to be enough for anyone + return length < 640 * 1024; +} +void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt) +{ session_t peer_id = pkt->getPeerId(); RemotePlayer *player = m_env->getPlayer(peer_id); @@ -1377,6 +1382,18 @@ void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt) return; } + v3s16 p; + std::string formname; + StringMap fields; + + *pkt >> p >> formname; + + if (!pkt_read_formspec_fields(pkt, fields)) { + warningstream << "Too large formspec fields! Ignoring for pos=" + << PP(p) << ", player=" << player->getName() << std::endl; + return; + } + // If something goes wrong, this player is to blame RollbackScopeActor rollback_scope(m_rollback, std::string("player:")+player->getName()); @@ -1397,18 +1414,6 @@ void Server::handleCommand_NodeMetaFields(NetworkPacket* pkt) void Server::handleCommand_InventoryFields(NetworkPacket* pkt) { - std::string client_formspec_name; - u16 num; - - *pkt >> client_formspec_name >> num; - - StringMap fields; - for (u16 k = 0; k < num; k++) { - std::string fieldname; - *pkt >> fieldname; - fields[fieldname] = pkt->readLongString(); - } - session_t peer_id = pkt->getPeerId(); RemotePlayer *player = m_env->getPlayer(peer_id); @@ -1429,6 +1434,17 @@ void Server::handleCommand_InventoryFields(NetworkPacket* pkt) return; } + std::string client_formspec_name; + StringMap fields; + + *pkt >> client_formspec_name; + + if (!pkt_read_formspec_fields(pkt, fields)) { + warningstream << "Too large formspec fields! Ignoring for formname=\"" + << client_formspec_name << "\", player=" << player->getName() << std::endl; + return; + } + if (client_formspec_name.empty()) { // pass through inventory submits m_script->on_playerReceiveFields(playersao, client_formspec_name, fields); return; |