mirror of
https://github.com/nlohmann/json.git
synced 2026-02-17 09:03:58 +00:00
fix(cbor): reject overflowing negative integers (#5039)
* fix(cbor): reject negative ints overflowing int64 CBOR encodes negative integers as "-1 - n" where n is uint64_t. When n > INT64_MAX, casting to int64_t caused undefined behavior and silent data corruption. Large negative values were incorrectly parsed as positive integers (e.g., -9223372036854775809 became 9223372036854775807). Add bounds check for to reject values that exceed int64_t representable range, returning parse_error instead of silently corrupting data. Added regression test cases to verify. Signed-off-by: Ville Vesilehto <ville@vesilehto.fi> * chore: clarify tests Add test for "n=0" case (result=-1) to cover the smallest magnitude boundary. Update comments to explain CBOR 0x3B encoding and why "result=0" is not possible. Clarify that n is an unsigned integer in the formula "result = -1 - n" to help understanding the tests. Signed-off-by: Ville Vesilehto <ville@vesilehto.fi> * fix(cbor): extend overflow checks for other types Extend negative integer overflow detection to all CBOR negative integer cases (0x38, 0x39, 0x3A) for consistency with the existing 0x3B check. Signed-off-by: Ville Vesilehto <ville@vesilehto.fi> --------- Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
This commit is contained in:
@@ -425,6 +425,25 @@ class binary_reader
|
||||
|
||||
@return whether a valid CBOR value was passed to the SAX parser
|
||||
*/
|
||||
|
||||
template<typename NumberType>
|
||||
bool get_cbor_negative_integer()
|
||||
{
|
||||
NumberType number{};
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, number)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const auto max_val = static_cast<NumberType>((std::numeric_limits<number_integer_t>::max)());
|
||||
if (number > max_val)
|
||||
{
|
||||
return sax->parse_error(chars_read, get_token_string(),
|
||||
parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::cbor, "negative integer overflow", "value"), nullptr));
|
||||
}
|
||||
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number));
|
||||
}
|
||||
|
||||
bool parse_cbor_internal(const bool get_char,
|
||||
const cbor_tag_handler_t tag_handler)
|
||||
{
|
||||
@@ -513,29 +532,16 @@ class binary_reader
|
||||
return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
|
||||
|
||||
case 0x38: // Negative integer (one-byte uint8_t follows)
|
||||
{
|
||||
std::uint8_t number{};
|
||||
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||
}
|
||||
return get_cbor_negative_integer<std::uint8_t>();
|
||||
|
||||
case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
|
||||
{
|
||||
std::uint16_t number{};
|
||||
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||
}
|
||||
return get_cbor_negative_integer<std::uint16_t>();
|
||||
|
||||
case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
|
||||
{
|
||||
std::uint32_t number{};
|
||||
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||
}
|
||||
return get_cbor_negative_integer<std::uint32_t>();
|
||||
|
||||
case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
|
||||
{
|
||||
std::uint64_t number{};
|
||||
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)
|
||||
- static_cast<number_integer_t>(number));
|
||||
}
|
||||
return get_cbor_negative_integer<std::uint64_t>();
|
||||
|
||||
// Binary data (0x00..0x17 bytes follow)
|
||||
case 0x40:
|
||||
|
||||
Reference in New Issue
Block a user