diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/jplist.c | 23 | ||||
| -rw-r--r-- | src/jsmn.c | 43 | ||||
| -rw-r--r-- | src/jsmn.h | 18 | ||||
| -rw-r--r-- | src/plist.c | 21 |
4 files changed, 77 insertions, 28 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; } @@ -3,6 +3,8 @@ * Simple JSON parser * * Copyright (c) 2010 Serge A. Zaitsev + * Updated to use size_t for token offsets and harden against overflows. + * (Nikias Bassen, January 2026) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,20 +26,25 @@ */ #include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include <assert.h> #include "jsmn.h" +#define JSMN_POS_INVALID ((size_t)SIZE_MAX) + /** * Allocates a fresh unused token from the token pull. */ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, - jsmntok_t *tokens, int num_tokens) { + jsmntok_t *tokens, unsigned int num_tokens) { jsmntok_t *tok; - if (parser->toknext >= num_tokens) { + if ((unsigned int)parser->toknext >= num_tokens) { return NULL; } tok = &tokens[parser->toknext++]; - tok->start = tok->end = -1; + tok->start = tok->end = JSMN_POS_INVALID; tok->size = 0; #ifdef JSMN_PARENT_LINKS tok->parent = -1; @@ -49,7 +56,7 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, * Fills token type and boundaries. */ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, - int start, int end) { + size_t start, size_t end) { token->type = type; token->start = start; token->end = end; @@ -60,9 +67,9 @@ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, * Fills next available token with JSON primitive. */ static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, - jsmntok_t *tokens, int num_tokens) { + jsmntok_t *tokens, unsigned int num_tokens) { jsmntok_t *token; - int start; + size_t start; start = parser->pos; @@ -107,10 +114,10 @@ found: * Fills next token with JSON string. */ static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, - jsmntok_t *tokens, int num_tokens) { + jsmntok_t *tokens, unsigned int num_tokens) { jsmntok_t *token; - int start = parser->pos; + size_t start = parser->pos; parser->pos++; @@ -162,7 +169,7 @@ static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, /** * Parse JSON string and fill tokens. */ -jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, jsmntok_t *tokens, +jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t length, jsmntok_t *tokens, unsigned int num_tokens) { jsmnerr_t r; int i; @@ -170,6 +177,13 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j parser->end = length; + if (num_tokens >= INT_MAX) { + return JSMN_ERROR_LIMIT; + } + if (length > SIZE_MAX / 2) { + return JSMN_ERROR_LIMIT; + } + for (; (parser->end > 0 && parser->pos < parser->end) && js[parser->pos] != '\0'; parser->pos++) { char c; jsmntype_t type; @@ -198,10 +212,13 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j } token = &tokens[parser->toknext - 1]; for (;;) { - if (token->start != -1 && token->end == -1) { + if (token->start != JSMN_POS_INVALID && token->end == JSMN_POS_INVALID) { if (token->type != type) { return JSMN_ERROR_INVAL; } + if (parser->pos == SIZE_MAX) { + return JSMN_ERROR_INVAL; + } token->end = parser->pos + 1; parser->toksuper = token->parent; break; @@ -214,7 +231,7 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j #else for (i = parser->toknext - 1; i >= 0; i--) { token = &tokens[i]; - if (token->start != -1 && token->end == -1) { + if (token->start != JSMN_POS_INVALID && token->end == JSMN_POS_INVALID) { if (token->type != type) { return JSMN_ERROR_INVAL; } @@ -227,7 +244,7 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j if (i == -1) return JSMN_ERROR_INVAL; for (; i >= 0; i--) { token = &tokens[i]; - if (token->start != -1 && token->end == -1) { + if (token->start != JSMN_POS_INVALID && token->end == JSMN_POS_INVALID) { parser->toksuper = i; break; } @@ -268,7 +285,7 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j for (i = parser->toknext - 1; i >= 0; i--) { /* Unmatched opened object or array */ - if (tokens[i].start != -1 && tokens[i].end == -1) { + if (tokens[i].start != JSMN_POS_INVALID && tokens[i].end == JSMN_POS_INVALID) { return JSMN_ERROR_PART; } } @@ -3,6 +3,8 @@ * Simple JSON parser (header file) * * Copyright (c) 2010 Serge A. Zaitsev + * Updated to use size_t for token offsets and harden against overflows. + * (Nikias Bassen, January 2026) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +27,8 @@ #ifndef __JSMN_H_ #define __JSMN_H_ +#include <stddef.h> + /** * JSON type identifier. Basic types are: * o Object @@ -46,6 +50,8 @@ typedef enum { JSMN_ERROR_INVAL = -2, /* The string is not a full JSON packet, more bytes expected */ JSMN_ERROR_PART = -3, + /* Input exceeds implementation-defined limits */ + JSMN_ERROR_LIMIT = -4, /* Everything was fine */ JSMN_SUCCESS = 0 } jsmnerr_t; @@ -58,9 +64,9 @@ typedef enum { */ typedef struct { jsmntype_t type; - int start; - int end; - int size; + size_t start; + size_t end; + size_t size; #ifdef JSMN_PARENT_LINKS int parent; #endif @@ -71,8 +77,8 @@ typedef struct { * the string being parsed now and current position in that string */ typedef struct { - unsigned int pos; /* offset in the JSON string */ - unsigned int end; /* offset after last character of JSON string */ + size_t pos; /* offset in the JSON string */ + size_t end; /* offset after last character of JSON string */ int toknext; /* next token to allocate */ int toksuper; /* superior token node, e.g parent object or array */ } jsmn_parser; @@ -86,7 +92,7 @@ void jsmn_init(jsmn_parser *parser); * Run JSON parser. It parses a JSON data string into and array of tokens, each describing * a single JSON object. */ -jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, +jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t length, jsmntok_t *tokens, unsigned int num_tokens); #endif /* __JSMN_H_ */ diff --git a/src/plist.c b/src/plist.c index 9a488bb..6197e3d 100644 --- a/src/plist.c +++ b/src/plist.c @@ -581,12 +581,27 @@ static plist_t plist_copy_node(node_t node) node_type = plist_get_node_type(node); switch (node_type) { case PLIST_DATA: - newdata->buff = (uint8_t *) malloc(data->length); - memcpy(newdata->buff, data->buff, data->length); + if (data->buff) { + newdata->buff = (uint8_t *) malloc(data->length); + assert(newdata->buff); + memcpy(newdata->buff, data->buff, data->length); + } else { + newdata->buff = NULL; + newdata->length = 0; + } break; case PLIST_KEY: case PLIST_STRING: - newdata->strval = strdup(data->strval); + if (data->strval) { + size_t n = strlen(data->strval) + 1; + newdata->strval = (char*)malloc(n); + assert(newdata->strval); + memcpy(newdata->strval, data->strval, n); + newdata->length = (uint64_t)n; + } else { + newdata->strval = NULL; + newdata->length = 0; + } break; case PLIST_ARRAY: if (data->hashtable) { |
