diff options
| author | 2022-01-31 03:27:42 +0100 | |
|---|---|---|
| committer | 2022-01-31 03:27:42 +0100 | |
| commit | 8ea84caa3cba801c4f240648a6b7919e9b3e0b0d (patch) | |
| tree | 3ec89ca7e0ed28ead0c76e8e9abc46fae0c6dbfc | |
| parent | 7ddb1bd9e1d8bba58295d2e7e4872bcc6386968c (diff) | |
| download | libplist-8ea84caa3cba801c4f240648a6b7919e9b3e0b0d.tar.gz libplist-8ea84caa3cba801c4f240648a6b7919e9b3e0b0d.tar.bz2 | |
jplist: Fix OOB read in parse_primitive caused by missing 0-termination
In parse_primitive, integer and double values are parsed by using strtoll
and atof, which both expect the string to be 0-terminated. While this is
not a problem in well-formed JSON files, it can be if the JSON data is not,
possibly leading to a crash due to OOB memory access.
This commit fixes it by copying the value data in question to a stack buffer
and 0-terminate it, and use that buffer instead.
Credit to OSS-Fuzz
| -rw-r--r-- | src/jplist.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/src/jplist.c b/src/jplist.c index 2182079..827b367 100644 --- a/src/jplist.c +++ b/src/jplist.c | |||
| @@ -443,7 +443,13 @@ static plist_t parse_primitive(const char* js, jsmntok_info_t* ti, int* index) | |||
| 443 | val = plist_new_node(data); | 443 | val = plist_new_node(data); |
| 444 | } else if (str_val[0] == '-' || isdigit(str_val[0])) { | 444 | } else if (str_val[0] == '-' || isdigit(str_val[0])) { |
| 445 | char* endp = NULL; | 445 | char* endp = NULL; |
| 446 | long long intpart = strtol(str_val, &endp, 10); | 446 | char cbuf[48]; |
| 447 | size_t maxlen = str_end-str_val; | ||
| 448 | if (maxlen >= sizeof(cbuf)) maxlen = sizeof(cbuf)-1; | ||
| 449 | strncpy(cbuf, str_val, maxlen); | ||
| 450 | cbuf[maxlen] = '\0'; | ||
| 451 | long long intpart = strtoll(cbuf, &endp, 10); | ||
| 452 | endp = (char*)str_val + (endp-&cbuf[0]); | ||
| 447 | if (endp >= str_end) { | 453 | if (endp >= str_end) { |
| 448 | /* integer */ | 454 | /* integer */ |
| 449 | val = plist_new_uint((uint64_t)intpart); | 455 | val = plist_new_uint((uint64_t)intpart); |
| @@ -452,7 +458,7 @@ static plist_t parse_primitive(const char* js, jsmntok_info_t* ti, int* index) | |||
| 452 | char* fendp = endp+1; | 458 | char* fendp = endp+1; |
| 453 | while (isdigit(*fendp) && fendp < str_end) fendp++; | 459 | while (isdigit(*fendp) && fendp < str_end) fendp++; |
| 454 | if ((fendp > endp+1 && fendp >= str_end) || (fendp+2 < str_end && (*fendp == 'e' || *fendp == 'E') && (*(fendp+1) == '+' || *(fendp+1) == '-') && isdigit(*(fendp+2)))) { | 460 | if ((fendp > endp+1 && fendp >= str_end) || (fendp+2 < str_end && (*fendp == 'e' || *fendp == 'E') && (*(fendp+1) == '+' || *(fendp+1) == '-') && isdigit(*(fendp+2)))) { |
| 455 | double dval = atof(str_val); | 461 | double dval = atof(cbuf); |
| 456 | val = plist_new_real(dval); | 462 | val = plist_new_real(dval); |
| 457 | } else { | 463 | } else { |
| 458 | PLIST_JSON_ERR("%s: invalid character at offset %d when parsing floating point value\n", __func__, (int)(fendp - js)); | 464 | PLIST_JSON_ERR("%s: invalid character at offset %d when parsing floating point value\n", __func__, (int)(fendp - js)); |
