Skip to content

Commit a90a83a

Browse files
committed
variant_utils: bound nested MessagePack values
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
1 parent 0242fd7 commit a90a83a

2 files changed

Lines changed: 113 additions & 13 deletions

File tree

include/cmetrics/cmt_variant_utils.h

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#define CFL_VARIANT_UTILS_MAXIMUM_FIXED_ARRAY_SIZE 100
2626
#define CFL_VARIANT_UTILS_INITIAL_ARRAY_SIZE 100
2727
#define CFL_VARIANT_UTILS_SERIALIZED_ARRAY_SIZE_LIMIT 100000
28+
#define CFL_VARIANT_UTILS_MAXIMUM_NESTING_DEPTH 32
2829

2930
/* These are the only functions meant for general use,
3031
* the reason why the kvlist packing and unpacking
@@ -48,9 +49,17 @@ static inline int pack_cfl_variant(mpack_writer_t *writer,
4849
static inline int pack_cfl_variant_kvlist(mpack_writer_t *writer,
4950
struct cfl_kvlist *kvlist);
5051

52+
static inline int unpack_cfl_variant_depth(mpack_reader_t *reader,
53+
struct cfl_variant **value,
54+
size_t depth);
55+
5156
static inline int unpack_cfl_variant(mpack_reader_t *reader,
5257
struct cfl_variant **value);
5358

59+
static inline int unpack_cfl_kvlist_depth(mpack_reader_t *reader,
60+
struct cfl_kvlist **result_kvlist,
61+
size_t depth);
62+
5463
static inline int unpack_cfl_kvlist(mpack_reader_t *reader,
5564
struct cfl_kvlist **result_kvlist);
5665

@@ -234,7 +243,8 @@ static inline int unpack_cfl_variant_read_tag(mpack_reader_t *reader,
234243
}
235244

236245
static inline int unpack_cfl_array(mpack_reader_t *reader,
237-
struct cfl_array **result_array)
246+
struct cfl_array **result_array,
247+
size_t depth)
238248
{
239249
struct cfl_array *internal_array;
240250
size_t entry_count;
@@ -243,6 +253,10 @@ static inline int unpack_cfl_array(mpack_reader_t *reader,
243253
size_t index;
244254
mpack_tag_t tag;
245255

256+
if (depth >= CFL_VARIANT_UTILS_MAXIMUM_NESTING_DEPTH) {
257+
return -2;
258+
}
259+
246260
result = unpack_cfl_variant_read_tag(reader, &tag, mpack_type_array);
247261

248262
if (result != 0) {
@@ -271,7 +285,7 @@ static inline int unpack_cfl_array(mpack_reader_t *reader,
271285
}
272286

273287
for (index = 0 ; index < entry_count ; index++) {
274-
result = unpack_cfl_variant(reader, &entry_value);
288+
result = unpack_cfl_variant_depth(reader, &entry_value, depth + 1);
275289

276290
if (result != 0) {
277291
cfl_array_destroy(internal_array);
@@ -301,8 +315,9 @@ static inline int unpack_cfl_array(mpack_reader_t *reader,
301315
return 0;
302316
}
303317

304-
static inline int unpack_cfl_kvlist(mpack_reader_t *reader,
305-
struct cfl_kvlist **result_kvlist)
318+
static inline int unpack_cfl_kvlist_depth(mpack_reader_t *reader,
319+
struct cfl_kvlist **result_kvlist,
320+
size_t depth)
306321
{
307322
struct cfl_kvlist *internal_kvlist;
308323
char key_name[256];
@@ -314,6 +329,10 @@ static inline int unpack_cfl_kvlist(mpack_reader_t *reader,
314329
size_t index;
315330
mpack_tag_t tag;
316331

332+
if (depth >= CFL_VARIANT_UTILS_MAXIMUM_NESTING_DEPTH) {
333+
return -2;
334+
}
335+
317336
result = unpack_cfl_variant_read_tag(reader, &tag, mpack_type_map);
318337

319338
if (result != 0) {
@@ -360,7 +379,7 @@ static inline int unpack_cfl_kvlist(mpack_reader_t *reader,
360379
break;
361380
}
362381

363-
result = unpack_cfl_variant(reader, &key_value);
382+
result = unpack_cfl_variant_depth(reader, &key_value, depth + 1);
364383

365384
if (result != 0) {
366385
result = -7;
@@ -399,6 +418,12 @@ static inline int unpack_cfl_kvlist(mpack_reader_t *reader,
399418
return result;
400419
}
401420

421+
static inline int unpack_cfl_kvlist(mpack_reader_t *reader,
422+
struct cfl_kvlist **result_kvlist)
423+
{
424+
return unpack_cfl_kvlist_depth(reader, result_kvlist, 0);
425+
}
426+
402427
static inline int unpack_cfl_variant_string(mpack_reader_t *reader,
403428
struct cfl_variant **value)
404429
{
@@ -595,12 +620,13 @@ static inline int unpack_cfl_variant_null(mpack_reader_t *reader,
595620
}
596621

597622
static inline int unpack_cfl_variant_array(mpack_reader_t *reader,
598-
struct cfl_variant **value)
623+
struct cfl_variant **value,
624+
size_t depth)
599625
{
600626
struct cfl_array *unpacked_array;
601627
int result;
602628

603-
result = unpack_cfl_array(reader, &unpacked_array);
629+
result = unpack_cfl_array(reader, &unpacked_array, depth);
604630

605631
if (result != 0) {
606632
return result;
@@ -616,12 +642,13 @@ static inline int unpack_cfl_variant_array(mpack_reader_t *reader,
616642
}
617643

618644
static inline int unpack_cfl_variant_kvlist(mpack_reader_t *reader,
619-
struct cfl_variant **value)
645+
struct cfl_variant **value,
646+
size_t depth)
620647
{
621648
struct cfl_kvlist *unpacked_kvlist;
622649
int result;
623650

624-
result = unpack_cfl_kvlist(reader, &unpacked_kvlist);
651+
result = unpack_cfl_kvlist_depth(reader, &unpacked_kvlist, depth);
625652

626653
if (result != 0) {
627654
return result;
@@ -636,8 +663,9 @@ static inline int unpack_cfl_variant_kvlist(mpack_reader_t *reader,
636663
return 0;
637664
}
638665

639-
static inline int unpack_cfl_variant(mpack_reader_t *reader,
640-
struct cfl_variant **value)
666+
static inline int unpack_cfl_variant_depth(mpack_reader_t *reader,
667+
struct cfl_variant **value,
668+
size_t depth)
641669
{
642670
mpack_type_t value_type;
643671
int result;
@@ -670,10 +698,10 @@ static inline int unpack_cfl_variant(mpack_reader_t *reader,
670698
result = unpack_cfl_variant_null(reader, value);
671699
}
672700
else if (value_type == mpack_type_array) {
673-
result = unpack_cfl_variant_array(reader, value);
701+
result = unpack_cfl_variant_array(reader, value, depth);
674702
}
675703
else if (value_type == mpack_type_map) {
676-
result = unpack_cfl_variant_kvlist(reader, value);
704+
result = unpack_cfl_variant_kvlist(reader, value, depth);
677705
}
678706
else if (value_type == mpack_type_bin) {
679707
result = unpack_cfl_variant_binary(reader, value);
@@ -685,4 +713,10 @@ static inline int unpack_cfl_variant(mpack_reader_t *reader,
685713
return result;
686714
}
687715

716+
static inline int unpack_cfl_variant(mpack_reader_t *reader,
717+
struct cfl_variant **value)
718+
{
719+
return unpack_cfl_variant_depth(reader, value, 0);
720+
}
721+
688722
#endif

tests/issues.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <cmetrics/cmt_encode_prometheus.h>
2727
#include <cmetrics/cmt_map.h>
2828
#include <cmetrics/cmt_mpack_utils.h>
29+
#include <cmetrics/cmt_variant_utils.h>
2930
#include <mpack/mpack.h>
3031

3132
#include "cmt_tests.h"
@@ -178,6 +179,70 @@ void test_truncated_msgpack_string()
178179
TEST_CHECK(output == NULL);
179180
}
180181

182+
static void check_variant_nesting_limit(int use_maps, size_t nesting_depth,
183+
int expected_result)
184+
{
185+
char *buffer;
186+
size_t size;
187+
size_t index;
188+
int result;
189+
mpack_writer_t writer;
190+
mpack_reader_t reader;
191+
struct cfl_variant *variant;
192+
193+
buffer = NULL;
194+
size = 0;
195+
variant = NULL;
196+
197+
mpack_writer_init_growable(&writer, &buffer, &size);
198+
199+
for (index = 0; index < nesting_depth; index++) {
200+
if (use_maps) {
201+
mpack_start_map(&writer, 1);
202+
mpack_write_cstr(&writer, "key");
203+
}
204+
else {
205+
mpack_start_array(&writer, 1);
206+
}
207+
}
208+
209+
mpack_write_i64(&writer, 1);
210+
211+
for (index = 0; index < nesting_depth; index++) {
212+
if (use_maps) {
213+
mpack_finish_map(&writer);
214+
}
215+
else {
216+
mpack_finish_array(&writer);
217+
}
218+
}
219+
220+
TEST_ASSERT(mpack_writer_destroy(&writer) == mpack_ok);
221+
222+
mpack_reader_init_data(&reader, buffer, size);
223+
result = unpack_cfl_variant(&reader, &variant);
224+
TEST_CHECK((result == 0) == (expected_result == 0));
225+
226+
if (variant != NULL) {
227+
cfl_variant_destroy(variant);
228+
}
229+
230+
mpack_reader_destroy(&reader);
231+
free(buffer);
232+
}
233+
234+
void test_msgpack_variant_nesting_limit()
235+
{
236+
check_variant_nesting_limit(CFL_FALSE,
237+
CFL_VARIANT_UTILS_MAXIMUM_NESTING_DEPTH, 0);
238+
check_variant_nesting_limit(CFL_FALSE,
239+
CFL_VARIANT_UTILS_MAXIMUM_NESTING_DEPTH + 1, -1);
240+
check_variant_nesting_limit(CFL_TRUE,
241+
CFL_VARIANT_UTILS_MAXIMUM_NESTING_DEPTH, 0);
242+
check_variant_nesting_limit(CFL_TRUE,
243+
CFL_VARIANT_UTILS_MAXIMUM_NESTING_DEPTH + 1, -1);
244+
}
245+
181246
#ifdef CMT_HAVE_PROMETHEUS_TEXT_DECODER
182247

183248
/* issue: https://github.com/fluent/fluent-bit/issues/10761 */
@@ -212,6 +277,7 @@ TEST_LIST = {
212277
{"issue_54", test_issue_54},
213278
{"long_msgpack_labels", test_long_msgpack_labels},
214279
{"truncated_msgpack_string", test_truncated_msgpack_string},
280+
{"msgpack_variant_nesting_limit", test_msgpack_variant_nesting_limit},
215281
#ifdef CMT_HAVE_PROMETHEUS_TEXT_DECODER
216282
{"prometheus_metric_no_subsystem", test_prometheus_metric_no_subsystem},
217283
#endif

0 commit comments

Comments
 (0)