When value_to_pretty is called with recursionsLeft=0 and an Array or Map
type, container_to_pretty is called with recursionsLeft - 1 = -1. This
breaks the recursion limit check.
In practice, this can be triggered with a CBOR data containing 1023
Arrays, a Tag and many more Arrays:
$ python3 -c 'import sys;sys.stdout.buffer.write(b"\x9f" * 1023 + b"\xc0\x9f" + b"\x9f" * 100000 + b"\xff" * 101024)' | ./bin/cbordump
Segmentation fault (core dumped)
This segmentation fault is due to the stack growing too much, due to the
quantity of recursive calls.
Fix this by reporting a proper error when recursionsLeft <= 0, instead
of when recursionsLeft == 0. The same input now produces:
[_ [_ [_ ... [_ 0([
-: internal error: too many nested containers found in recursive function
_ <nesting too deep, recursion stopped>
Moreover, using fewer nested arrays works fine:
$ python3 -c 'import sys;sys.stdout.buffer.write(b"\x9f" * 1023 + b"\xc0\x9f" + b"\x9f" * 1024 + b"\xff" * 2048)' |./bin/cbordump
[_ [_ [_ ... [_ 0([_ <nesting too deep, recursion stopped>])] ... ]]]
Also modify the test when formatting CborTagType to ensure
value_to_pretty is never called with a negative recursionsLeft.
When printing CBOR data containing NaN, function convertToUint64 does an
undefined behavior. This can be reproduced using test cases from
tests/parser/data.cpp:
$ make CC='clang -fsanitize=undefined'
$ printf "\xfb\x7f\xf8\0\0\0\0\0\0" | ./bin/cbordump
src/cborpretty.c:171:17: runtime error: nan is outside the range of
representable values of type 'unsigned long'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/cborpretty.c:171:17 in
nan
$ printf "\xf9\x7e\x00" | ./bin/cbordump
src/cborpretty.c:171:17: runtime error: nan is outside the range of
representable values of type 'unsigned long'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/cborpretty.c:171:17 in
nan
Fix this by checking whether the value to convert is not NaN.
When function text_string_to_escaped successfully parses a string and
fails to parse the next value (cbor_value_finish_string_iteration
returns an error), it correctly propagates the error but the string is
never freed.
This can be reproduced with:
make CC='clang -g -fsanitize=address'
printf '\x82\x60\xff' | ./bin/cbordump -j
clang's Address Sanitizer reports:
=================================================================
==20317==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 1 byte(s) in 1 object(s) allocated from:
#0 0x560b654b9916 in __interceptor_realloc (/tinycbor/bin/cbordump+0xa4916) (BuildId: f9933666b5d987b21f68c2887de4aebe93bc2bef)
#1 0x560b654f5c18 in escape_text_string /tinycbor/src/cbortojson.c:331:15
#2 0x560b654f3e29 in text_string_to_escaped /tinycbor/src/cbortojson.c:377:19
#3 0x560b654f267d in value_to_json /tinycbor/src/cbortojson.c:674:19
#4 0x560b654f34c2 in array_to_json /tinycbor/src/cbortojson.c:545:25
#5 0x560b654f2085 in value_to_json /tinycbor/src/cbortojson.c:627:19
#6 0x560b654f1baf in cbor_value_to_json_advance /tinycbor/src/cbortojson.c:816:12
#7 0x560b654ea928 in dumpFile /tinycbor/tools/cbordump/cbordump.c:76:19
#8 0x560b654ead2b in main /tinycbor/tools/cbordump/cbordump.c:149:9
#9 0x7fa9d7629d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: 1 byte(s) leaked in 1 allocation(s).
Fix this by freeing the string when cbor_value_finish_string_iteration
fails.
Fixes: e072bc1d78 ("CBOR-to-JSON: do properly escape JSON strings")