aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSmallJoker <SmallJoker@users.noreply.github.com>2023-04-07 12:49:23 +0200
committerGitHub <noreply@github.com>2023-04-07 12:49:23 +0200
commitd975ebdcb98512c8b7c17af4a95481238a520078 (patch)
tree105210a2aa250badbaf8b1cc4dd22479cf570459
parent7048fc25dd963490552214e15d5e9a4c612d6b18 (diff)
downloadminetest-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.cpp56
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;