Skip to content

Commit

Permalink
🐛 fix for #962
Browse files Browse the repository at this point in the history
Added out_of_range exception for UBJSON containers with sizes that exceed the target container's max_size.
  • Loading branch information
nlohmann committed Feb 6, 2018
1 parent 8b457ac commit 33a9b00
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 6 deletions.
1 change: 1 addition & 0 deletions include/nlohmann/detail/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference
json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.
json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.
json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. |
json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |
@liveexample{The following code shows how an `out_of_range` exception can be
caught.,out_of_range}
Expand Down
20 changes: 17 additions & 3 deletions include/nlohmann/detail/input/binary_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1246,14 +1246,22 @@ class binary_reader

if (size_and_type.first != string_t::npos)
{
if (JSON_UNLIKELY(size_and_type.first > result.max_size()))
{
JSON_THROW(out_of_range::create(408,
"excessive array size: " + std::to_string(size_and_type.first)));
}

if (size_and_type.second != 0)
{
if (size_and_type.second != 'N')
{
std::generate_n(std::back_inserter(*result.m_value.array),
size_and_type.first, [this, size_and_type]()
{
return get_ubjson_value(size_and_type.second);
});
{
return get_ubjson_value(size_and_type.second);
});
}
}
else
{
Expand Down Expand Up @@ -1283,6 +1291,12 @@ class binary_reader

if (size_and_type.first != string_t::npos)
{
if (JSON_UNLIKELY(size_and_type.first > result.max_size()))
{
JSON_THROW(out_of_range::create(408,
"excessive object size: " + std::to_string(size_and_type.first)));
}

if (size_and_type.second != 0)
{
std::generate_n(std::inserter(*result.m_value.object,
Expand Down
21 changes: 18 additions & 3 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference
json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.
json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.
json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. |
json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |

@liveexample{The following code shows how an `out_of_range` exception can be
caught.,out_of_range}
Expand Down Expand Up @@ -6066,14 +6067,22 @@ class binary_reader

if (size_and_type.first != string_t::npos)
{
if (JSON_UNLIKELY(size_and_type.first > result.max_size()))
{
JSON_THROW(out_of_range::create(408,
"excessive array size: " + std::to_string(size_and_type.first)));
}

if (size_and_type.second != 0)
{
if (size_and_type.second != 'N')
{
std::generate_n(std::back_inserter(*result.m_value.array),
size_and_type.first, [this, size_and_type]()
{
return get_ubjson_value(size_and_type.second);
});
{
return get_ubjson_value(size_and_type.second);
});
}
}
else
{
Expand Down Expand Up @@ -6103,6 +6112,12 @@ class binary_reader

if (size_and_type.first != string_t::npos)
{
if (JSON_UNLIKELY(size_and_type.first > result.max_size()))
{
JSON_THROW(out_of_range::create(408,
"excessive object size: " + std::to_string(size_and_type.first)));
}

if (size_and_type.second != 0)
{
std::generate_n(std::inserter(*result.m_value.object,
Expand Down
4 changes: 4 additions & 0 deletions test/src/fuzzer-parse_ubjson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
// type errors can occur during parsing, too
}
catch (const json::out_of_range&)
{
// out of range errors may happen if provided sizes are excessive
}

// return 0 - non-zero return values are reserved for future use
return 0;
Expand Down
13 changes: 13 additions & 0 deletions test/src/unit-regression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1423,4 +1423,17 @@ TEST_CASE("regression tests")
json j = json::from_cbor(v_cbor);
CHECK(j == "abcd123");
}

SECTION("issue #962 - Timeout (OSS-Fuzz 6034)")
{
std::vector<uint8_t> v_ubjson = {0x5b, 0x24, 0x5a, 0x23, 0x4c, 0x78, 0x28, 0x00, 0x68, 0x28, 0x69, 0x69, 0x17};
CHECK_THROWS_AS(json::from_ubjson(v_ubjson), json::out_of_range&);
CHECK_THROWS_WITH(json::from_ubjson(v_ubjson),
"[json.exception.out_of_range.408] excessive array size: 8658170730974374167");

v_ubjson[0] = '{';
CHECK_THROWS_AS(json::from_ubjson(v_ubjson), json::out_of_range&);
CHECK_THROWS_WITH(json::from_ubjson(v_ubjson),
"[json.exception.out_of_range.408] excessive object size: 8658170730974374167");
}
}

0 comments on commit 33a9b00

Please sign in to comment.