summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2022-01-31 03:27:42 +0100
committerGravatar Nikias Bassen2022-01-31 03:27:42 +0100
commit8ea84caa3cba801c4f240648a6b7919e9b3e0b0d (patch)
tree3ec89ca7e0ed28ead0c76e8e9abc46fae0c6dbfc
parent7ddb1bd9e1d8bba58295d2e7e4872bcc6386968c (diff)
downloadlibplist-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.c10
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));