summaryrefslogtreecommitdiffstats
path: root/src/jplist.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2022-02-07 01:12:58 +0100
committerGravatar Nikias Bassen2022-02-07 01:12:58 +0100
commita5316629a34ec5e1cd0cf76b4cb1625c5a6f3f88 (patch)
tree6df952a29aa05a1730c3306fe6022c07c6a9f84e /src/jplist.c
parent7bc4d2f14e5a0bb80fd7342f954554947b9fee01 (diff)
downloadlibplist-a5316629a34ec5e1cd0cf76b4cb1625c5a6f3f88.tar.gz
libplist-a5316629a34ec5e1cd0cf76b4cb1625c5a6f3f88.tar.bz2
jplist: Prevent integer overflow when parsing numerical values
Credit to OSS-Fuzz
Diffstat (limited to 'src/jplist.c')
-rw-r--r--src/jplist.c35
1 files changed, 29 insertions, 6 deletions
diff --git a/src/jplist.c b/src/jplist.c
index 7264da2..6c6e331 100644
--- a/src/jplist.c
+++ b/src/jplist.c
@@ -266,7 +266,7 @@ static int num_digits_i(int64_t i)
int64_t po10;
n=1;
if (i < 0) {
- i = -i;
+ i = (i == INT64_MIN) ? INT64_MAX : -i;
n++;
}
po10=10;
@@ -423,9 +423,10 @@ typedef struct {
int count;
} jsmntok_info_t;
-static long long parse_decimal(const char* str, const char* str_end, char** endp)
+static int64_t parse_decimal(const char* str, const char* str_end, char** endp)
{
- long long x = 0;
+ uint64_t MAX = INT64_MAX;
+ uint64_t x = 0;
int is_neg = 0;
*endp = (char*)str;
@@ -433,14 +434,36 @@ static long long parse_decimal(const char* str, const char* str_end, char** endp
is_neg = 1;
(*endp)++;
}
+ if (is_neg) {
+ MAX++;
+ }
while (*endp < str_end && isdigit(**endp)) {
- x = x * 10 + (**endp - '0');
+ if (x > PO10i_LIMIT) {
+ x = MAX;
+ break;
+ }
+ x = x * 10;
+ unsigned int add = (**endp - '0');
+ if (x + add > MAX) {
+ x = MAX;
+ break;
+ }
+ x += add;
(*endp)++;
}
+
+ // swallow the rest of the digits in case we dropped out early
+ while (*endp < str_end && isdigit(**endp)) (*endp)++;
+
+ int64_t result = x;
if (is_neg) {
- x = -x;
+ if (x == MAX) {
+ result = INT64_MIN;
+ } else {
+ result = -(int64_t)x;
+ }
}
- return x;
+ return result;
}
static plist_t parse_primitive(const char* js, jsmntok_info_t* ti, int* index)