From cf9bf2d9136a9d1c2131f83aa493bb03f36849ab Mon Sep 17 00:00:00 2001
From: Niels Lohmann <niels.lohmann@gmail.com>
Date: Sun, 1 Jan 2017 15:28:01 +0100
Subject: [PATCH] :ambulance: fix for #411 and #412

---
 src/json.hpp                 | 11 +++-----
 src/json.hpp.re2c            | 11 +++-----
 test/src/unit-regression.cpp | 53 ++++++++++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+), 14 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index f8d948f1..5dc8e67c 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -7135,13 +7135,10 @@ class basic_json
     */
     static basic_json from_cbor_internal(const std::vector<uint8_t>& v, size_t& idx)
     {
-        // make sure reading 1 byte is safe
-        check_length(v.size(), 1, idx);
-
         // store and increment index
         const size_t current_idx = idx++;
 
-        switch (v[current_idx])
+        switch (v.at(current_idx))
         {
             // Integer 0x00..0x17 (0..23)
             case 0x00:
@@ -7322,7 +7319,7 @@ class basic_json
             case 0x7f: // UTF-8 string (indefinite length)
             {
                 std::string result;
-                while (v[idx] != 0xff)
+                while (v.at(idx) != 0xff)
                 {
                     string_t s = from_cbor_internal(v, idx);
                     result += s;
@@ -7418,7 +7415,7 @@ class basic_json
             case 0x9f: // array (indefinite length)
             {
                 basic_json result = value_t::array;
-                while (v[idx] != 0xff)
+                while (v.at(idx) != 0xff)
                 {
                     result.push_back(from_cbor_internal(v, idx));
                 }
@@ -7518,7 +7515,7 @@ class basic_json
             case 0xbf: // map (indefinite length)
             {
                 basic_json result = value_t::object;
-                while (v[idx] != 0xff)
+                while (v.at(idx) != 0xff)
                 {
                     std::string key = from_cbor_internal(v, idx);
                     result[key] = from_cbor_internal(v, idx);
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 2faf3858..49bccb02 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -7135,13 +7135,10 @@ class basic_json
     */
     static basic_json from_cbor_internal(const std::vector<uint8_t>& v, size_t& idx)
     {
-        // make sure reading 1 byte is safe
-        check_length(v.size(), 1, idx);
-
         // store and increment index
         const size_t current_idx = idx++;
 
-        switch (v[current_idx])
+        switch (v.at(current_idx))
         {
             // Integer 0x00..0x17 (0..23)
             case 0x00:
@@ -7322,7 +7319,7 @@ class basic_json
             case 0x7f: // UTF-8 string (indefinite length)
             {
                 std::string result;
-                while (v[idx] != 0xff)
+                while (v.at(idx) != 0xff)
                 {
                     string_t s = from_cbor_internal(v, idx);
                     result += s;
@@ -7418,7 +7415,7 @@ class basic_json
             case 0x9f: // array (indefinite length)
             {
                 basic_json result = value_t::array;
-                while (v[idx] != 0xff)
+                while (v.at(idx) != 0xff)
                 {
                     result.push_back(from_cbor_internal(v, idx));
                 }
@@ -7518,7 +7515,7 @@ class basic_json
             case 0xbf: // map (indefinite length)
             {
                 basic_json result = value_t::object;
-                while (v[idx] != 0xff)
+                while (v.at(idx) != 0xff)
                 {
                     std::string key = from_cbor_internal(v, idx);
                     result[key] = from_cbor_internal(v, idx);
diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp
index 421a386c..89b27e0e 100644
--- a/test/src/unit-regression.cpp
+++ b/test/src/unit-regression.cpp
@@ -610,4 +610,57 @@ TEST_CASE("regression tests")
         CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range);
         CHECK_THROWS_AS(json::from_msgpack(vec2), std::out_of_range);
     }
+
+    SECTION("issue #411 - Heap-buffer-overflow (OSS-Fuzz issue 366)")
+    {
+        // original test case: empty UTF-8 string (indefinite length)
+        std::vector<uint8_t> vec1 {0x7f};
+        CHECK_THROWS_AS(json::from_cbor(vec1), std::out_of_range);
+
+        // related test case: empty array (indefinite length)
+        std::vector<uint8_t> vec2 {0x9f};
+        CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range);
+
+        // related test case: empty map (indefinite length)
+        std::vector<uint8_t> vec3 {0xbf};
+        CHECK_THROWS_AS(json::from_cbor(vec3), std::out_of_range);
+    }
+
+    SECTION("issue #412 - Heap-buffer-overflow (OSS-Fuzz issue 367)")
+    {
+        // original test case
+        std::vector<uint8_t> vec
+        {
+            0xab, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+            0x98, 0x98, 0x98, 0x98, 0x98, 0x00, 0x00, 0x00,
+            0x60, 0xab, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+            0x98, 0x98, 0x98, 0x98, 0x98, 0x00, 0x00, 0x00,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0xa0, 0x9f,
+            0x9f, 0x97, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+            0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60
+        };
+        CHECK_THROWS_AS(json::from_cbor(vec), std::out_of_range);
+
+        // related test case: nonempty UTF-8 string (indefinite length)
+        std::vector<uint8_t> vec1 {0x7f, 0x61, 0x61};
+        CHECK_THROWS_AS(json::from_cbor(vec1), std::out_of_range);
+
+        // related test case: nonempty array (indefinite length)
+        std::vector<uint8_t> vec2 {0x9f, 0x01};
+        CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range);
+
+        // related test case: nonempty map (indefinite length)
+        std::vector<uint8_t> vec3 {0xbf, 0x61, 0x61, 0x01};
+        CHECK_THROWS_AS(json::from_cbor(vec3), std::out_of_range);
+    }
 }