fix(cbor): reject overflowing negative integers#5039
fix(cbor): reject overflowing negative integers#5039nlohmann merged 3 commits intonlohmann:developfrom
Conversation
🔴 Amalgamation check failed! 🔴The source code has not been amalgamated. @thevilledev |
a17996e to
47d033b
Compare
47d033b to
aeff909
Compare
|
It would be great to have a second opinion here. @gregmarr |
gregmarr
left a comment
There was a problem hiding this comment.
I'm unsure that the tests are testing what they should be. It should be testing getting a result of int64 max, and getting a result of int64 max + 1 failing, but it looks like it's testing putting the bit patterns for those values in the CBOR data and then checking for the results from those bit patterns.
I should be sleeping now, maybe it will make more sense tomorrow.
So the tests are specifically for CBOR type
I ran the tests against For positive integers (type But of course welcome to other ideas how to test this. I guess we could check that there's no sign flip, i.e. negative results are never positive? |
|
Like I said, don't review code when you should be sleeping. :) I mostly deal with floating point, where "min" refers to the smallest possible positive number, rather than integers, where it refers to the negative number with the largest magnitude, so I often mix up the integer min unless I really stop and think about it, and I was definitely not doing that properly. I agree that we should be testing |
|
np, no worries! I clarified the tests a bit, hopefully covering the boundaries fully now. Let me know what you think 👍 |
|
Quick question: don't we have the same situation with int32 overflow? #include <nlohmann/json.hpp>
#include <iostream>
using json = nlohmann::json;
int main() {
const std::vector<uint8_t> input = {0x3A, 0x80, 0x00, 0x00, 0x00};
auto j = json::from_cbor(input);
std::cout << j << '\n';
}Instead of printing |
|
I gotta say I totally missed the Thanks for pointing this out! |
|
Come to think of it, I think adding a check also for the other types would be consequent. |
|
Sure, I'll add those while at it |
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 <[email protected]>
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 <[email protected]>
c3f4e5b to
7d335c0
Compare
7d335c0 to
fd60a2a
Compare
|
Hmm, tests failing only on Windows clang-cl-12 (x64) failing due to:
The new boundary checks introduce switch-case-local variables (number, max_val). Since Is this test flaky in general? Or should we try breaking the logic down to a helper function? I'm not sure if this would get inlined though: |
Oh no!
That's not good...
No, the test was not flaky so far. |
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 <[email protected]>
fd60a2a to
482de87
Compare
|
Looks like it's fixed now 👍 |
Thanks! This is much cleaner now! |
Motivation
CBOR encodes negative integers as "-1 - n" where n is an unsigned integer. Per RFC 8949 Section 5.5:
and:
When n exceeds the representable range of
number_integer_t, the computation causes undefined behaviour and silent data corruption.For the default
int64_ttype:n = 0x8000000000000000) was incorrectly parsed as 9223372036854775807For custom 32-bit configurations (
int32_t):n = 0x80000000) would similarly overflowChanges
Add bounds checks for all CBOR negative integer types (
0x38,0x39,0x3A,0x3B) to reject values exceedingnumber_integer_trange, returningparse_error.112instead of silently corrupting data.Add regression tests for:
Overflow detection at boundary values
Truncated input handling
Custom
int32_tinteger type configurationsThe changes are described in detail, both the what and why.
If applicable, an existing issue is referenced.
The Code coverage remained at 100%. A test case for every new line of code.
If applicable, the documentation is updated.
The source code is amalgamated by running
make amalgamate.