Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
- Native/macOS: fix module `image_size` computation, which could have caused the symbolicator to misattribute every frame to the lowest-addressed image (typically `dyld` or `libsystem`). ([#1740](https://github.com/getsentry/sentry-native/pull/1740))
- Native: raise `SENTRY_CRASH_MAX_MODULES` from `512` to `2048` so processes that load many shared libraries no longer have their minidump module list truncated, which left frames in unrecorded modules without a `debug_id` and unsymbolicatable.
([#1738](https://github.com/getsentry/sentry-native/pull/1738))
- Reject overly deep msgpack payloads during deserialization. ([#1727](https://github.com/getsentry/sentry-native/pull/1727))
- Reject overly deep JSON and msgpack payloads during deserialization. ([#1727](https://github.com/getsentry/sentry-native/pull/1727), [#1748](https://github.com/getsentry/sentry-native/pull/1748))
- Read lengths for variadic fingerprints. ([#1730](https://github.com/getsentry/sentry-native/pull/1730))
- Guard against JSON token allocation overflow on 32-bit platforms. ([#1733](https://github.com/getsentry/sentry-native/pull/1733))
- Windows: fix HTTP rate limit response header parsing. ([#1732](https://github.com/getsentry/sentry-native/pull/1732))
Expand Down
16 changes: 12 additions & 4 deletions src/sentry_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "sentry_utils.h"
#include "sentry_value.h"

#define SENTRY_JSON_MAX_DEPTH 64

typedef struct {
void (*free)(sentry_jsonwriter_t *writer);
void (*write_str)(sentry_jsonwriter_t *writer, const char *str);
Expand Down Expand Up @@ -207,7 +209,7 @@ sentry__jsonwriter_into_string(sentry_jsonwriter_t *jw, size_t *len_out)
static bool
at_max_depth(const sentry_jsonwriter_t *jw)
{
return jw->depth >= 64;
return jw->depth >= SENTRY_JSON_MAX_DEPTH;
}

static void
Expand Down Expand Up @@ -578,15 +580,15 @@ decode_string_inplace(char *buf)

static size_t
tokens_to_value(jsmntok_t *tokens, size_t token_count, const char *buf,
sentry_value_t *value_out)
size_t depth, sentry_value_t *value_out)
{
size_t offset = 0;

#define POP() (offset < token_count ? &tokens[offset++] : NULL)
#define NESTED_PARSE(Target) \
do { \
size_t child_consumed = tokens_to_value( \
tokens + offset, token_count - offset, buf, Target); \
tokens + offset, token_count - offset, buf, depth + 1, Target); \
if (child_consumed == (size_t)-1) { \
goto error; \
} \
Expand Down Expand Up @@ -665,6 +667,9 @@ tokens_to_value(jsmntok_t *tokens, size_t token_count, const char *buf,
break;
}
case JSMN_OBJECT: {
if (depth >= SENTRY_JSON_MAX_DEPTH) {
goto error;
}
rv = sentry_value_new_object();
for (int i = 0; i < root->size; i++) {
jsmntok_t *token = POP();
Expand All @@ -687,6 +692,9 @@ tokens_to_value(jsmntok_t *tokens, size_t token_count, const char *buf,
break;
}
case JSMN_ARRAY: {
if (depth >= SENTRY_JSON_MAX_DEPTH) {
goto error;
}
rv = sentry_value_new_list();
for (int i = 0; i < root->size; i++) {
sentry_value_t child;
Expand Down Expand Up @@ -738,7 +746,7 @@ sentry__value_from_json(const char *buf, size_t buflen)

sentry_value_t value_out;
size_t tokens_consumed
= tokens_to_value(tokens, (size_t)token_count, buf, &value_out);
= tokens_to_value(tokens, (size_t)token_count, buf, 0, &value_out);
sentry_free(tokens);

if (tokens_consumed == (size_t)token_count) {
Expand Down
2 changes: 1 addition & 1 deletion src/sentry_value.c
Original file line number Diff line number Diff line change
Expand Up @@ -1643,7 +1643,7 @@ sentry_event_value_add_stacktrace(sentry_value_t event, void **ips, size_t len)
sentry_event_add_thread(event, thread);
}

#define SENTRY_MPACK_MAX_DEPTH 32
#define SENTRY_MPACK_MAX_DEPTH 64

static sentry_value_t
value_from_mpack(mpack_node_t node, size_t depth, bool *ok)
Expand Down
28 changes: 26 additions & 2 deletions tests/unit/test_value.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ write_nested_msgpack_arrays(char *buf, size_t depth)
buf[depth] = (char)0xc0; // nil
}

static void
write_nested_json_arrays(char *buf, size_t depth)
{
memset(buf, '[', depth);
memcpy(buf + depth, "null", 4);
memset(buf + depth + 4, ']', depth);
buf[depth * 2 + 4] = '\0';
}

SENTRY_TEST(value_null)
{
sentry_value_t val = sentry_value_new_null();
Expand Down Expand Up @@ -881,6 +890,21 @@ SENTRY_TEST(value_json_deeply_nested)
sentry_value_decref(parsed);
}

SENTRY_TEST(value_json_max_depth)
{
char accepted[64 * 2 + sizeof("null")]; // SENTRY_JSON_MAX_DEPTH
write_nested_json_arrays(accepted, 64);
sentry_value_t value = sentry__value_from_json(accepted, strlen(accepted));
TEST_CHECK(sentry_value_get_type(value) == SENTRY_VALUE_TYPE_LIST);
sentry_value_decref(value);

char too_deep[65 * 2 + sizeof("null")]; // SENTRY_JSON_MAX_DEPTH + 1
write_nested_json_arrays(too_deep, 65);
value = sentry__value_from_json(too_deep, strlen(too_deep));
TEST_CHECK(sentry_value_is_null(value));
sentry_value_decref(value);
}

SENTRY_TEST(value_json_escaping)
{
sentry_value_t rv = sentry__value_from_json(
Expand Down Expand Up @@ -1558,14 +1582,14 @@ SENTRY_TEST(value_from_msgpack_list)

SENTRY_TEST(value_from_msgpack_deeply_nested)
{
char accepted[32 + 1]; // SENTRY_MPACK_MAX_DEPTH + 1
char accepted[64 + 1]; // SENTRY_MPACK_MAX_DEPTH + 1
write_nested_msgpack_arrays(accepted, sizeof(accepted) - 1);
sentry_value_t value
= sentry__value_from_msgpack(accepted, sizeof(accepted));
TEST_CHECK(sentry_value_get_type(value) == SENTRY_VALUE_TYPE_LIST);
sentry_value_decref(value);

char too_deep[32 + 2]; // SENTRY_MPACK_MAX_DEPTH + 2
char too_deep[64 + 2]; // SENTRY_MPACK_MAX_DEPTH + 2
write_nested_msgpack_arrays(too_deep, sizeof(too_deep) - 1);
value = sentry__value_from_msgpack(too_deep, sizeof(too_deep));
TEST_CHECK(sentry_value_is_null(value));
Expand Down
1 change: 1 addition & 0 deletions tests/unit/tests.inc
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ XX(value_json_deeply_nested)
XX(value_json_escaping)
XX(value_json_invalid_doubles)
XX(value_json_locales)
XX(value_json_max_depth)
XX(value_json_parsing)
XX(value_json_surrogates)
XX(value_list)
Expand Down
Loading