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.
This commit is contained in:
SmallJoker 2023-04-07 12:49:23 +02:00 committed by GitHub
parent 7048fc25dd
commit d975ebdcb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 37 additions and 21 deletions

View File

@ -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;
u16 field_count;
*pkt >> field_count;
*pkt >> p >> formname >> num;
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;