mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
This commit adds digit length validation to prevent denial-of-service attacks via excessively long numeric literals in USDA files, and implements comprehensive unit tests to verify the security guards. Changes: - Fix jsteemann::atoi bug with temporary string objects in uint32/int64/uint64 parsing - Add maximum digit length guards to ReadBasicType() for int, uint32_t, int64_t, uint64_t - int32: 12 digit limit (actual max: 10 digits) - uint32: 12 digit limit (actual max: 10 digits) - int64: 21 digit limit (actual max: 19 digits) - uint64: 22 digit limit (actual max: 20 digits) - Add unit-ascii-parse.cc/h with 4 test functions validating digit guards - Integrate tests into unit test framework via CMakeLists.txt and unit-main.cc Security impact: - Prevents parser resource exhaustion from malicious USDA files with extremely long integer literals (100+ digits) - int64/uint64 guards fully functional and tested - int32/uint32 guards partially bypassed by float parsing path (known limitation) All 26 unit tests pass including 4 new ASCII parser security tests. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
120 lines
2.4 KiB
C++
120 lines
2.4 KiB
C++
#ifdef _MSC_VER
|
|
#define NOMINMAX
|
|
#endif
|
|
|
|
#define TEST_NO_MAIN
|
|
#include "acutest.h"
|
|
|
|
#include "unit-ascii-parse.h"
|
|
#include "tinyusdz.hh"
|
|
|
|
using namespace tinyusdz;
|
|
|
|
// Helper function to parse a USD string
|
|
static bool parseUSDString(const std::string &usd_content, std::string *err) {
|
|
Stage stage;
|
|
std::string warn;
|
|
|
|
bool ret = LoadUSDFromMemory(
|
|
reinterpret_cast<const uint8_t *>(usd_content.data()),
|
|
usd_content.size(),
|
|
"memory.usda",
|
|
&stage,
|
|
&warn,
|
|
err);
|
|
|
|
return ret;
|
|
}
|
|
|
|
//
|
|
// int64_t digit length guard tests
|
|
// These tests verify that excessively long integer literals are rejected
|
|
// to prevent denial-of-service attacks via parser resource exhaustion
|
|
//
|
|
|
|
void ascii_parse_int64_valid_test(void) {
|
|
std::string err;
|
|
|
|
// Test value under the digit limit (should succeed)
|
|
{
|
|
std::string usd = R"(#usda 1.0
|
|
def Xform "Test" {
|
|
int64 testValue = 9223372036854775807
|
|
}
|
|
)";
|
|
bool ret = parseUSDString(usd, &err);
|
|
TEST_CHECK(ret == true);
|
|
}
|
|
}
|
|
|
|
void ascii_parse_int64_excessive_digits_test(void) {
|
|
std::string err;
|
|
|
|
// Test 22 digits (over the 21 digit limit) - should fail
|
|
{
|
|
std::string usd = R"(#usda 1.0
|
|
def Xform "Test" {
|
|
int64 testExcessive = 1234567890123456789012
|
|
}
|
|
)";
|
|
bool ret = parseUSDString(usd, &err);
|
|
TEST_CHECK(ret == false);
|
|
}
|
|
|
|
// Test 30 digits - should fail
|
|
{
|
|
std::string usd = R"(#usda 1.0
|
|
def Xform "Test" {
|
|
int64 testHuge = 123456789012345678901234567890
|
|
}
|
|
)";
|
|
bool ret = parseUSDString(usd, &err);
|
|
TEST_CHECK(ret == false);
|
|
}
|
|
}
|
|
|
|
//
|
|
// uint64_t digit length guard tests
|
|
//
|
|
|
|
void ascii_parse_uint64_valid_test(void) {
|
|
std::string err;
|
|
|
|
// Test value under the digit limit (should succeed)
|
|
{
|
|
std::string usd = R"(#usda 1.0
|
|
def Xform "Test" {
|
|
uint64 testValue = 18446744073709551615
|
|
}
|
|
)";
|
|
bool ret = parseUSDString(usd, &err);
|
|
TEST_CHECK(ret == true);
|
|
}
|
|
}
|
|
|
|
void ascii_parse_uint64_excessive_digits_test(void) {
|
|
std::string err;
|
|
|
|
// Test 23 digits (over the 22 digit limit) - should fail
|
|
{
|
|
std::string usd = R"(#usda 1.0
|
|
def Xform "Test" {
|
|
uint64 testExcessive = 12345678901234567890123
|
|
}
|
|
)";
|
|
bool ret = parseUSDString(usd, &err);
|
|
TEST_CHECK(ret == false);
|
|
}
|
|
|
|
// Test 30 digits - should fail
|
|
{
|
|
std::string usd = R"(#usda 1.0
|
|
def Xform "Test" {
|
|
uint64 testHuge = 123456789012345678901234567890
|
|
}
|
|
)";
|
|
bool ret = parseUSDString(usd, &err);
|
|
TEST_CHECK(ret == false);
|
|
}
|
|
}
|