json_tokener_parse_ex: handle out of memory errors

Do not silently truncate values or skip entries if out of memory errors
occur.

Proof of Concept:

- Create poc.c, a program which creates an eight megabyte large json
  object with key "A" and a lot of "B"s as value, one of them is
  UTF-formatted:

```c
 #include <err.h>
 #include <stdio.h>
 #include <string.h>

 #include "json.h"

 #define STR_LEN (8 * 1024 * 1024)
 #define STR_PREFIX "{ \"A\": \""
 #define STR_SUFFIX "\\u0042\" }"

int main(void) {
  char *str;
  struct json_tokener *tok;
  struct json_object *obj;

  if ((tok = json_tokener_new()) == NULL)
    errx(1, "json_tokener_new");

  if ((str = malloc(STR_LEN)) == NULL)
    err(1, "malloc");
  memset(str, 'B', STR_LEN);
  memcpy(str, STR_PREFIX, sizeof(STR_PREFIX) - 1);
  memcpy(str + STR_LEN - sizeof(STR_SUFFIX), STR_SUFFIX, sizeof(STR_SUFFIX));

  obj = json_tokener_parse(str);
  free(str);

  printf("%p\n", obj);
  if (obj != NULL) {
    printf("%.*s\n", 50, json_object_to_json_string(obj));
    json_object_put(obj);
  }

  json_tokener_free(tok);
  return 0;
}
```
- Compile and run poc, assuming you have enough free heap space:
```
gcc $(pkg-config --cflags --libs) -o poc poc.c
./poc
0x559421e15de0
{ "A": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
```
- Reduce available heap and run again, which leads to truncation:
```
ulimit -d 10000
./poc
0x555a5b453de0
{ "A": "B" }
```
- Compile json-c with this change and run with reduced heap again:
```
ulimit -d 10000
./poc
(nil)
```

The output is limited to 70 characters, i.e. json-c parses the 8 MB
string correctly but the poc does not print all of them to the screen.

The truncation occurs because the parser tries to add all chars up
to the UTF-8 formatted 'B' at once. Since memory is limited to 10 MB
there is not enough for this operation. The parser does not fail but
continues normally.

Another possibility is to create a json file close to 2 GB and run a
program on a system with limited amount of RAM, i.e. around 3 GB. But
ulimit restrictions are much easier for proof of concepts.

Treat memory errors correctly and abort operations.
This commit is contained in:
Tobias Stoeckmann
2022-03-20 17:22:07 +01:00
parent 79459b2de2
commit 9e6acc9a4e
2 changed files with 103 additions and 43 deletions

View File

@@ -28,6 +28,7 @@ enum json_tokener_error
json_tokener_success,
json_tokener_continue,
json_tokener_error_depth,
json_tokener_error_memory,
json_tokener_error_parse_eof,
json_tokener_error_parse_unexpected,
json_tokener_error_parse_null,