Pretty: ensure recursionsLeft is not zero before decrementing it

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.
This commit is contained in:
Nicolas Iooss
2025-03-18 10:49:39 -07:00
committed by Thiago Macieira
parent f96502575f
commit 4682eaa1e0
+5 -2
View File
@@ -308,7 +308,7 @@ static CborError container_to_pretty(CborStreamFunction stream, void *out, CborV
const char *comma = "";
CborError err = CborNoError;
if (!recursionsLeft) {
if (recursionsLeft <= 0) {
printRecursionLimit(stream, out);
while (!cbor_value_at_end(it) && !err) {
err = cbor_value_advance(it);
@@ -356,6 +356,9 @@ static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue
copy_current_position(it, &recursed);
return err; /* parse error */
}
/* N.B. recursionsLeft can be zero, in which case container_to_pretty is called with
* recursionsLeft = -1 and reports that nesting is too deep.
*/
err = container_to_pretty(stream, out, &recursed, type, flags, recursionsLeft - 1);
if (err) {
copy_current_position(it, &recursed);
@@ -452,7 +455,7 @@ static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue
err = stream(out, "%" PRIu64 "%s(", tag, get_indicator(it, flags));
if (!err)
err = cbor_value_advance_fixed(it);
if (!err && recursionsLeft)
if (!err && recursionsLeft > 0)
err = value_to_pretty(stream, out, it, flags, recursionsLeft - 1);
else if (!err)
printRecursionLimit(stream, out);