|  | @@ -25,6 +25,9 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include "src/core/lib/json/json.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define GRPC_JSON_MAX_DEPTH 255
 | 
	
		
			
				|  |  | +#define GRPC_JSON_MAX_ERRORS 16
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  namespace grpc_core {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace {
 | 
	
	
		
			
				|  | @@ -92,7 +95,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();
 | 
	
	
		
			
				|  | @@ -111,6 +114,7 @@ class JsonReader {
 | 
	
		
			
				|  |  |    uint16_t unicode_char_ = 0;
 | 
	
		
			
				|  |  |    uint16_t unicode_high_surrogate_ = 0;
 | 
	
		
			
				|  |  |    std::vector<grpc_error*> errors_;
 | 
	
		
			
				|  |  | +  bool truncated_errors_ = false;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    Json root_value_;
 | 
	
		
			
				|  |  |    std::vector<Json*> stack_;
 | 
	
	
		
			
				|  | @@ -169,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 {
 | 
	
	
		
			
				|  | @@ -185,7 +193,19 @@ Json* JsonReader::CreateAndLinkValue() {
 | 
	
		
			
				|  |  |    return value;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void JsonReader::StartContainer(Json::Type type) {
 | 
	
		
			
				|  |  | +bool JsonReader::StartContainer(Json::Type type) {
 | 
	
		
			
				|  |  | +  if (stack_.size() == GRPC_JSON_MAX_DEPTH) {
 | 
	
		
			
				|  |  | +    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();
 | 
	
		
			
				|  |  |    if (type == Json::Type::OBJECT) {
 | 
	
		
			
				|  |  |      *value = Json::Object();
 | 
	
	
		
			
				|  | @@ -194,6 +214,7 @@ void JsonReader::StartContainer(Json::Type type) {
 | 
	
		
			
				|  |  |      *value = Json::Array();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    stack_.push_back(value);
 | 
	
		
			
				|  |  | +  return true;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void JsonReader::EndContainer() {
 | 
	
	
		
			
				|  | @@ -483,13 +504,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;
 | 
	
	
		
			
				|  | @@ -793,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,
 |