diff options
author | Nikias Bassen | 2022-02-07 01:12:58 +0100 |
---|---|---|
committer | Nikias Bassen | 2022-02-07 01:12:58 +0100 |
commit | a5316629a34ec5e1cd0cf76b4cb1625c5a6f3f88 (patch) | |
tree | 6df952a29aa05a1730c3306fe6022c07c6a9f84e | |
parent | 7bc4d2f14e5a0bb80fd7342f954554947b9fee01 (diff) | |
download | libplist-a5316629a34ec5e1cd0cf76b4cb1625c5a6f3f88.tar.gz libplist-a5316629a34ec5e1cd0cf76b4cb1625c5a6f3f88.tar.bz2 |
jplist: Prevent integer overflow when parsing numerical values
Credit to OSS-Fuzz
-rw-r--r-- | src/jplist.c | 35 |
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) |