Skip to content

Commit 72fc9e7

Browse files
committed
lib BUGFIX check value size limits
Use uint64_t for bit sizes and check all sizes for overflows. Fixes #2497
1 parent bd5b38f commit 72fc9e7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+209
-187
lines changed

src/json.c

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @author Michal Vasko <mvasko@cesnet.cz>
55
* @brief Generic JSON format parser for libyang
66
*
7-
* Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
7+
* Copyright (c) 2020 - 2026 CESNET, z.s.p.o.
88
*
99
* This source code is licensed under BSD 3-Clause License (the "License").
1010
* You may not use this file except in compliance with the License.
@@ -106,7 +106,7 @@ lyjson_skip_ws(struct lyjson_ctx *jsonctx)
106106
* @param[in] dynamic Whether @p value is dynamically-allocated.
107107
*/
108108
static void
109-
lyjson_ctx_set_value(struct lyjson_ctx *jsonctx, const char *value, size_t value_len, ly_bool dynamic)
109+
lyjson_ctx_set_value(struct lyjson_ctx *jsonctx, const char *value, uint32_t value_len, ly_bool dynamic)
110110
{
111111
assert(jsonctx);
112112

@@ -127,11 +127,18 @@ lyjson_ctx_set_value(struct lyjson_ctx *jsonctx, const char *value, size_t value
127127
static LY_ERR
128128
lyjson_string(struct lyjson_ctx *jsonctx)
129129
{
130+
#define ADD_CHECK_OVERFLOW_GOTO(var, num, err_label) \
131+
if (var + num < var) { \
132+
LOGVAL(jsonctx->ctx, NULL, LYVE_SYNTAX, "JSON value too long."); \
133+
goto err_label; \
134+
} \
135+
var += num;
136+
130137
const char *in = jsonctx->in->current, *start, *c;
131138
char *buf = NULL;
132-
size_t offset; /* read offset in input buffer */
133-
size_t len; /* length of the output string (write offset in output buffer) */
134-
size_t size = 0; /* size of the output buffer */
139+
uint32_t offset; /* read offset in input buffer */
140+
uint32_t len; /* length of the output string (write offset in output buffer) */
141+
uint32_t size = 0; /* size of the output buffer */
135142
uint64_t start_line, orig_line;
136143
uint32_t u, value;
137144
uint8_t i;
@@ -160,7 +167,7 @@ lyjson_string(struct lyjson_ctx *jsonctx)
160167
* we will need 4 bytes at most since we support only the predefined
161168
* (one-char) entities and character references */
162169
if (len + offset + 4 >= size) {
163-
size_t increment;
170+
uint32_t increment;
164171

165172
for (increment = LYJSON_STRING_BUF_STEP; len + offset + 4 >= size + increment; increment += LYJSON_STRING_BUF_STEP) {}
166173
buf = ly_realloc(buf, size + increment);
@@ -212,7 +219,7 @@ lyjson_string(struct lyjson_ctx *jsonctx)
212219
break;
213220
case 'u':
214221
/* Basic Multilingual Plane character \uXXXX */
215-
offset++;
222+
ADD_CHECK_OVERFLOW_GOTO(offset, 1, error);
216223
for (value = i = 0; i < 4; i++) {
217224
if (!in[offset + i]) {
218225
LOGVAL(jsonctx->ctx, NULL, LYVE_SYNTAX, "Invalid basic multilingual plane character \"%s\".", c);
@@ -233,7 +240,8 @@ lyjson_string(struct lyjson_ctx *jsonctx)
233240
goto error;
234241
}
235242

236-
offset += i; /* add read escaped characters */
243+
/* add read escaped characters */
244+
ADD_CHECK_OVERFLOW_GOTO(offset, i, error);
237245
LY_CHECK_ERR_GOTO(ly_pututf8(&buf[len], value, &u),
238246
LOGVAL(jsonctx->ctx, NULL, LYVE_SYNTAX, "Invalid character reference \"%.*s\" (0x%08" PRIx32 ").",
239247
(int)(&in[offset] - c), c, value),
@@ -258,7 +266,7 @@ lyjson_string(struct lyjson_ctx *jsonctx)
258266
buf[len + offset] = '\0';
259267
}
260268
len += offset;
261-
++offset;
269+
ADD_CHECK_OVERFLOW_GOTO(offset, 1, error);
262270
in += offset;
263271
goto success;
264272

@@ -274,7 +282,7 @@ lyjson_string(struct lyjson_ctx *jsonctx)
274282
error);
275283

276284
/* character is ok, continue */
277-
offset += u;
285+
ADD_CHECK_OVERFLOW_GOTO(offset, u, error);
278286
break;
279287
}
280288
}
@@ -438,7 +446,7 @@ lyjson_exp_number_copy_num_part(const char *num, uint32_t num_len, char *dec_poi
438446
*/
439447
static LY_ERR
440448
lyjson_exp_number(const struct ly_ctx *ctx, const char *in, const char *exponent, uint64_t total_len, char **res,
441-
size_t *res_len)
449+
uint32_t *res_len)
442450
{
443451

444452
#define MAYBE_WRITE_MINUS(ARRAY, INDEX, FLAG) \
@@ -630,7 +638,14 @@ lyjson_exp_number(const struct ly_ctx *ctx, const char *in, const char *exponent
630638
static LY_ERR
631639
lyjson_number(struct lyjson_ctx *jsonctx)
632640
{
633-
size_t offset = 0, num_len;
641+
#define ADD_CHECK_OVERFLOW_RET(var, num, ret) \
642+
if (var + num < var) { \
643+
LOGVAL(jsonctx->ctx, NULL, LYVE_SYNTAX, "JSON value too long."); \
644+
return ret; \
645+
} \
646+
var += num;
647+
648+
uint32_t offset = 0, num_len;
634649
const char *in = jsonctx->in->current, *exponent = NULL;
635650
uint8_t minus = 0;
636651
char *num;
@@ -645,7 +660,7 @@ lyjson_number(struct lyjson_ctx *jsonctx)
645660
} else if (isdigit(in[offset])) {
646661
++offset;
647662
while (isdigit(in[offset])) {
648-
++offset;
663+
ADD_CHECK_OVERFLOW_RET(offset, 1, LY_EINVAL);
649664
}
650665
} else {
651666
invalid_character:
@@ -658,26 +673,26 @@ lyjson_number(struct lyjson_ctx *jsonctx)
658673
}
659674

660675
if (in[offset] == '.') {
661-
++offset;
676+
ADD_CHECK_OVERFLOW_RET(offset, 1, LY_EINVAL);
662677
if (!isdigit(in[offset])) {
663678
goto invalid_character;
664679
}
665680
while (isdigit(in[offset])) {
666-
++offset;
681+
ADD_CHECK_OVERFLOW_RET(offset, 1, LY_EINVAL);
667682
}
668683
}
669684

670685
if ((in[offset] == 'e') || (in[offset] == 'E')) {
671686
exponent = &in[offset];
672-
++offset;
687+
ADD_CHECK_OVERFLOW_RET(offset, 1, LY_EINVAL);
673688
if ((in[offset] == '+') || (in[offset] == '-')) {
674-
++offset;
689+
ADD_CHECK_OVERFLOW_RET(offset, 1, LY_EINVAL);
675690
}
676691
if (!isdigit(in[offset])) {
677692
goto invalid_character;
678693
}
679694
while (isdigit(in[offset])) {
680-
++offset;
695+
ADD_CHECK_OVERFLOW_RET(offset, 1, LY_EINVAL);
681696
}
682697
}
683698

src/json.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @author Michal Vasko <mvasko@cesnet.cz>
55
* @brief Generic JSON format parser routines.
66
*
7-
* Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
7+
* Copyright (c) 2020 - 2026 CESNET, z.s.p.o.
88
*
99
* This source code is licensed under BSD 3-Clause License (the "License").
1010
* You may not use this file except in compliance with the License.
@@ -69,14 +69,14 @@ struct lyjson_ctx {
6969
struct ly_set status; /* stack of ::LYJSON_PARSER_STATUS values corresponding to the JSON items being processed */
7070

7171
const char *value; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
72-
size_t value_len; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
72+
uint32_t value_len; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
7373
ly_bool dynamic; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
7474

7575
struct {
7676
enum LYJSON_PARSER_STATUS status;
7777
uint32_t status_count;
7878
const char *value;
79-
size_t value_len;
79+
uint32_t value_len;
8080
ly_bool dynamic;
8181
const char *input;
8282
} backup;

src/parser_common.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,13 @@ lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode)
203203

204204
LY_ERR
205205
lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *schema, const struct lyd_node *lnode,
206-
const void *value, uint32_t value_bits_len, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data,
206+
const void *value, uint64_t value_size_bits, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data,
207207
uint32_t hints, struct lyd_node **node)
208208
{
209209
ly_bool incomplete;
210210
ly_bool store_only = (lydctx->parse_opts & LYD_PARSE_STORE_ONLY) == LYD_PARSE_STORE_ONLY ? 1 : 0;
211211

212-
LY_CHECK_RET(lyd_create_term(schema, lnode, value, value_bits_len, 1, store_only, dynamic, format, prefix_data,
212+
LY_CHECK_RET(lyd_create_term(schema, lnode, value, value_size_bits, 1, store_only, dynamic, format, prefix_data,
213213
hints, &incomplete, node));
214214

215215
if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) {
@@ -220,7 +220,7 @@ lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *schema, c
220220

221221
LY_ERR
222222
lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod,
223-
const char *name, uint32_t name_len, const void *value, uint32_t value_size_bits, ly_bool *dynamic, LY_VALUE_FORMAT format,
223+
const char *name, uint32_t name_len, const void *value, uint64_t value_size_bits, ly_bool *dynamic, LY_VALUE_FORMAT format,
224224
void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, const struct lyd_node *lnode)
225225
{
226226
LY_ERR rc = LY_SUCCESS;

src/parser_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ LY_ERR lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *s
371371
* @return LY_ERR value if an error occurred.
372372
*/
373373
LY_ERR lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *schema, const struct lyd_node *lnode,
374-
const void *value, uint32_t value_size_bits, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data,
374+
const void *value, uint64_t value_size_bits, ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data,
375375
uint32_t hints, struct lyd_node **node);
376376

377377
/**
@@ -394,7 +394,7 @@ LY_ERR lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *sc
394394
* @return LY_ERR value.
395395
*/
396396
LY_ERR lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta,
397-
const struct lys_module *mod, const char *name, uint32_t name_len, const void *value, uint32_t value_size_bits,
397+
const struct lys_module *mod, const char *name, uint32_t name_len, const void *value, uint64_t value_size_bits,
398398
ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
399399
const struct lyd_node *lnode);
400400

src/parser_json.c

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ lyjson_ctx_give_dynamic_value(struct lyjson_ctx *jsonctx, char **dst)
104104
* @param[out] is_meta_p Pointer to the metadata flag, set to 1 if the member-name contains \@, 0 otherwise.
105105
*/
106106
static void
107-
lydjson_parse_name(const char *value, size_t value_len, const char **name_p, size_t *name_len_p, const char **prefix_p,
108-
size_t *prefix_len_p, ly_bool *is_meta_p)
107+
lydjson_parse_name(const char *value, uint32_t value_len, const char **name_p, uint32_t *name_len_p, const char **prefix_p,
108+
uint32_t *prefix_len_p, ly_bool *is_meta_p)
109109
{
110110
const char *name, *prefix = NULL;
111-
size_t name_len, prefix_len = 0;
111+
uint32_t name_len, prefix_len = 0;
112112
ly_bool is_meta = 0;
113113

114114
name = memchr(value, ':', value_len);
@@ -150,8 +150,8 @@ lydjson_parse_name(const char *value, size_t value_len, const char **name_p, siz
150150
* @return LY_ERR value.
151151
*/
152152
static LY_ERR
153-
lydjson_get_node_prefix(struct lyd_node *node, const char *local_prefix, size_t local_prefix_len, const char **prefix_p,
154-
size_t *prefix_len_p)
153+
lydjson_get_node_prefix(struct lyd_node *node, const char *local_prefix, uint32_t local_prefix_len, const char **prefix_p,
154+
uint32_t *prefix_len_p)
155155
{
156156
struct lyd_node_opaq *onode;
157157
const char *module_name = NULL;
@@ -253,8 +253,8 @@ lydjson_data_skip(struct lyjson_ctx *jsonctx)
253253
* @return LY_ERR on error.
254254
*/
255255
static LY_ERR
256-
lydjson_get_snode(struct lyd_json_ctx *lydctx, ly_bool is_attr, const char *prefix, size_t prefix_len, const char *name,
257-
size_t name_len, struct lyd_node *parent, const struct lysc_node **snode, struct lysc_ext_instance **ext)
256+
lydjson_get_snode(struct lyd_json_ctx *lydctx, ly_bool is_attr, const char *prefix, uint32_t prefix_len, const char *name,
257+
uint32_t name_len, struct lyd_node *parent, const struct lysc_node **snode, struct lysc_ext_instance **ext)
258258
{
259259
LY_ERR r;
260260
struct lys_module *mod = NULL;
@@ -432,7 +432,7 @@ lydjson_check_list(struct lyd_json_ctx *lydctx, const struct lysc_node *list)
432432
if (status == LYJSON_OBJECT) {
433433
do {
434434
const char *name, *prefix;
435-
size_t name_len, prefix_len;
435+
uint32_t name_len, prefix_len;
436436
ly_bool is_attr;
437437

438438
/* match the key */
@@ -589,7 +589,7 @@ lydjson_metadata_finish(struct lyd_json_ctx *lydctx, struct lyd_node **first_p)
589589
uint64_t match = 0;
590590
ly_bool is_attr;
591591
const char *name, *prefix;
592-
size_t name_len, prefix_len;
592+
uint32_t name_len, prefix_len;
593593
const struct lysc_node *snode;
594594

595595
if (attr->schema || (meta_container->name.name[0] != '@')) {
@@ -733,7 +733,7 @@ lydjson_meta_attr(struct lyd_json_ctx *lydctx, struct lyd_node *node)
733733
ly_bool in_parent = 0;
734734
const char *name, *prefix = NULL;
735735
char *dynamic_prefname = NULL;
736-
size_t name_len, prefix_len = 0;
736+
uint32_t name_len, prefix_len = 0;
737737
struct lys_module *mod;
738738
const struct ly_ctx *ctx = lydctx->jsonctx->ctx;
739739
ly_bool is_attr = 0;
@@ -867,7 +867,7 @@ lydjson_meta_attr(struct lyd_json_ctx *lydctx, struct lyd_node *node)
867867
} else {
868868
/* create attribute */
869869
const char *module_name;
870-
size_t module_name_len;
870+
uint32_t module_name_len;
871871

872872
lydjson_get_node_prefix(node, prefix, prefix_len, &module_name, &module_name_len);
873873

@@ -929,12 +929,12 @@ lydjson_meta_attr(struct lyd_json_ctx *lydctx, struct lyd_node *node)
929929
* @return LY_ERR value.
930930
*/
931931
static LY_ERR
932-
lydjson_create_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
932+
lydjson_create_opaq(struct lyd_json_ctx *lydctx, const char *name, uint32_t name_len, const char *prefix, uint32_t prefix_len,
933933
struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_inner_p, struct lyd_node **node_p)
934934
{
935935
LY_ERR ret = LY_SUCCESS;
936936
const char *value = NULL, *module_name;
937-
size_t value_len = 0, module_name_len = 0;
937+
uint32_t value_len = 0, module_name_len = 0;
938938
ly_bool dynamic = 0;
939939
uint32_t type_hint = 0;
940940

@@ -987,7 +987,7 @@ lydjson_create_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_l
987987
* @return LY_ERR value.
988988
*/
989989
static LY_ERR
990-
lydjson_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len,
990+
lydjson_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, uint32_t name_len, const char *prefix, uint32_t prefix_len,
991991
struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_p, enum LYJSON_PARSER_STATUS *status_inner_p,
992992
struct lyd_node **first_p, struct lyd_node **node)
993993
{
@@ -1084,8 +1084,8 @@ lydjson_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_le
10841084
* @return LY_ERR value.
10851085
*/
10861086
static LY_ERR
1087-
lydjson_ctx_next_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_len, const char *prefix,
1088-
size_t prefix_len, struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_p,
1087+
lydjson_ctx_next_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, uint32_t name_len, const char *prefix,
1088+
uint32_t prefix_len, struct lyd_node *parent, enum LYJSON_PARSER_STATUS *status_p,
10891089
struct lyd_node **first_p, struct lyd_node **node)
10901090
{
10911091
enum LYJSON_PARSER_STATUS status_inner = 0;
@@ -1132,12 +1132,12 @@ lydjson_ctx_next_parse_opaq(struct lyd_json_ctx *lydctx, const char *name, size_
11321132
*/
11331133
static LY_ERR
11341134
lydjson_parse_attribute(struct lyd_json_ctx *lydctx, struct lyd_node *attr_node, const struct lysc_node *snode,
1135-
const char *name, size_t name_len, const char *prefix, size_t prefix_len, struct lyd_node *parent,
1135+
const char *name, uint32_t name_len, const char *prefix, uint32_t prefix_len, struct lyd_node *parent,
11361136
enum LYJSON_PARSER_STATUS *status_p, struct lyd_node **first_p, struct lyd_node **node_p)
11371137
{
11381138
LY_ERR r;
11391139
const char *opaq_name, *mod_name, *attr_mod = NULL;
1140-
size_t opaq_name_len, attr_mod_len = 0;
1140+
uint32_t opaq_name_len, attr_mod_len = 0;
11411141

11421142
if (!attr_node) {
11431143
/* learn the attribute module name */
@@ -1446,8 +1446,8 @@ lydjson_parse_instance_inner(struct lyd_json_ctx *lydctx, const struct lysc_node
14461446
*/
14471447
static LY_ERR
14481448
lydjson_parse_instance(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p,
1449-
const struct lysc_node *snode, const struct lysc_ext_instance *ext, const char *name, size_t name_len,
1450-
const char *prefix, size_t prefix_len, enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
1449+
const struct lysc_node *snode, const struct lysc_ext_instance *ext, const char *name, uint32_t name_len,
1450+
const char *prefix, uint32_t prefix_len, enum LYJSON_PARSER_STATUS *status, struct lyd_node **node)
14511451
{
14521452
LY_ERR r, rc = LY_SUCCESS;
14531453
uint32_t type_hints = 0;
@@ -1467,7 +1467,8 @@ lydjson_parse_instance(struct lyd_json_ctx *lydctx, struct lyd_node *parent, str
14671467

14681468
/* create terminal node */
14691469
r = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, parent, lydctx->jsonctx->value,
1470-
lydctx->jsonctx->value_len * 8, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL, type_hints, node);
1470+
(uint64_t)lydctx->jsonctx->value_len * 8, &lydctx->jsonctx->dynamic, LY_VALUE_JSON, NULL,
1471+
type_hints, node);
14711472
LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);
14721473

14731474
/* insert, needs LYD_EXT flag */
@@ -1537,7 +1538,7 @@ lydjson_subtree_r(struct lyd_json_ctx *lydctx, struct lyd_node *parent, struct l
15371538
LY_ERR r, rc = LY_SUCCESS;
15381539
enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(lydctx->jsonctx);
15391540
const char *name, *prefix = NULL, *expected = NULL;
1540-
size_t name_len, prefix_len = 0;
1541+
uint32_t name_len, prefix_len = 0;
15411542
ly_bool is_meta = 0;
15421543
const struct lysc_node *snode = NULL;
15431544
struct lysc_ext_instance *ext = NULL;
@@ -2009,7 +2010,7 @@ lydjson_envelope(struct lyjson_ctx *jsonctx, const char *name, const char *modul
20092010
LY_ERR rc = LY_SUCCESS, r;
20102011
enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx);
20112012
const char *nam, *prefix;
2012-
size_t nam_len, prefix_len;
2013+
uint32_t nam_len, prefix_len;
20132014
ly_bool is_meta;
20142015

20152016
assert(status == LYJSON_OBJECT);

0 commit comments

Comments
 (0)