]> granicus.if.org Git - json-c/commitdiff
Prevent truncation on custom double formatters.
authorTobias Stoeckmann <tobias@stoeckmann.org>
Sat, 16 May 2020 11:01:10 +0000 (13:01 +0200)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Sat, 16 May 2020 13:26:16 +0000 (15:26 +0200)
A custom double formatter can lead to truncation of the rest of the
JSON document.

If a custom formatter completely fills the buffer used by snprintf
with a trailing dot or comma and the formatting option
JSON_C_TO_STRING_NOZERO has been specified, then an iterator moves
past the ending '\0' (off-by-one buffer overflow) to set an
additional '\0' and adds the first '\0' into the printbuf.

Since '\0' will eventually be considered the terminating character
of the complete printbuf result, all trailing characters are lost.

This leads to an incomplete JSON string as can be seen with the
test case.

The off-by-one can be noticed if compiled with address sanitizer.

Since this is a very special case and a malformed formatter could
do way more harm and is the responsibility of the user of this
library, this is just a protective measure to keep json-c code as
robust as possible.

json_object.c
tests/test_set_serializer.c
tests/test_set_serializer.expected

index 04164d059e9e63c5c2a8f235c55fcdc8e3641bd2..c2463c10c11d9f2d4b794a5f4d6510a71ab78ace 100644 (file)
@@ -969,7 +969,8 @@ static int json_object_double_to_json_string_format(struct json_object *jso, str
                                        p = q;
                        }
                        /* drop trailing zeroes */
-                       *(++p) = 0;
+                       if (*p != 0)
+                               *(++p) = 0;
                        size = p - buf;
                }
        }
index db1c1876c7ae9bf321e8732bb2d3602938838b7f..b5c19791add5973b322f327ab7ba046ac493c7a2 100644 (file)
@@ -26,7 +26,7 @@ static int custom_serializer(struct json_object *o, struct printbuf *pb, int lev
 
 int main(int argc, char **argv)
 {
-       json_object *my_object;
+       json_object *my_object, *my_sub_object;
 
        MC_SET_DEBUG(1);
 
@@ -67,5 +67,17 @@ int main(int argc, char **argv)
        json_object_put(my_object);
        assert(freeit_was_called);
 
+       // ============================================
+
+       my_object = json_object_new_object();
+       my_sub_object = json_object_new_double(1.0);
+       json_object_object_add(my_object, "double", my_sub_object);
+       printf("Check that the custom serializer does not include nul byte:\n");
+       json_object_set_serializer(my_sub_object, json_object_double_to_json_string, "%125.0f,", NULL);
+       printf("my_object.to_string(custom serializer)=%s\n",
+              json_object_to_json_string_ext(my_object, JSON_C_TO_STRING_NOZERO));
+
+       json_object_put(my_object);
+
        return 0;
 }
index ad44a9053be6a701d1e4240994d228f8d4fcf06c..9629dd6e873856ecad5b157f8b6d100f5c88829d 100644 (file)
@@ -8,3 +8,5 @@ Check that the custom serializer isn't free'd until the last json_object_put:
 my_object.to_string(custom serializer)=Custom Output
 Next line of output should be from the custom freeit function:
 freeit, value=123
+Check that the custom serializer does not include nul byte:
+my_object.to_string(custom serializer)={"double":                                                                                                                            1.}