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 |
3 files changed, 59 insertions, 25 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 | |||
| 719 | return NULL; | 719 | return NULL; |
| 720 | } | 720 | } |
| 721 | plist_t arr = plist_new_array(); | 721 | plist_t arr = plist_new_array(); |
| 722 | int num_tokens = ti->tokens[*index].size; | 722 | size_t num_tokens = ti->tokens[*index].size; |
| 723 | int num; | 723 | size_t num; |
| 724 | int j = (*index)+1; | 724 | int j = (*index)+1; |
| 725 | for (num = 0; num < num_tokens; num++) { | 725 | for (num = 0; num < num_tokens; num++) { |
| 726 | if (j >= ti->count) { | 726 | if (j >= ti->count) { |
| @@ -770,8 +770,8 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index, uint | |||
| 770 | ti->err = PLIST_ERR_MAX_NESTING; | 770 | ti->err = PLIST_ERR_MAX_NESTING; |
| 771 | return NULL; | 771 | return NULL; |
| 772 | } | 772 | } |
| 773 | int num_tokens = ti->tokens[*index].size; | 773 | size_t num_tokens = ti->tokens[*index].size; |
| 774 | int num; | 774 | size_t num; |
| 775 | int j = (*index)+1; | 775 | int j = (*index)+1; |
| 776 | if (num_tokens % 2 != 0) { | 776 | if (num_tokens % 2 != 0) { |
| 777 | PLIST_JSON_ERR("%s: number of children must be even\n", __func__); | 777 | 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) | |||
| 844 | 844 | ||
| 845 | jsmn_parser parser; | 845 | jsmn_parser parser; |
| 846 | jsmn_init(&parser); | 846 | jsmn_init(&parser); |
| 847 | int maxtoks = 256; | 847 | unsigned int maxtoks = 256; |
| 848 | int curtoks = 0; | 848 | unsigned int curtoks = 0; |
| 849 | int r = 0; | 849 | int r = 0; |
| 850 | jsmntok_t *tokens = NULL; | 850 | jsmntok_t *tokens = NULL; |
| 851 | 851 | ||
| 852 | do { | 852 | do { |
| 853 | jsmntok_t* newtokens = (jsmntok_t*)realloc(tokens, sizeof(jsmntok_t)*maxtoks); | 853 | jsmntok_t* newtokens = (jsmntok_t*)realloc(tokens, sizeof(jsmntok_t)*maxtoks); |
| 854 | if (!newtokens) { | 854 | if (!newtokens) { |
| 855 | free(tokens); | ||
| 855 | PLIST_JSON_ERR("%s: Out of memory\n", __func__); | 856 | PLIST_JSON_ERR("%s: Out of memory\n", __func__); |
| 856 | return PLIST_ERR_NO_MEM; | 857 | return PLIST_ERR_NO_MEM; |
| 857 | } | 858 | } |
| @@ -861,8 +862,14 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist) | |||
| 861 | 862 | ||
| 862 | r = jsmn_parse(&parser, json, length, tokens, maxtoks); | 863 | r = jsmn_parse(&parser, json, length, tokens, maxtoks); |
| 863 | if (r == JSMN_ERROR_NOMEM) { | 864 | if (r == JSMN_ERROR_NOMEM) { |
| 865 | if (maxtoks > (unsigned int)INT_MAX - 16) { | ||
| 866 | free(tokens); | ||
| 867 | return PLIST_ERR_NO_MEM; | ||
| 868 | } | ||
| 864 | maxtoks+=16; | 869 | maxtoks+=16; |
| 865 | continue; | 870 | continue; |
| 871 | } else if (r < 0) { | ||
| 872 | break; | ||
| 866 | } | 873 | } |
| 867 | } while (r == JSMN_ERROR_NOMEM); | 874 | } while (r == JSMN_ERROR_NOMEM); |
| 868 | 875 | ||
| @@ -879,6 +886,10 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist) | |||
| 879 | PLIST_JSON_ERR("%s: Incomplete JSON, more bytes expected\n", __func__); | 886 | PLIST_JSON_ERR("%s: Incomplete JSON, more bytes expected\n", __func__); |
| 880 | free(tokens); | 887 | free(tokens); |
| 881 | return PLIST_ERR_PARSE; | 888 | return PLIST_ERR_PARSE; |
| 889 | case JSMN_ERROR_LIMIT: | ||
| 890 | PLIST_JSON_ERR("%s: Input data too large\n", __func__); | ||
| 891 | free(tokens); | ||
| 892 | return PLIST_ERR_PARSE; | ||
| 882 | default: | 893 | default: |
| 883 | break; | 894 | break; |
| 884 | } | 895 | } |
| @@ -3,6 +3,8 @@ | |||
| 3 | * Simple JSON parser | 3 | * Simple JSON parser |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2010 Serge A. Zaitsev | 5 | * Copyright (c) 2010 Serge A. Zaitsev |
| 6 | * Updated to use size_t for token offsets and harden against overflows. | ||
| 7 | * (Nikias Bassen, January 2026) | ||
| 6 | * | 8 | * |
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 8 | * of this software and associated documentation files (the "Software"), to deal | 10 | * of this software and associated documentation files (the "Software"), to deal |
| @@ -24,20 +26,25 @@ | |||
| 24 | */ | 26 | */ |
| 25 | 27 | ||
| 26 | #include <stdlib.h> | 28 | #include <stdlib.h> |
| 29 | #include <stdint.h> | ||
| 30 | #include <limits.h> | ||
| 31 | #include <assert.h> | ||
| 27 | 32 | ||
| 28 | #include "jsmn.h" | 33 | #include "jsmn.h" |
| 29 | 34 | ||
| 35 | #define JSMN_POS_INVALID ((size_t)SIZE_MAX) | ||
| 36 | |||
| 30 | /** | 37 | /** |
| 31 | * Allocates a fresh unused token from the token pull. | 38 | * Allocates a fresh unused token from the token pull. |
| 32 | */ | 39 | */ |
| 33 | static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, | 40 | static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, |
| 34 | jsmntok_t *tokens, int num_tokens) { | 41 | jsmntok_t *tokens, unsigned int num_tokens) { |
| 35 | jsmntok_t *tok; | 42 | jsmntok_t *tok; |
| 36 | if (parser->toknext >= num_tokens) { | 43 | if ((unsigned int)parser->toknext >= num_tokens) { |
| 37 | return NULL; | 44 | return NULL; |
| 38 | } | 45 | } |
| 39 | tok = &tokens[parser->toknext++]; | 46 | tok = &tokens[parser->toknext++]; |
| 40 | tok->start = tok->end = -1; | 47 | tok->start = tok->end = JSMN_POS_INVALID; |
| 41 | tok->size = 0; | 48 | tok->size = 0; |
| 42 | #ifdef JSMN_PARENT_LINKS | 49 | #ifdef JSMN_PARENT_LINKS |
| 43 | tok->parent = -1; | 50 | tok->parent = -1; |
| @@ -49,7 +56,7 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, | |||
| 49 | * Fills token type and boundaries. | 56 | * Fills token type and boundaries. |
| 50 | */ | 57 | */ |
| 51 | static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, | 58 | static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, |
| 52 | int start, int end) { | 59 | size_t start, size_t end) { |
| 53 | token->type = type; | 60 | token->type = type; |
| 54 | token->start = start; | 61 | token->start = start; |
| 55 | token->end = end; | 62 | token->end = end; |
| @@ -60,9 +67,9 @@ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, | |||
| 60 | * Fills next available token with JSON primitive. | 67 | * Fills next available token with JSON primitive. |
| 61 | */ | 68 | */ |
| 62 | static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, | 69 | static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, |
| 63 | jsmntok_t *tokens, int num_tokens) { | 70 | jsmntok_t *tokens, unsigned int num_tokens) { |
| 64 | jsmntok_t *token; | 71 | jsmntok_t *token; |
| 65 | int start; | 72 | size_t start; |
| 66 | 73 | ||
| 67 | start = parser->pos; | 74 | start = parser->pos; |
| 68 | 75 | ||
| @@ -107,10 +114,10 @@ found: | |||
| 107 | * Fills next token with JSON string. | 114 | * Fills next token with JSON string. |
| 108 | */ | 115 | */ |
| 109 | static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, | 116 | static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, |
| 110 | jsmntok_t *tokens, int num_tokens) { | 117 | jsmntok_t *tokens, unsigned int num_tokens) { |
| 111 | jsmntok_t *token; | 118 | jsmntok_t *token; |
| 112 | 119 | ||
| 113 | int start = parser->pos; | 120 | size_t start = parser->pos; |
| 114 | 121 | ||
| 115 | parser->pos++; | 122 | parser->pos++; |
| 116 | 123 | ||
| @@ -162,7 +169,7 @@ static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, | |||
| 162 | /** | 169 | /** |
| 163 | * Parse JSON string and fill tokens. | 170 | * Parse JSON string and fill tokens. |
| 164 | */ | 171 | */ |
| 165 | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, jsmntok_t *tokens, | 172 | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t length, jsmntok_t *tokens, |
| 166 | unsigned int num_tokens) { | 173 | unsigned int num_tokens) { |
| 167 | jsmnerr_t r; | 174 | jsmnerr_t r; |
| 168 | int i; | 175 | int i; |
| @@ -170,6 +177,13 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j | |||
| 170 | 177 | ||
| 171 | parser->end = length; | 178 | parser->end = length; |
| 172 | 179 | ||
| 180 | if (num_tokens >= INT_MAX) { | ||
| 181 | return JSMN_ERROR_LIMIT; | ||
| 182 | } | ||
| 183 | if (length > SIZE_MAX / 2) { | ||
| 184 | return JSMN_ERROR_LIMIT; | ||
| 185 | } | ||
| 186 | |||
| 173 | for (; (parser->end > 0 && parser->pos < parser->end) && js[parser->pos] != '\0'; parser->pos++) { | 187 | for (; (parser->end > 0 && parser->pos < parser->end) && js[parser->pos] != '\0'; parser->pos++) { |
| 174 | char c; | 188 | char c; |
| 175 | jsmntype_t type; | 189 | jsmntype_t type; |
| @@ -198,10 +212,13 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j | |||
| 198 | } | 212 | } |
| 199 | token = &tokens[parser->toknext - 1]; | 213 | token = &tokens[parser->toknext - 1]; |
| 200 | for (;;) { | 214 | for (;;) { |
| 201 | if (token->start != -1 && token->end == -1) { | 215 | if (token->start != JSMN_POS_INVALID && token->end == JSMN_POS_INVALID) { |
| 202 | if (token->type != type) { | 216 | if (token->type != type) { |
| 203 | return JSMN_ERROR_INVAL; | 217 | return JSMN_ERROR_INVAL; |
| 204 | } | 218 | } |
| 219 | if (parser->pos == SIZE_MAX) { | ||
| 220 | return JSMN_ERROR_INVAL; | ||
| 221 | } | ||
| 205 | token->end = parser->pos + 1; | 222 | token->end = parser->pos + 1; |
| 206 | parser->toksuper = token->parent; | 223 | parser->toksuper = token->parent; |
| 207 | break; | 224 | break; |
| @@ -214,7 +231,7 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j | |||
| 214 | #else | 231 | #else |
| 215 | for (i = parser->toknext - 1; i >= 0; i--) { | 232 | for (i = parser->toknext - 1; i >= 0; i--) { |
| 216 | token = &tokens[i]; | 233 | token = &tokens[i]; |
| 217 | if (token->start != -1 && token->end == -1) { | 234 | if (token->start != JSMN_POS_INVALID && token->end == JSMN_POS_INVALID) { |
| 218 | if (token->type != type) { | 235 | if (token->type != type) { |
| 219 | return JSMN_ERROR_INVAL; | 236 | return JSMN_ERROR_INVAL; |
| 220 | } | 237 | } |
| @@ -227,7 +244,7 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j | |||
| 227 | if (i == -1) return JSMN_ERROR_INVAL; | 244 | if (i == -1) return JSMN_ERROR_INVAL; |
| 228 | for (; i >= 0; i--) { | 245 | for (; i >= 0; i--) { |
| 229 | token = &tokens[i]; | 246 | token = &tokens[i]; |
| 230 | if (token->start != -1 && token->end == -1) { | 247 | if (token->start != JSMN_POS_INVALID && token->end == JSMN_POS_INVALID) { |
| 231 | parser->toksuper = i; | 248 | parser->toksuper = i; |
| 232 | break; | 249 | break; |
| 233 | } | 250 | } |
| @@ -268,7 +285,7 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j | |||
| 268 | 285 | ||
| 269 | for (i = parser->toknext - 1; i >= 0; i--) { | 286 | for (i = parser->toknext - 1; i >= 0; i--) { |
| 270 | /* Unmatched opened object or array */ | 287 | /* Unmatched opened object or array */ |
| 271 | if (tokens[i].start != -1 && tokens[i].end == -1) { | 288 | if (tokens[i].start != JSMN_POS_INVALID && tokens[i].end == JSMN_POS_INVALID) { |
| 272 | return JSMN_ERROR_PART; | 289 | return JSMN_ERROR_PART; |
| 273 | } | 290 | } |
| 274 | } | 291 | } |
| @@ -3,6 +3,8 @@ | |||
| 3 | * Simple JSON parser (header file) | 3 | * Simple JSON parser (header file) |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2010 Serge A. Zaitsev | 5 | * Copyright (c) 2010 Serge A. Zaitsev |
| 6 | * Updated to use size_t for token offsets and harden against overflows. | ||
| 7 | * (Nikias Bassen, January 2026) | ||
| 6 | * | 8 | * |
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 8 | * of this software and associated documentation files (the "Software"), to deal | 10 | * of this software and associated documentation files (the "Software"), to deal |
| @@ -25,6 +27,8 @@ | |||
| 25 | #ifndef __JSMN_H_ | 27 | #ifndef __JSMN_H_ |
| 26 | #define __JSMN_H_ | 28 | #define __JSMN_H_ |
| 27 | 29 | ||
| 30 | #include <stddef.h> | ||
| 31 | |||
| 28 | /** | 32 | /** |
| 29 | * JSON type identifier. Basic types are: | 33 | * JSON type identifier. Basic types are: |
| 30 | * o Object | 34 | * o Object |
| @@ -46,6 +50,8 @@ typedef enum { | |||
| 46 | JSMN_ERROR_INVAL = -2, | 50 | JSMN_ERROR_INVAL = -2, |
| 47 | /* The string is not a full JSON packet, more bytes expected */ | 51 | /* The string is not a full JSON packet, more bytes expected */ |
| 48 | JSMN_ERROR_PART = -3, | 52 | JSMN_ERROR_PART = -3, |
| 53 | /* Input exceeds implementation-defined limits */ | ||
| 54 | JSMN_ERROR_LIMIT = -4, | ||
| 49 | /* Everything was fine */ | 55 | /* Everything was fine */ |
| 50 | JSMN_SUCCESS = 0 | 56 | JSMN_SUCCESS = 0 |
| 51 | } jsmnerr_t; | 57 | } jsmnerr_t; |
| @@ -58,9 +64,9 @@ typedef enum { | |||
| 58 | */ | 64 | */ |
| 59 | typedef struct { | 65 | typedef struct { |
| 60 | jsmntype_t type; | 66 | jsmntype_t type; |
| 61 | int start; | 67 | size_t start; |
| 62 | int end; | 68 | size_t end; |
| 63 | int size; | 69 | size_t size; |
| 64 | #ifdef JSMN_PARENT_LINKS | 70 | #ifdef JSMN_PARENT_LINKS |
| 65 | int parent; | 71 | int parent; |
| 66 | #endif | 72 | #endif |
| @@ -71,8 +77,8 @@ typedef struct { | |||
| 71 | * the string being parsed now and current position in that string | 77 | * the string being parsed now and current position in that string |
| 72 | */ | 78 | */ |
| 73 | typedef struct { | 79 | typedef struct { |
| 74 | unsigned int pos; /* offset in the JSON string */ | 80 | size_t pos; /* offset in the JSON string */ |
| 75 | unsigned int end; /* offset after last character of JSON string */ | 81 | size_t end; /* offset after last character of JSON string */ |
| 76 | int toknext; /* next token to allocate */ | 82 | int toknext; /* next token to allocate */ |
| 77 | int toksuper; /* superior token node, e.g parent object or array */ | 83 | int toksuper; /* superior token node, e.g parent object or array */ |
| 78 | } jsmn_parser; | 84 | } jsmn_parser; |
| @@ -86,7 +92,7 @@ void jsmn_init(jsmn_parser *parser); | |||
| 86 | * Run JSON parser. It parses a JSON data string into and array of tokens, each describing | 92 | * Run JSON parser. It parses a JSON data string into and array of tokens, each describing |
| 87 | * a single JSON object. | 93 | * a single JSON object. |
| 88 | */ | 94 | */ |
| 89 | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, | 95 | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t length, |
| 90 | jsmntok_t *tokens, unsigned int num_tokens); | 96 | jsmntok_t *tokens, unsigned int num_tokens); |
| 91 | 97 | ||
| 92 | #endif /* __JSMN_H_ */ | 98 | #endif /* __JSMN_H_ */ |
