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. 38
      src/core/lib/json/json_reader.cc

@ -25,6 +25,9 @@
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#define GRPC_JSON_MAX_DEPTH 255
#define GRPC_JSON_MAX_ERRORS 16
namespace grpc_core { namespace grpc_core {
namespace { namespace {
@ -92,7 +95,7 @@ class JsonReader {
void StringAddUtf32(uint32_t c); void StringAddUtf32(uint32_t c);
Json* CreateAndLinkValue(); Json* CreateAndLinkValue();
void StartContainer(Json::Type type); bool StartContainer(Json::Type type);
void EndContainer(); void EndContainer();
void SetKey(); void SetKey();
void SetString(); void SetString();
@ -111,6 +114,7 @@ class JsonReader {
uint16_t unicode_char_ = 0; uint16_t unicode_char_ = 0;
uint16_t unicode_high_surrogate_ = 0; uint16_t unicode_high_surrogate_ = 0;
std::vector<grpc_error*> errors_; std::vector<grpc_error*> errors_;
bool truncated_errors_ = false;
Json root_value_; Json root_value_;
std::vector<Json*> stack_; std::vector<Json*> stack_;
@ -169,12 +173,16 @@ Json* JsonReader::CreateAndLinkValue() {
Json* parent = stack_.back(); Json* parent = stack_.back();
if (parent->type() == Json::Type::OBJECT) { if (parent->type() == Json::Type::OBJECT) {
if (parent->object_value().find(key_) != parent->object_value().end()) { if (parent->object_value().find(key_) != parent->object_value().end()) {
if (errors_.size() == GRPC_JSON_MAX_ERRORS) {
truncated_errors_ = true;
} else {
char* msg; char* msg;
gpr_asprintf(&msg, "duplicate key \"%s\" at index %" PRIuPTR, gpr_asprintf(&msg, "duplicate key \"%s\" at index %" PRIuPTR,
key_.c_str(), CurrentIndex()); key_.c_str(), CurrentIndex());
errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
gpr_free(msg); gpr_free(msg);
} }
}
value = &(*parent->mutable_object())[std::move(key_)]; value = &(*parent->mutable_object())[std::move(key_)];
} else { } else {
GPR_ASSERT(parent->type() == Json::Type::ARRAY); GPR_ASSERT(parent->type() == Json::Type::ARRAY);
@ -185,7 +193,19 @@ Json* JsonReader::CreateAndLinkValue() {
return value; 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(); Json* value = CreateAndLinkValue();
if (type == Json::Type::OBJECT) { if (type == Json::Type::OBJECT) {
*value = Json::Object(); *value = Json::Object();
@ -194,6 +214,7 @@ void JsonReader::StartContainer(Json::Type type) {
*value = Json::Array(); *value = Json::Array();
} }
stack_.push_back(value); stack_.push_back(value);
return true;
} }
void JsonReader::EndContainer() { void JsonReader::EndContainer() {
@ -483,13 +504,17 @@ JsonReader::Status JsonReader::Run() {
case '{': case '{':
container_just_begun_ = true; 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; state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
break; break;
case '[': case '[':
container_just_begun_ = true; container_just_begun_ = true;
StartContainer(Json::Type::ARRAY); if (!StartContainer(Json::Type::ARRAY)) {
return Status::GRPC_JSON_PARSE_ERROR;
}
break; break;
default: default:
return Status::GRPC_JSON_PARSE_ERROR; return Status::GRPC_JSON_PARSE_ERROR;
@ -793,6 +818,11 @@ JsonReader::Status JsonReader::Run() {
grpc_error* JsonReader::Parse(StringView input, Json* output) { grpc_error* JsonReader::Parse(StringView input, Json* output) {
JsonReader reader(input); JsonReader reader(input);
Status status = reader.Run(); 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) { if (status == Status::GRPC_JSON_INTERNAL_ERROR) {
char* msg; char* msg;
gpr_asprintf(&msg, "internal error in JSON parser at index %" PRIuPTR, gpr_asprintf(&msg, "internal error in JSON parser at index %" PRIuPTR,

Loading…
Cancel
Save