mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-11-01 08:48:30 +01:00 
			
		
		
		
	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 { | ||||
|  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(); | ||||
|   JsonObject &parseObject(); | ||||
| @@ -33,6 +34,7 @@ class JsonParser { | ||||
|  | ||||
|   JsonBuffer *_buffer; | ||||
|   char *_ptr; | ||||
|   uint8_t _nestingLimit; | ||||
| }; | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -19,9 +19,11 @@ class JsonBuffer { | ||||
|   JsonArray &createArray(); | ||||
|   JsonObject &createObject(); | ||||
|  | ||||
|   JsonArray &parseArray(char *json); | ||||
|   JsonObject &parseObject(char *json); | ||||
|   JsonArray &parseArray(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); | ||||
|   JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT); | ||||
|  | ||||
|   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) { | ||||
|   if (_nestingLimit == 0) return; | ||||
|   _nestingLimit--; | ||||
|  | ||||
|   skipSpaces(); | ||||
|  | ||||
|   switch (*_ptr) { | ||||
| @@ -79,6 +82,8 @@ void JsonParser::parseAnythingTo(JsonVariant &destination) { | ||||
|       destination = parseString(); | ||||
|       break; | ||||
|   } | ||||
|  | ||||
|   _nestingLimit++; | ||||
| } | ||||
|  | ||||
| JsonArray &JsonParser::parseArray() { | ||||
|   | ||||
| @@ -26,12 +26,12 @@ JsonObject &JsonBuffer::createObject() { | ||||
|   return JsonObject::invalid(); | ||||
| } | ||||
|  | ||||
| JsonArray &JsonBuffer::parseArray(char *json) { | ||||
|   JsonParser parser(this, json); | ||||
| JsonArray &JsonBuffer::parseArray(char *json, uint8_t nestingLimit) { | ||||
|   JsonParser parser(this, json, nestingLimit); | ||||
|   return parser.parseArray(); | ||||
| } | ||||
|  | ||||
| JsonObject &JsonBuffer::parseObject(char *json) { | ||||
|   JsonParser parser(this, json); | ||||
| JsonObject &JsonBuffer::parseObject(char *json, uint8_t nestingLimit) { | ||||
|   JsonParser parser(this, json, nestingLimit); | ||||
|   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