fix(dbc): cap JSON DBC string sizes (4KB/string, 64MB total) + NaN floats

JSON DBC values are mostly small integers, but a malicious file could
stuff 100MB strings into every cell to OOM the stringBlock (which has
no per-string or total cap). Added 4KB per-string + 64MB total caps —
fields exceeding either are zeroed. Float fields also get NaN scrub
(same pattern as the earlier vertex/keyframe guards).
This commit is contained in:
Kelsi 2026-05-06 06:19:01 -07:00
parent 719951976d
commit be64298218

View file

@ -2,6 +2,7 @@
#include "core/logger.hpp"
#include <nlohmann/json.hpp>
#include <cctype>
#include <cmath>
#include <cstring>
#include <set>
#include <sstream>
@ -430,8 +431,14 @@ bool DBCFile::loadJSON(const std::vector<uint8_t>& jsonData) {
const auto& val = row[col];
if (val.is_string()) {
const std::string& str = val.get_ref<const std::string&>();
// Cap individual string at 4KB and total stringBlock at
// 64MB to prevent OOM from a malicious JSON DBC stuffing
// huge strings into every field.
if (str.empty()) {
fields[col] = 0;
} else if (str.size() > 4096 ||
stringBlock.size() + str.size() > 64ull * 1024 * 1024) {
fields[col] = 0;
} else {
fields[col] = static_cast<uint32_t>(stringBlock.size());
stringBlock.insert(stringBlock.end(), str.begin(), str.end());
@ -439,6 +446,7 @@ bool DBCFile::loadJSON(const std::vector<uint8_t>& jsonData) {
}
} else if (val.is_number_float()) {
float f = val.get<float>();
if (!std::isfinite(f)) f = 0.0f;
std::memcpy(&fields[col], &f, 4);
} else if (val.is_number_integer()) {
fields[col] = val.get<uint32_t>();