From ff22a394d62da2bb1c75a4023f969c5ce4a3ee9d Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 11 Feb 2020 13:34:40 -0800 Subject: [PATCH 1/2] Avoid stack overflow in JSON parser. --- src/core/lib/json/json_reader.cc | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/core/lib/json/json_reader.cc b/src/core/lib/json/json_reader.cc index d316dec98ad..c9f1451491f 100644 --- a/src/core/lib/json/json_reader.cc +++ b/src/core/lib/json/json_reader.cc @@ -25,6 +25,8 @@ #include "src/core/lib/json/json.h" +#define GRPC_JSON_MAX_DEPTH 255 + namespace grpc_core { namespace { @@ -92,7 +94,7 @@ class JsonReader { void StringAddUtf32(uint32_t c); Json* CreateAndLinkValue(); - void StartContainer(Json::Type type); + bool StartContainer(Json::Type type); void EndContainer(); void SetKey(); void SetString(); @@ -185,7 +187,15 @@ Json* JsonReader::CreateAndLinkValue() { return value; } -void JsonReader::StartContainer(Json::Type type) { +bool JsonReader::StartContainer(Json::Type type) { + if (stack_.size() == GRPC_JSON_MAX_DEPTH) { + char* msg; + gpr_asprintf(&msg, "exceeded max stack depth (%d) at index %" PRIuPTR, + GRPC_JSON_MAX_DEPTH, CurrentIndex()); + errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); + gpr_free(msg); + return false; + } Json* value = CreateAndLinkValue(); if (type == Json::Type::OBJECT) { *value = Json::Object(); @@ -194,6 +204,7 @@ void JsonReader::StartContainer(Json::Type type) { *value = Json::Array(); } stack_.push_back(value); + return true; } void JsonReader::EndContainer() { @@ -483,13 +494,17 @@ JsonReader::Status JsonReader::Run() { case '{': container_just_begun_ = true; - StartContainer(Json::Type::OBJECT); + if (!StartContainer(Json::Type::OBJECT)) { + return Status::GRPC_JSON_PARSE_ERROR; + } state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN; break; case '[': container_just_begun_ = true; - StartContainer(Json::Type::ARRAY); + if (!StartContainer(Json::Type::ARRAY)) { + return Status::GRPC_JSON_PARSE_ERROR; + } break; default: return Status::GRPC_JSON_PARSE_ERROR; From 2fe2637b3988af62958070dcc62fd754916aa09e Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 11 Feb 2020 13:58:53 -0800 Subject: [PATCH 2/2] Cap the number of errors returned from JSON parsing. --- src/core/lib/json/json_reader.cc | 35 +++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/core/lib/json/json_reader.cc b/src/core/lib/json/json_reader.cc index c9f1451491f..5667f03d52b 100644 --- a/src/core/lib/json/json_reader.cc +++ b/src/core/lib/json/json_reader.cc @@ -26,6 +26,7 @@ #include "src/core/lib/json/json.h" #define GRPC_JSON_MAX_DEPTH 255 +#define GRPC_JSON_MAX_ERRORS 16 namespace grpc_core { @@ -113,6 +114,7 @@ class JsonReader { uint16_t unicode_char_ = 0; uint16_t unicode_high_surrogate_ = 0; std::vector errors_; + bool truncated_errors_ = false; Json root_value_; std::vector stack_; @@ -171,11 +173,15 @@ Json* JsonReader::CreateAndLinkValue() { Json* parent = stack_.back(); if (parent->type() == Json::Type::OBJECT) { if (parent->object_value().find(key_) != parent->object_value().end()) { - char* msg; - gpr_asprintf(&msg, "duplicate key \"%s\" at index %" PRIuPTR, - key_.c_str(), CurrentIndex()); - errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); - gpr_free(msg); + if (errors_.size() == GRPC_JSON_MAX_ERRORS) { + truncated_errors_ = true; + } else { + char* msg; + gpr_asprintf(&msg, "duplicate key \"%s\" at index %" PRIuPTR, + key_.c_str(), CurrentIndex()); + errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); + gpr_free(msg); + } } value = &(*parent->mutable_object())[std::move(key_)]; } else { @@ -189,11 +195,15 @@ Json* JsonReader::CreateAndLinkValue() { bool JsonReader::StartContainer(Json::Type type) { if (stack_.size() == GRPC_JSON_MAX_DEPTH) { - char* msg; - gpr_asprintf(&msg, "exceeded max stack depth (%d) at index %" PRIuPTR, - GRPC_JSON_MAX_DEPTH, CurrentIndex()); - errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); - gpr_free(msg); + if (errors_.size() == GRPC_JSON_MAX_ERRORS) { + truncated_errors_ = true; + } else { + char* msg; + gpr_asprintf(&msg, "exceeded max stack depth (%d) at index %" PRIuPTR, + GRPC_JSON_MAX_DEPTH, CurrentIndex()); + errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); + gpr_free(msg); + } return false; } Json* value = CreateAndLinkValue(); @@ -808,6 +818,11 @@ JsonReader::Status JsonReader::Run() { grpc_error* JsonReader::Parse(StringView input, Json* output) { JsonReader reader(input); Status status = reader.Run(); + if (reader.truncated_errors_) { + reader.errors_.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "too many errors encountered during JSON parsing -- fix reported " + "errors and try again to see additional errors")); + } if (status == Status::GRPC_JSON_INTERNAL_ERROR) { char* msg; gpr_asprintf(&msg, "internal error in JSON parser at index %" PRIuPTR,