Просмотр исходного кода

Fix integer overflow in MsgPackDeserializer

Benoit Blanchon 1 год назад
Родитель
Сommit
208e7a3304

+ 10 - 1
extras/tests/MixedConfiguration/string_length_size_2.cpp

@@ -112,6 +112,15 @@ TEST_CASE("ARDUINOJSON_STRING_LENGTH_SIZE == 2") {
       REQUIRE(err == DeserializationError::NoMemory);
     }
 
+    // https://oss-fuzz.com/testcase?key=5354792971993088
+    SECTION("doesn't overflow if binary size == 0xFFFF") {
+      auto input = "\xc5\xff\xff"_s;
+
+      auto err = deserializeMsgPack(doc, input);
+
+      REQUIRE(err == DeserializationError::NoMemory);
+    }
+
     SECTION("returns Ok if extension size <= 65531") {
       auto input = "\xc8\xff\xfb\x01" + std::string(65531, '?');
 
@@ -120,7 +129,7 @@ TEST_CASE("ARDUINOJSON_STRING_LENGTH_SIZE == 2") {
       REQUIRE(err == DeserializationError::Ok);
     }
 
-    SECTION("returns NoMemory if binary size >= 65532") {
+    SECTION("returns NoMemory if extension size >= 65532") {
       auto input = "\xc8\xff\xfc\x01" + std::string(65532, '?');
 
       auto err = deserializeMsgPack(doc, input);

+ 17 - 0
extras/tests/MixedConfiguration/string_length_size_4.cpp

@@ -72,6 +72,23 @@ TEST_CASE("ARDUINOJSON_STRING_LENGTH_SIZE == 4") {
 
       REQUIRE(err == DeserializationError::Ok);
     }
+
+    // https://oss-fuzz.com/testcase?key=5354792971993088
+    SECTION("doesn't overflow if binary size == 0xFFFFFFFF") {
+      auto input = "\xc6\xff\xff\xff\xff"_s;
+
+      auto err = deserializeMsgPack(doc, input);
+
+      REQUIRE(err == DeserializationError::NoMemory);
+    }
+
+    SECTION("doesn't overflow if string size == 0xFFFFFFFF") {
+      auto input = "\xdb\xff\xff\xff\xff???????????????????"_s;
+
+      auto err = deserializeMsgPack(doc, input);
+
+      REQUIRE(err != DeserializationError::Ok);
+    }
   }
 
   SECTION("bin 32 deserialization") {

+ 4 - 2
src/ArduinoJson/Memory/StringNode.hpp

@@ -35,8 +35,10 @@ struct StringNode {
   static StringNode* create(size_t length, Allocator* allocator) {
     if (length > maxLength)
       return nullptr;
-    auto node = reinterpret_cast<StringNode*>(
-        allocator->allocate(sizeForLength(length)));
+    auto size = sizeForLength(length);
+    if (size < length)  // integer overflow
+      return nullptr;   // (not testable on 64-bit)
+    auto node = reinterpret_cast<StringNode*>(allocator->allocate(size));
     if (node) {
       node->length = length_type(length);
       node->references = 1;

+ 11 - 2
src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp

@@ -198,8 +198,13 @@ class MsgPackDeserializer {
       if (err)
         return err;
 
+      uint32_t size32 = 0;
       for (size_t i = 0; i < sizeBytes; i++)
-        size = (size << 8) | header[i + 1];
+        size32 = (size32 << 8) | header[i + 1];
+
+      size = size_t(size32);
+      if (size < size32)                        // integer overflow
+        return DeserializationError::NoMemory;  // (not testable on 32/64-bit)
     }
 
     // array 16, 32 and fixarray
@@ -366,7 +371,11 @@ class MsgPackDeserializer {
   DeserializationError::Code readRawString(VariantData* variant,
                                            const void* header,
                                            uint8_t headerSize, size_t n) {
-    char* p = stringBuffer_.reserve(headerSize + n);
+    auto totalSize = size_t(headerSize + n);
+    if (totalSize < n)                        // integer overflow
+      return DeserializationError::NoMemory;  // (not testable on 64-bit)
+
+    char* p = stringBuffer_.reserve(totalSize);
     if (!p)
       return DeserializationError::NoMemory;