diff --git a/iotdb-client/client-cpp/src/main/ColumnDecoder.cpp b/iotdb-client/client-cpp/src/main/ColumnDecoder.cpp index e45cb49409a0d..32f29d876f368 100644 --- a/iotdb-client/client-cpp/src/main/ColumnDecoder.cpp +++ b/iotdb-client/client-cpp/src/main/ColumnDecoder.cpp @@ -151,6 +151,9 @@ std::unique_ptr BinaryArrayColumnDecoder::readColumn( if (!nullIndicators.empty() && nullIndicators[i]) continue; int32_t length = buffer.getInt(); + if (length < 0) { + throw IoTDBException("BinaryArrayColumnDecoder: negative TEXT length"); + } std::vector value(length); for (int32_t j = 0; j < length; j++) { diff --git a/iotdb-client/client-cpp/src/main/Common.cpp b/iotdb-client/client-cpp/src/main/Common.cpp index 56dc96830571c..f7eeb2a218e49 100644 --- a/iotdb-client/client-cpp/src/main/Common.cpp +++ b/iotdb-client/client-cpp/src/main/Common.cpp @@ -293,6 +293,10 @@ double MyStringBuffer::getDouble() { } char MyStringBuffer::getChar() { + if (pos >= str.size()) { + throw IoTDBException("MyStringBuffer::getChar: read past end (pos=" + std::to_string(pos) + + ", size=" + std::to_string(str.size()) + ")"); + } return str[pos++]; } @@ -301,8 +305,16 @@ bool MyStringBuffer::getBool() { } std::string MyStringBuffer::getString() { - size_t len = getInt(); - size_t tmpPos = pos; + const int lenInt = getInt(); + if (lenInt < 0) { + throw IoTDBException("MyStringBuffer::getString: negative length"); + } + const size_t len = static_cast(lenInt); + if (pos > str.size() || len > str.size() - pos) { + throw IoTDBException("MyStringBuffer::getString: length exceeds buffer (pos=" + std::to_string(pos) + + ", len=" + std::to_string(len) + ", size=" + std::to_string(str.size()) + ")"); + } + const size_t tmpPos = pos; pos += len; return str.substr(tmpPos, len); } @@ -351,6 +363,10 @@ void MyStringBuffer::checkBigEndian() { } const char* MyStringBuffer::getOrderedByte(size_t len) { + if (pos > str.size() || len > str.size() - pos) { + throw IoTDBException("MyStringBuffer::getOrderedByte: read past end (pos=" + std::to_string(pos) + + ", len=" + std::to_string(len) + ", size=" + std::to_string(str.size()) + ")"); + } const char* p = nullptr; if (isBigEndian) { p = str.c_str() + pos; diff --git a/iotdb-client/client-cpp/src/main/TsBlock.cpp b/iotdb-client/client-cpp/src/main/TsBlock.cpp index 7c2bac272a601..92afbef3f270f 100644 --- a/iotdb-client/client-cpp/src/main/TsBlock.cpp +++ b/iotdb-client/client-cpp/src/main/TsBlock.cpp @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +#include #include #include #include "TsBlock.h" @@ -34,6 +35,14 @@ std::shared_ptr TsBlock::deserialize(const std::string& data) { // Read value column count int32_t valueColumnCount = buffer.getInt(); + if (valueColumnCount < 0) { + throw IoTDBException("TsBlock::deserialize: negative valueColumnCount"); + } + const int64_t minHeaderBytes = + 9LL + 2LL * static_cast(valueColumnCount); + if (minHeaderBytes > static_cast(data.size())) { + throw IoTDBException("TsBlock::deserialize: truncated header"); + } // Read value column data types std::vector valueColumnDataTypes(valueColumnCount); @@ -43,6 +52,9 @@ std::shared_ptr TsBlock::deserialize(const std::string& data) { // Read position count int32_t positionCount = buffer.getInt(); + if (positionCount < 0) { + throw IoTDBException("TsBlock::deserialize: negative positionCount"); + } // Read column encodings std::vector columnEncodings(valueColumnCount + 1); diff --git a/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp b/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp index af7f13855a4b7..c5e6e9060832d 100644 --- a/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp +++ b/iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp @@ -20,6 +20,7 @@ #include "catch.hpp" #include "Session.h" #include "SessionBuilder.h" +#include "TsBlock.h" using namespace std; @@ -858,4 +859,10 @@ TEST_CASE("UrlUtils - parseTEndPointIpv4AndIpv6Url", "[UrlUtils]") { REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("localhost:0"), "localhost", 0); REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("127.0.0.1:65535"), "127.0.0.1", 65535); } +} + +TEST_CASE("TsBlock deserialize rejects truncated malicious payload", "[TsBlockDeserialize]") { + std::string data(18, '\0'); + data[3] = '\x10'; + REQUIRE_THROWS_AS(TsBlock::deserialize(data), IoTDBException); } \ No newline at end of file