Merge pull request #21985 from markdroth/json_overflow_fixes

Prevent overflows in JSON parser
pull/21999/head
Mark D. Roth 5 years ago committed by GitHub
commit 82c2aff21f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 48
      src/core/lib/json/json_reader.cc

@ -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,

Loading…
Cancel
Save