summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2022-01-31 02:55:18 +0100
committerGravatar Nikias Bassen2022-01-31 02:55:18 +0100
commit924ba961d68f6833f617fd3ad03c40f63f287142 (patch)
tree140dd874ce171810c9fcc5cb98c3a071445aa717
parent25f2f01c2693da8cc651d80debda9ad61fa17743 (diff)
downloadlibplist-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
-rw-r--r--src/jplist.c79
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;