diff options
author | Nikias Bassen | 2022-01-31 02:55:18 +0100 |
---|---|---|
committer | Nikias Bassen | 2022-01-31 02:55:18 +0100 |
commit | 924ba961d68f6833f617fd3ad03c40f63f287142 (patch) | |
tree | 140dd874ce171810c9fcc5cb98c3a071445aa717 /src | |
parent | 25f2f01c2693da8cc651d80debda9ad61fa17743 (diff) | |
download | libplist-924ba961d68f6833f617fd3ad03c40f63f287142.tar.gz libplist-924ba961d68f6833f617fd3ad03c40f63f287142.tar.bz2 |
jplist: Fix OOB read by making sure the JSMN token index is in valid range
Credit to OSS-Fuzz
Diffstat (limited to 'src')
-rw-r--r-- | src/jplist.c | 79 |
1 files changed, 48 insertions, 31 deletions
diff --git a/src/jplist.c b/src/jplist.c index 88cce28..2182079 100644 --- a/src/jplist.c +++ b/src/jplist.c @@ -418,16 +418,21 @@ PLIST_API int plist_to_json(plist_t plist, char **json, uint32_t* length, int pr return PLIST_ERR_SUCCESS; } -static plist_t parse_primitive(const char* js, jsmntok_t* tokens, int* index) +typedef struct { + jsmntok_t* tokens; + int count; +} jsmntok_info_t; + +static plist_t parse_primitive(const char* js, jsmntok_info_t* ti, int* index) { - if (tokens[*index].type != JSMN_PRIMITIVE) { + if (ti->tokens[*index].type != JSMN_PRIMITIVE) { PLIST_JSON_ERR("%s: token type != JSMN_PRIMITIVE\n", __func__); return NULL; } plist_t val = NULL; - const char* str_val = js + tokens[*index].start; - const char* str_end = js + tokens[*index].end; - size_t str_len = tokens[*index].end - tokens[*index].start; + const char* str_val = js + ti->tokens[*index].start; + const char* str_end = js + ti->tokens[*index].end; + size_t str_len = ti->tokens[*index].end - ti->tokens[*index].start; if (!strncmp("false", str_val, str_len)) { val = plist_new_bool(0); } else if (!strncmp("true", str_val, str_len)) { @@ -540,15 +545,15 @@ static char* unescape_string(const char* str_val, size_t str_len, size_t *new_le return strval; } -static plist_t parse_string(const char* js, jsmntok_t* tokens, int* index) +static plist_t parse_string(const char* js, jsmntok_info_t* ti, int* index) { - if (tokens[*index].type != JSMN_STRING) { + if (ti->tokens[*index].type != JSMN_STRING) { PLIST_JSON_ERR("%s: token type != JSMN_STRING\n", __func__); return NULL; } size_t str_len = 0; ; - char* strval = unescape_string(js + tokens[*index].start, tokens[*index].end - tokens[*index].start, &str_len); + char* strval = unescape_string(js + ti->tokens[*index].start, ti->tokens[*index].end - ti->tokens[*index].start, &str_len); if (!strval) { return NULL; } @@ -564,32 +569,36 @@ static plist_t parse_string(const char* js, jsmntok_t* tokens, int* index) return node; } -static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index); +static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index); -static plist_t parse_array(const char* js, jsmntok_t* tokens, int* index) +static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index) { - if (tokens[*index].type != JSMN_ARRAY) { + if (ti->tokens[*index].type != JSMN_ARRAY) { PLIST_JSON_ERR("%s: token type != JSMN_ARRAY\n", __func__); return NULL; } plist_t arr = plist_new_array(); - int num_tokens = tokens[*index].size; + int num_tokens = ti->tokens[*index].size; int num; int j = (*index)+1; for (num = 0; num < num_tokens; num++) { + if (j >= ti->count) { + PLIST_JSON_ERR("%s: token index out of valid range\n", __func__); + return NULL; + } plist_t val = NULL; - switch (tokens[j].type) { + switch (ti->tokens[j].type) { case JSMN_OBJECT: - val = parse_object(js, tokens, &j); + val = parse_object(js, ti, &j); break; case JSMN_ARRAY: - val = parse_array(js, tokens, &j); + val = parse_array(js, ti, &j); break; case JSMN_STRING: - val = parse_string(js, tokens, &j); + val = parse_string(js, ti, &j); break; case JSMN_PRIMITIVE: - val = parse_primitive(js, tokens, &j); + val = parse_primitive(js, ti, &j); break; default: break; @@ -605,19 +614,23 @@ static plist_t parse_array(const char* js, jsmntok_t* tokens, int* index) return arr; } -static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index) +static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index) { - if (tokens[*index].type != JSMN_OBJECT) { + if (ti->tokens[*index].type != JSMN_OBJECT) { PLIST_JSON_ERR("%s: token type != JSMN_OBJECT\n", __func__); return NULL; } plist_t obj = plist_new_dict(); - int num_tokens = tokens[*index].size; + int num_tokens = ti->tokens[*index].size; int num; int j = (*index)+1; for (num = 0; num < num_tokens; num++) { - if (tokens[j].type == JSMN_STRING) { - char* key = unescape_string(js + tokens[j].start, tokens[j].end - tokens[j].start, NULL); + if (j >= ti->count) { + PLIST_JSON_ERR("%s: token index out of valid range\n", __func__); + return NULL; + } + if (ti->tokens[j].type == JSMN_STRING) { + char* key = unescape_string(js + ti->tokens[j].start, ti->tokens[j].end - ti->tokens[j].start, NULL); if (!key) { plist_free(obj); return NULL; @@ -625,24 +638,27 @@ static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index) plist_t val = NULL; j++; num++; - switch (tokens[j].type) { + switch (ti->tokens[j].type) { case JSMN_OBJECT: - val = parse_object(js, tokens, &j); + val = parse_object(js, ti, &j); break; case JSMN_ARRAY: - val = parse_array(js, tokens, &j); + val = parse_array(js, ti, &j); break; case JSMN_STRING: - val = parse_string(js, tokens, &j); + val = parse_string(js, ti, &j); break; case JSMN_PRIMITIVE: - val = parse_primitive(js, tokens, &j); + val = parse_primitive(js, ti, &j); break; default: break; } if (val) { plist_dict_set_item(obj, key, val); + } else { + plist_free(obj); + return NULL; } free(key); } else { @@ -707,18 +723,19 @@ PLIST_API int plist_from_json(const char *json, uint32_t length, plist_t * plist } int startindex = 0; + jsmntok_info_t ti = { tokens, parser.toknext }; switch (tokens[startindex].type) { case JSMN_PRIMITIVE: - *plist = parse_primitive(json, tokens, &startindex); + *plist = parse_primitive(json, &ti, &startindex); break; case JSMN_STRING: - *plist = parse_string(json, tokens, &startindex); + *plist = parse_string(json, &ti, &startindex); break; case JSMN_ARRAY: - *plist = parse_array(json, tokens, &startindex); + *plist = parse_array(json, &ti, &startindex); break; case JSMN_OBJECT: - *plist = parse_object(json, tokens, &startindex); + *plist = parse_object(json, &ti, &startindex); break; default: break; |