Procházet zdrojové kódy

HPCC-24509 Avoid core in esp when row length exceeds maxlength

Signed-off-by: Gavin Halliday <gavin.halliday@lexisnexis.com>
Gavin Halliday před 4 roky
rodič
revize
b329cb923b

+ 1 - 0
common/fileview2/fverror.hpp

@@ -56,6 +56,7 @@
 #define FVERR_PluginMismatch                    6728
 #define FVERR_RowTooLarge                       6729
 #define FVERR_CouldNotProcessSchema             6730
+#define FVERR_MaxLengthExceeded                 6731
 
 #define FVERR_CouldNotResolveX_Text             "Could not resolve file '%s' in DFS"
 #define FVERR_NoRecordDescription_Text          "DFS did not contain a record description for '%s'"

+ 20 - 0
common/fileview2/fvsource.cpp

@@ -16,6 +16,7 @@
 ############################################################################## */
 
 #include "platform.h"
+#include "limits.h"
 #include "jliball.hpp"
 #include "eclrtl.hpp"
 #include "rtlds_imp.hpp"
@@ -594,6 +595,18 @@ void DataSourceMetaData::serialize(MemoryBuffer & buffer) const
 
 size32_t DataSourceMetaData::getRecordSize(const void *rec)
 {
+    return calcRecordSize(UINT_MAX, rec);
+}
+
+static void checkReadPastEnd(size32_t offset, size32_t delta, size32_t maxLength)
+{
+    //Check for reading past the end of the buffer, or for the size wrapping 32bits.
+    if ((offset > maxLength) || (offset + delta < offset))
+        throw makeStringException(FVERR_MaxLengthExceeded, "Read past the end of a variable size block (MAXLENGTH exceeded)");
+}
+
+size32_t DataSourceMetaData::calcRecordSize(size32_t maxLength, const void *rec)
+{
     if (isStoredFixedWidth)
         return minRecordSize;
     if (!rec)
@@ -616,21 +629,27 @@ size32_t DataSourceMetaData::getRecordSize(const void *rec)
             case type_string:
             case type_table:
             case type_groupedtable:
+                checkReadPastEnd(curOffset, sizeof(unsigned), maxLength);
                 size = *((unsigned *)cur) + sizeof(unsigned);
                 break;
             case type_set:
+                checkReadPastEnd(curOffset, sizeof(bool) + sizeof(unsigned), maxLength);
                 size = *((unsigned *)(cur + sizeof(bool))) + sizeof(unsigned) + sizeof(bool);
                 break;
             case type_qstring:
+                checkReadPastEnd(curOffset, sizeof(unsigned), maxLength);
                 size = rtlQStrSize(*((unsigned *)cur)) + sizeof(unsigned);
                 break;
             case type_unicode:
+                checkReadPastEnd(curOffset, sizeof(unsigned), maxLength);
                 size = *((unsigned *)cur)*2 + sizeof(unsigned);
                 break;
             case type_utf8:
+                checkReadPastEnd(curOffset, sizeof(unsigned), maxLength);
                 size = sizeof(unsigned) + rtlUtf8Size(*(unsigned *)cur, cur+sizeof(unsigned));
                 break;
             case type_varstring:
+                //buffer overflow checking for the following will wait until code is reimplemented
                 size = strlen((char *)cur)+1;
                 break;
             case type_varunicode:
@@ -660,6 +679,7 @@ size32_t DataSourceMetaData::getRecordSize(const void *rec)
         else
             bitsRemaining = 0;
 
+        checkReadPastEnd(curOffset, size, maxLength);
         curOffset += size;
     }
     return curOffset;

+ 2 - 1
common/fileview2/fvsource.ipp

@@ -137,12 +137,13 @@ public:
     virtual size32_t getFixedSize() const;
     virtual size32_t getRecordSize(unsigned maxLength, const void *rec)
     {
-        return getRecordSize(rec);
+        return calcRecordSize(maxLength, rec);
     }
     virtual size32_t getMinRecordSize() const;
 
 protected:
     void addSimpleField(const char * name, const char * xpath, ITypeInfo * type, unsigned flag=FVFFnone);
+    size32_t calcRecordSize(unsigned maxLength, const void *rec);
     void gatherFields(IHqlExpression * expr, bool isConditional, bool *pMixedContent);
     void gatherChildFields(IHqlExpression * expr, bool isConditional, bool *pMixedContent);
     void gatherAttributes();