From c0f9df912d2a4001e56321fb53615e6474b32232 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 21 Jan 2026 12:24:52 +0100 Subject: 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. --- src/jplist.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'src/jplist.c') 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; } -- cgit v1.1-32-gdbae