Blame SOURCES/expat-2.2.5-Detect-and-prevent-integer-overflow-in-XML_GetBuffer.patch

83eb0d
commit 22fe2da8e2bc0625d3c492f42d6b716adb36d5c2
83eb0d
Author: Tomas Korbar <tkorbar@redhat.com>
83eb0d
Date:   Mon Feb 14 12:09:42 2022 +0100
83eb0d
83eb0d
    CVE-2022-23852
83eb0d
83eb0d
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
83eb0d
index 85ee0a8..4552680 100644
83eb0d
--- a/lib/xmlparse.c
83eb0d
+++ b/lib/xmlparse.c
83eb0d
@@ -161,6 +161,9 @@ typedef char ICHAR;
83eb0d
 /* Round up n to be a multiple of sz, where sz is a power of 2. */
83eb0d
 #define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
83eb0d
 
83eb0d
+/* Do safe (NULL-aware) pointer arithmetic */
83eb0d
+#define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0)
83eb0d
+
83eb0d
 /* Handle the case where memmove() doesn't exist. */
83eb0d
 #ifndef HAVE_MEMMOVE
83eb0d
 #ifdef HAVE_BCOPY
83eb0d
@@ -2026,39 +2029,54 @@ XML_GetBuffer(XML_Parser parser, int len)
83eb0d
   default: ;
83eb0d
   }
83eb0d
 
83eb0d
-  if (len > parser->m_bufferLim - parser->m_bufferEnd) {
83eb0d
-#ifdef XML_CONTEXT_BYTES
83eb0d
+  if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)) {
83eb0d
     int keep;
83eb0d
-#endif  /* defined XML_CONTEXT_BYTES */
83eb0d
     /* Do not invoke signed arithmetic overflow: */
83eb0d
-    int neededSize = (int) ((unsigned)len + (unsigned)(parser->m_bufferEnd - parser->m_bufferPtr));
83eb0d
+    int neededSize = (int)((unsigned)len
83eb0d
+                           + (unsigned)EXPAT_SAFE_PTR_DIFF(
83eb0d
+                               parser->m_bufferEnd, parser->m_bufferPtr));
83eb0d
     if (neededSize < 0) {
83eb0d
       parser->m_errorCode = XML_ERROR_NO_MEMORY;
83eb0d
       return NULL;
83eb0d
     }
83eb0d
-#ifdef XML_CONTEXT_BYTES
83eb0d
-    keep = (int)(parser->m_bufferPtr - parser->m_buffer);
83eb0d
+
83eb0d
+    keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
83eb0d
     if (keep > XML_CONTEXT_BYTES)
83eb0d
       keep = XML_CONTEXT_BYTES;
83eb0d
+    /* Detect and prevent integer overflow */
83eb0d
+    if (keep > INT_MAX - neededSize) {
83eb0d
+      parser->m_errorCode = XML_ERROR_NO_MEMORY;
83eb0d
+      return NULL;
83eb0d
+    }
83eb0d
     neededSize += keep;
83eb0d
-#endif  /* defined XML_CONTEXT_BYTES */
83eb0d
-    if (neededSize  <= parser->m_bufferLim - parser->m_buffer) {
83eb0d
+    if (neededSize
83eb0d
+        <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
83eb0d
 #ifdef XML_CONTEXT_BYTES
83eb0d
-      if (keep < parser->m_bufferPtr - parser->m_buffer) {
83eb0d
-        int offset = (int)(parser->m_bufferPtr - parser->m_buffer) - keep;
83eb0d
-        memmove(parser->m_buffer, &parser->m_buffer[offset], parser->m_bufferEnd - parser->m_bufferPtr + keep);
83eb0d
+      if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) {
83eb0d
+        int offset
83eb0d
+            = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)
83eb0d
+              - keep;
83eb0d
+        /* The buffer pointers cannot be NULL here; we have at least some bytes
83eb0d
+         * in the buffer */
83eb0d
+        memmove(parser->m_buffer, &parser->m_buffer[offset],
83eb0d
+                parser->m_bufferEnd - parser->m_bufferPtr + keep);
83eb0d
         parser->m_bufferEnd -= offset;
83eb0d
         parser->m_bufferPtr -= offset;
83eb0d
       }
83eb0d
 #else
83eb0d
-      memmove(parser->m_buffer, parser->m_bufferPtr, parser->m_bufferEnd - parser->m_bufferPtr);
83eb0d
-      parser->m_bufferEnd = parser->m_buffer + (parser->m_bufferEnd - parser->m_bufferPtr);
83eb0d
-      parser->m_bufferPtr = parser->m_buffer;
83eb0d
-#endif  /* not defined XML_CONTEXT_BYTES */
83eb0d
-    }
83eb0d
-    else {
83eb0d
+      if (parser->m_buffer && parser->m_bufferPtr) {
83eb0d
+        memmove(parser->m_buffer, parser->m_bufferPtr,
83eb0d
+                EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
83eb0d
+        parser->m_bufferEnd
83eb0d
+            = parser->m_buffer
83eb0d
+              + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
83eb0d
+        parser->m_bufferPtr = parser->m_buffer;
83eb0d
+      }
83eb0d
+#endif /* not defined XML_CONTEXT_BYTES */
83eb0d
+    } else {
83eb0d
       char *newBuf;
83eb0d
-      int bufferSize = (int)(parser->m_bufferLim - parser->m_bufferPtr);
83eb0d
+      int bufferSize
83eb0d
+          = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferPtr);
83eb0d
       if (bufferSize == 0)
83eb0d
         bufferSize = INIT_BUFFER_SIZE;
83eb0d
       do {
83eb0d
@@ -2077,25 +2095,33 @@ XML_GetBuffer(XML_Parser parser, int len)
83eb0d
       parser->m_bufferLim = newBuf + bufferSize;
83eb0d
 #ifdef XML_CONTEXT_BYTES
83eb0d
       if (parser->m_bufferPtr) {
83eb0d
-        int keep = (int)(parser->m_bufferPtr - parser->m_buffer);
83eb0d
-        if (keep > XML_CONTEXT_BYTES)
83eb0d
-          keep = XML_CONTEXT_BYTES;
83eb0d
-        memcpy(newBuf, &parser->m_bufferPtr[-keep], parser->m_bufferEnd - parser->m_bufferPtr + keep);
83eb0d
+        memcpy(newBuf, &parser->m_bufferPtr[-keep],
83eb0d
+               EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
83eb0d
+                   + keep);
83eb0d
         FREE(parser, parser->m_buffer);
83eb0d
         parser->m_buffer = newBuf;
83eb0d
-        parser->m_bufferEnd = parser->m_buffer + (parser->m_bufferEnd - parser->m_bufferPtr) + keep;
83eb0d
+        parser->m_bufferEnd
83eb0d
+            = parser->m_buffer
83eb0d
+              + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
83eb0d
+              + keep;
83eb0d
         parser->m_bufferPtr = parser->m_buffer + keep;
83eb0d
-      }
83eb0d
-      else {
83eb0d
-        parser->m_bufferEnd = newBuf + (parser->m_bufferEnd - parser->m_bufferPtr);
83eb0d
+      } else {
83eb0d
+        /* This must be a brand new buffer with no data in it yet */
83eb0d
+        parser->m_bufferEnd = newBuf;
83eb0d
         parser->m_bufferPtr = parser->m_buffer = newBuf;
83eb0d
       }
83eb0d
 #else
83eb0d
       if (parser->m_bufferPtr) {
83eb0d
-        memcpy(newBuf, parser->m_bufferPtr, parser->m_bufferEnd - parser->m_bufferPtr);
83eb0d
+        memcpy(newBuf, parser->m_bufferPtr,
83eb0d
+               EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
83eb0d
         FREE(parser, parser->m_buffer);
83eb0d
+        parser->m_bufferEnd
83eb0d
+            = newBuf
83eb0d
+              + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
83eb0d
+      } else {
83eb0d
+        /* This must be a brand new buffer with no data in it yet */
83eb0d
+        parser->m_bufferEnd = newBuf;
83eb0d
       }
83eb0d
-      parser->m_bufferEnd = newBuf + (parser->m_bufferEnd - parser->m_bufferPtr);
83eb0d
       parser->m_bufferPtr = parser->m_buffer = newBuf;
83eb0d
 #endif  /* not defined XML_CONTEXT_BYTES */
83eb0d
     }
83eb0d
diff --git a/tests/runtests.c b/tests/runtests.c
83eb0d
index e1f1ad1..ecc6f47 100644
83eb0d
--- a/tests/runtests.c
83eb0d
+++ b/tests/runtests.c
83eb0d
@@ -4116,6 +4116,31 @@ START_TEST(test_get_buffer_2)
83eb0d
 }
83eb0d
 END_TEST
83eb0d
 
83eb0d
+/* Test for signed integer overflow CVE-2022-23852 */
83eb0d
+#if defined(XML_CONTEXT_BYTES)
83eb0d
+START_TEST(test_get_buffer_3_overflow) {
83eb0d
+  XML_Parser parser = XML_ParserCreate(NULL);
83eb0d
+  assert(parser != NULL);
83eb0d
+
83eb0d
+  const char *const text = "\n";
83eb0d
+  const int expectedKeepValue = (int)strlen(text);
83eb0d
+
83eb0d
+  // After this call, variable "keep" in XML_GetBuffer will
83eb0d
+  // have value expectedKeepValue
83eb0d
+  if (XML_Parse(parser, text, (int)strlen(text), XML_FALSE /* isFinal */)
83eb0d
+      == XML_STATUS_ERROR)
83eb0d
+    xml_failure(parser);
83eb0d
+
83eb0d
+  assert(expectedKeepValue > 0);
83eb0d
+  if (XML_GetBuffer(parser, INT_MAX - expectedKeepValue + 1) != NULL)
83eb0d
+    fail("enlarging buffer not failed");
83eb0d
+
83eb0d
+  XML_ParserFree(parser);
83eb0d
+}
83eb0d
+END_TEST
83eb0d
+#endif // defined(XML_CONTEXT_BYTES)
83eb0d
+
83eb0d
+
83eb0d
 /* Test position information macros */
83eb0d
 START_TEST(test_byte_info_at_end)
83eb0d
 {
83eb0d
@@ -12117,6 +12142,9 @@ make_suite(void)
83eb0d
     tcase_add_test(tc_basic, test_empty_parse);
83eb0d
     tcase_add_test(tc_basic, test_get_buffer_1);
83eb0d
     tcase_add_test(tc_basic, test_get_buffer_2);
83eb0d
+#if defined(XML_CONTEXT_BYTES)
83eb0d
+    tcase_add_test(tc_basic, test_get_buffer_3_overflow);
83eb0d
+#endif
83eb0d
     tcase_add_test(tc_basic, test_byte_info_at_end);
83eb0d
     tcase_add_test(tc_basic, test_byte_info_at_error);
83eb0d
     tcase_add_test(tc_basic, test_byte_info_at_cdata);