diff options
| author | 2026-01-21 12:24:52 +0100 | |
|---|---|---|
| committer | 2026-01-21 12:26:13 +0100 | |
| commit | c0f9df912d2a4001e56321fb53615e6474b32232 (patch) | |
| tree | ce3d46fa9ac9e173d2f86451037d1456205c067f /src/jplist.c | |
| parent | c18d6b323e8121c041e8b88d2ea6b6e85ca41274 (diff) | |
| download | libplist-c0f9df912d2a4001e56321fb53615e6474b32232.tar.gz libplist-c0f9df912d2a4001e56321fb53615e6474b32232.tar.bz2 | |
jsmn: use size_t for token offsets and harden against overflow
Use size_t for token start/end offsets instead of int, replace the -1
sentinel with SIZE_MAX, and add a defensive guard against offset
wraparound. This prevents overflow when parsing very large JSON inputs.
This addresses issue #282.
Credit to @ylwango613 for repporting.
Diffstat (limited to 'src/jplist.c')
| -rw-r--r-- | src/jplist.c | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/src/jplist.c b/src/jplist.c index 9a40844..2c88756 100644 --- a/src/jplist.c +++ b/src/jplist.c @@ -719,8 +719,8 @@ static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index, uint3 return NULL; } plist_t arr = plist_new_array(); - int num_tokens = ti->tokens[*index].size; - int num; + size_t num_tokens = ti->tokens[*index].size; + size_t num; int j = (*index)+1; for (num = 0; num < num_tokens; num++) { if (j >= ti->count) { @@ -770,8 +770,8 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index, uint ti->err = PLIST_ERR_MAX_NESTING; return NULL; } - int num_tokens = ti->tokens[*index].size; - int num; + size_t num_tokens = ti->tokens[*index].size; + size_t num; int j = (*index)+1; if (num_tokens % 2 != 0) { PLIST_JSON_ERR("%s: number of children must be even\n", __func__); @@ -844,14 +844,15 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist) jsmn_parser parser; jsmn_init(&parser); - int maxtoks = 256; - int curtoks = 0; + unsigned int maxtoks = 256; + unsigned int curtoks = 0; int r = 0; jsmntok_t *tokens = NULL; do { jsmntok_t* newtokens = (jsmntok_t*)realloc(tokens, sizeof(jsmntok_t)*maxtoks); if (!newtokens) { + free(tokens); PLIST_JSON_ERR("%s: Out of memory\n", __func__); return PLIST_ERR_NO_MEM; } @@ -861,8 +862,14 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist) r = jsmn_parse(&parser, json, length, tokens, maxtoks); if (r == JSMN_ERROR_NOMEM) { + if (maxtoks > (unsigned int)INT_MAX - 16) { + free(tokens); + return PLIST_ERR_NO_MEM; + } maxtoks+=16; continue; + } else if (r < 0) { + break; } } while (r == JSMN_ERROR_NOMEM); @@ -879,6 +886,10 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist) PLIST_JSON_ERR("%s: Incomplete JSON, more bytes expected\n", __func__); free(tokens); return PLIST_ERR_PARSE; + case JSMN_ERROR_LIMIT: + PLIST_JSON_ERR("%s: Input data too large\n", __func__); + free(tokens); + return PLIST_ERR_PARSE; default: break; } |
