forked from bblanchon/ArduinoJson
Added a nesting limit to the parser to prevent stack overflow that could be a security issue
This commit is contained in:
@ -13,7 +13,8 @@ namespace Internals {
|
|||||||
|
|
||||||
class JsonParser {
|
class JsonParser {
|
||||||
public:
|
public:
|
||||||
JsonParser(JsonBuffer *buffer, char *json) : _buffer(buffer), _ptr(json) {}
|
JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit)
|
||||||
|
: _buffer(buffer), _ptr(json), _nestingLimit(nestingLimit) {}
|
||||||
|
|
||||||
JsonArray &parseArray();
|
JsonArray &parseArray();
|
||||||
JsonObject &parseObject();
|
JsonObject &parseObject();
|
||||||
@ -33,6 +34,7 @@ class JsonParser {
|
|||||||
|
|
||||||
JsonBuffer *_buffer;
|
JsonBuffer *_buffer;
|
||||||
char *_ptr;
|
char *_ptr;
|
||||||
|
uint8_t _nestingLimit;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,11 @@ class JsonBuffer {
|
|||||||
JsonArray &createArray();
|
JsonArray &createArray();
|
||||||
JsonObject &createObject();
|
JsonObject &createObject();
|
||||||
|
|
||||||
JsonArray &parseArray(char *json);
|
JsonArray &parseArray(char *json, uint8_t nestingLimit = DEFAULT_LIMIT);
|
||||||
JsonObject &parseObject(char *json);
|
JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT);
|
||||||
|
|
||||||
virtual void *alloc(size_t size) = 0;
|
virtual void *alloc(size_t size) = 0;
|
||||||
|
|
||||||
|
static const uint8_t DEFAULT_LIMIT = 10;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,9 @@ bool JsonParser::skip(const char *wordToSkip) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JsonParser::parseAnythingTo(JsonVariant &destination) {
|
void JsonParser::parseAnythingTo(JsonVariant &destination) {
|
||||||
|
if (_nestingLimit == 0) return;
|
||||||
|
_nestingLimit--;
|
||||||
|
|
||||||
skipSpaces();
|
skipSpaces();
|
||||||
|
|
||||||
switch (*_ptr) {
|
switch (*_ptr) {
|
||||||
@ -79,6 +82,8 @@ void JsonParser::parseAnythingTo(JsonVariant &destination) {
|
|||||||
destination = parseString();
|
destination = parseString();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_nestingLimit++;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArray &JsonParser::parseArray() {
|
JsonArray &JsonParser::parseArray() {
|
||||||
|
@ -26,12 +26,12 @@ JsonObject &JsonBuffer::createObject() {
|
|||||||
return JsonObject::invalid();
|
return JsonObject::invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArray &JsonBuffer::parseArray(char *json) {
|
JsonArray &JsonBuffer::parseArray(char *json, uint8_t nestingLimit) {
|
||||||
JsonParser parser(this, json);
|
JsonParser parser(this, json, nestingLimit);
|
||||||
return parser.parseArray();
|
return parser.parseArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject &JsonBuffer::parseObject(char *json) {
|
JsonObject &JsonBuffer::parseObject(char *json, uint8_t nestingLimit) {
|
||||||
JsonParser parser(this, json);
|
JsonParser parser(this, json, nestingLimit);
|
||||||
return parser.parseObject();
|
return parser.parseObject();
|
||||||
}
|
}
|
||||||
|
88
test/JsonParser_NestingLimit_Tests.cpp
Normal file
88
test/JsonParser_NestingLimit_Tests.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <ArduinoJson/JsonArray.hpp>
|
||||||
|
#include <ArduinoJson/JsonObject.hpp>
|
||||||
|
#include <ArduinoJson/StaticJsonBuffer.hpp>
|
||||||
|
|
||||||
|
using namespace ArduinoJson;
|
||||||
|
|
||||||
|
class JsonParser_NestingLimit_Tests : public testing::Test {
|
||||||
|
protected:
|
||||||
|
void whenNestingLimitIs(uint8_t nestingLimit) {
|
||||||
|
_nestingLimit = nestingLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseArrayMustFail(const char *json) {
|
||||||
|
ASSERT_FALSE(tryParseArray(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseArrayMustSucceed(const char *json) {
|
||||||
|
ASSERT_TRUE(tryParseArray(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseObjectMustFail(const char *json) {
|
||||||
|
ASSERT_FALSE(tryParseObject(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseObjectMustSucceed(const char *json) {
|
||||||
|
ASSERT_TRUE(tryParseObject(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool tryParseArray(const char *json) {
|
||||||
|
StaticJsonBuffer<256> buffer;
|
||||||
|
char s[256];
|
||||||
|
strcpy(s, json);
|
||||||
|
return buffer.parseArray(s, _nestingLimit).success();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tryParseObject(const char *json) {
|
||||||
|
StaticJsonBuffer<256> buffer;
|
||||||
|
char s[256];
|
||||||
|
strcpy(s, json);
|
||||||
|
return buffer.parseObject(s, _nestingLimit).success();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t _nestingLimit;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(JsonParser_NestingLimit_Tests, ParseArrayWithNestingLimit0) {
|
||||||
|
whenNestingLimitIs(0);
|
||||||
|
parseArrayMustSucceed("[]");
|
||||||
|
parseArrayMustFail("[[]]");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_NestingLimit_Tests, ParseArrayWithNestingLimit1) {
|
||||||
|
whenNestingLimitIs(1);
|
||||||
|
parseArrayMustSucceed("[[]]");
|
||||||
|
parseArrayMustFail("[[[]]]");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_NestingLimit_Tests, ParseArrayWithNestingLimit2) {
|
||||||
|
whenNestingLimitIs(2);
|
||||||
|
parseArrayMustSucceed("[[[]]]");
|
||||||
|
parseArrayMustFail("[[[[]]]]");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_NestingLimit_Tests, ParseObjectWithNestingLimit0) {
|
||||||
|
whenNestingLimitIs(0);
|
||||||
|
parseObjectMustSucceed("{}");
|
||||||
|
parseObjectMustFail("{\"key\":{}}");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_NestingLimit_Tests, ParseObjectWithNestingLimit1) {
|
||||||
|
whenNestingLimitIs(1);
|
||||||
|
parseObjectMustSucceed("{\"key\":{}}");
|
||||||
|
parseObjectMustFail("{\"key\":{\"key\":{}}}");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_NestingLimit_Tests, ParseObjectWithNestingLimit2) {
|
||||||
|
whenNestingLimitIs(2);
|
||||||
|
parseObjectMustSucceed("{\"key\":{\"key\":{}}}");
|
||||||
|
parseObjectMustFail("{\"key\":{\"key\":{\"key\":{}}}}");
|
||||||
|
}
|
Reference in New Issue
Block a user