Blame SOURCES/libxml2-2.9.13-CVE-2022-29824.patch

1d8b84
From ecc43dce8e2cd19f635841e788421d0f4bd72cce Mon Sep 17 00:00:00 2001
1d8b84
From: Nick Wellnhofer <wellnhofer@aevum.de>
1d8b84
Date: Tue, 8 Mar 2022 20:10:02 +0100
1d8b84
Subject: [PATCH] [CVE-2022-29824] Fix integer overflows in xmlBuf and
1d8b84
 xmlBuffer
1d8b84
1d8b84
In several places, the code handling string buffers didn't check for
1d8b84
integer overflow or used wrong types for buffer sizes. This could
1d8b84
result in out-of-bounds writes or other memory errors when working on
1d8b84
large, multi-gigabyte buffers.
1d8b84
1d8b84
Thanks to Felix Wilhelm for the report.
1d8b84
---
1d8b84
 buf.c  | 86 +++++++++++++++++++++++-----------------------------------
1d8b84
 tree.c | 72 ++++++++++++++++++------------------------------
1d8b84
 2 files changed, 61 insertions(+), 97 deletions(-)
1d8b84
1d8b84
diff --git a/buf.c b/buf.c
1d8b84
index 24368d37..40a5ee06 100644
1d8b84
--- a/buf.c
1d8b84
+++ b/buf.c
1d8b84
@@ -30,6 +30,10 @@
1d8b84
 #include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
1d8b84
 #include "buf.h"
1d8b84
 
1d8b84
+#ifndef SIZE_MAX
1d8b84
+#define SIZE_MAX ((size_t) -1)
1d8b84
+#endif
1d8b84
+
1d8b84
 #define WITH_BUFFER_COMPAT
1d8b84
 
1d8b84
 /**
1d8b84
@@ -156,6 +160,8 @@ xmlBufPtr
1d8b84
 xmlBufCreateSize(size_t size) {
1d8b84
     xmlBufPtr ret;
1d8b84
 
1d8b84
+    if (size == SIZE_MAX)
1d8b84
+        return(NULL);
1d8b84
     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
1d8b84
     if (ret == NULL) {
1d8b84
 	xmlBufMemoryError(NULL, "creating buffer");
1d8b84
@@ -166,8 +172,8 @@ xmlBufCreateSize(size_t size) {
1d8b84
     ret->error = 0;
1d8b84
     ret->buffer = NULL;
1d8b84
     ret->alloc = xmlBufferAllocScheme;
1d8b84
-    ret->size = (size ? size+2 : 0);         /* +1 for ending null */
1d8b84
-    ret->compat_size = (int) ret->size;
1d8b84
+    ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
1d8b84
+    ret->compat_size = (ret->size > INT_MAX ? INT_MAX : ret->size);
1d8b84
     if (ret->size){
1d8b84
         ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
1d8b84
         if (ret->content == NULL) {
1d8b84
@@ -442,23 +448,17 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
1d8b84
     CHECK_COMPAT(buf)
1d8b84
 
1d8b84
     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
1d8b84
-    if (buf->use + len < buf->size)
1d8b84
+    if (len < buf->size - buf->use)
1d8b84
         return(buf->size - buf->use);
1d8b84
+    if (len > SIZE_MAX - buf->use)
1d8b84
+        return(0);
1d8b84
 
1d8b84
-    /*
1d8b84
-     * Windows has a BIG problem on realloc timing, so we try to double
1d8b84
-     * the buffer size (if that's enough) (bug 146697)
1d8b84
-     * Apparently BSD too, and it's probably best for linux too
1d8b84
-     * On an embedded system this may be something to change
1d8b84
-     */
1d8b84
-#if 1
1d8b84
-    if (buf->size > (size_t) len)
1d8b84
-        size = buf->size * 2;
1d8b84
-    else
1d8b84
-        size = buf->use + len + 100;
1d8b84
-#else
1d8b84
-    size = buf->use + len + 100;
1d8b84
-#endif
1d8b84
+    if (buf->size > (size_t) len) {
1d8b84
+        size = buf->size > SIZE_MAX / 2 ? SIZE_MAX : buf->size * 2;
1d8b84
+    } else {
1d8b84
+        size = buf->use + len;
1d8b84
+        size = size > SIZE_MAX - 100 ? SIZE_MAX : size + 100;
1d8b84
+    }
1d8b84
 
1d8b84
     if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
1d8b84
         /*
1d8b84
@@ -744,7 +744,7 @@ xmlBufIsEmpty(const xmlBufPtr buf)
1d8b84
 int
1d8b84
 xmlBufResize(xmlBufPtr buf, size_t size)
1d8b84
 {
1d8b84
-    unsigned int newSize;
1d8b84
+    size_t newSize;
1d8b84
     xmlChar* rebuf = NULL;
1d8b84
     size_t start_buf;
1d8b84
 
1d8b84
@@ -772,9 +772,13 @@ xmlBufResize(xmlBufPtr buf, size_t size)
1d8b84
 	case XML_BUFFER_ALLOC_IO:
1d8b84
 	case XML_BUFFER_ALLOC_DOUBLEIT:
1d8b84
 	    /*take care of empty case*/
1d8b84
-	    newSize = (buf->size ? buf->size*2 : size + 10);
1d8b84
+            if (buf->size == 0) {
1d8b84
+                newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
1d8b84
+            } else {
1d8b84
+                newSize = buf->size;
1d8b84
+            }
1d8b84
 	    while (size > newSize) {
1d8b84
-	        if (newSize > UINT_MAX / 2) {
1d8b84
+	        if (newSize > SIZE_MAX / 2) {
1d8b84
 	            xmlBufMemoryError(buf, "growing buffer");
1d8b84
 	            return 0;
1d8b84
 	        }
1d8b84
@@ -782,15 +786,15 @@ xmlBufResize(xmlBufPtr buf, size_t size)
1d8b84
 	    }
1d8b84
 	    break;
1d8b84
 	case XML_BUFFER_ALLOC_EXACT:
1d8b84
-	    newSize = size+10;
1d8b84
+            newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
1d8b84
 	    break;
1d8b84
         case XML_BUFFER_ALLOC_HYBRID:
1d8b84
             if (buf->use < BASE_BUFFER_SIZE)
1d8b84
                 newSize = size;
1d8b84
             else {
1d8b84
-                newSize = buf->size * 2;
1d8b84
+                newSize = buf->size;
1d8b84
                 while (size > newSize) {
1d8b84
-                    if (newSize > UINT_MAX / 2) {
1d8b84
+                    if (newSize > SIZE_MAX / 2) {
1d8b84
                         xmlBufMemoryError(buf, "growing buffer");
1d8b84
                         return 0;
1d8b84
                     }
1d8b84
@@ -800,7 +804,7 @@ xmlBufResize(xmlBufPtr buf, size_t size)
1d8b84
             break;
1d8b84
 
1d8b84
 	default:
1d8b84
-	    newSize = size+10;
1d8b84
+            newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
1d8b84
 	    break;
1d8b84
     }
1d8b84
 
1d8b84
@@ -866,7 +870,7 @@ xmlBufResize(xmlBufPtr buf, size_t size)
1d8b84
  */
1d8b84
 int
1d8b84
 xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
1d8b84
-    unsigned int needSize;
1d8b84
+    size_t needSize;
1d8b84
 
1d8b84
     if ((str == NULL) || (buf == NULL) || (buf->error))
1d8b84
 	return -1;
1d8b84
@@ -888,8 +892,10 @@ xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
1d8b84
     if (len < 0) return -1;
1d8b84
     if (len == 0) return 0;
1d8b84
 
1d8b84
-    needSize = buf->use + len + 2;
1d8b84
-    if (needSize > buf->size){
1d8b84
+    if ((size_t) len >= buf->size - buf->use) {
1d8b84
+        if ((size_t) len >= SIZE_MAX - buf->use)
1d8b84
+            return(-1);
1d8b84
+        needSize = buf->use + len + 1;
1d8b84
 	if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
1d8b84
 	    /*
1d8b84
 	     * Used to provide parsing limits
1d8b84
@@ -1025,31 +1031,7 @@ xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
1d8b84
  */
1d8b84
 int
1d8b84
 xmlBufCCat(xmlBufPtr buf, const char *str) {
1d8b84
-    const char *cur;
1d8b84
-
1d8b84
-    if ((buf == NULL) || (buf->error))
1d8b84
-        return(-1);
1d8b84
-    CHECK_COMPAT(buf)
1d8b84
-    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
1d8b84
-    if (str == NULL) {
1d8b84
-#ifdef DEBUG_BUFFER
1d8b84
-        xmlGenericError(xmlGenericErrorContext,
1d8b84
-		"xmlBufCCat: str == NULL\n");
1d8b84
-#endif
1d8b84
-	return -1;
1d8b84
-    }
1d8b84
-    for (cur = str;*cur != 0;cur++) {
1d8b84
-        if (buf->use  + 10 >= buf->size) {
1d8b84
-            if (!xmlBufResize(buf, buf->use+10)){
1d8b84
-		xmlBufMemoryError(buf, "growing buffer");
1d8b84
-                return XML_ERR_NO_MEMORY;
1d8b84
-            }
1d8b84
-        }
1d8b84
-        buf->content[buf->use++] = *cur;
1d8b84
-    }
1d8b84
-    buf->content[buf->use] = 0;
1d8b84
-    UPDATE_COMPAT(buf)
1d8b84
-    return 0;
1d8b84
+    return xmlBufCat(buf, (const xmlChar *) str);
1d8b84
 }
1d8b84
 
1d8b84
 /**
1d8b84
diff --git a/tree.c b/tree.c
1d8b84
index 9d94aa42..86afb7d6 100644
1d8b84
--- a/tree.c
1d8b84
+++ b/tree.c
1d8b84
@@ -7104,6 +7104,8 @@ xmlBufferPtr
1d8b84
 xmlBufferCreateSize(size_t size) {
1d8b84
     xmlBufferPtr ret;
1d8b84
 
1d8b84
+    if (size >= UINT_MAX)
1d8b84
+        return(NULL);
1d8b84
     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
1d8b84
     if (ret == NULL) {
1d8b84
 	xmlTreeErrMemory("creating buffer");
1d8b84
@@ -7111,7 +7113,7 @@ xmlBufferCreateSize(size_t size) {
1d8b84
     }
1d8b84
     ret->use = 0;
1d8b84
     ret->alloc = xmlBufferAllocScheme;
1d8b84
-    ret->size = (size ? size+2 : 0);         /* +1 for ending null */
1d8b84
+    ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
1d8b84
     if (ret->size){
1d8b84
         ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
1d8b84
         if (ret->content == NULL) {
1d8b84
@@ -7171,6 +7173,8 @@ xmlBufferCreateStatic(void *mem, size_t size) {
1d8b84
 
1d8b84
     if ((mem == NULL) || (size == 0))
1d8b84
         return(NULL);
1d8b84
+    if (size > UINT_MAX)
1d8b84
+        return(NULL);
1d8b84
 
1d8b84
     ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
1d8b84
     if (ret == NULL) {
1d8b84
@@ -7318,28 +7322,23 @@ xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
1d8b84
  */
1d8b84
 int
1d8b84
 xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
1d8b84
-    int size;
1d8b84
+    unsigned int size;
1d8b84
     xmlChar *newbuf;
1d8b84
 
1d8b84
     if (buf == NULL) return(-1);
1d8b84
 
1d8b84
     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
1d8b84
-    if (len + buf->use < buf->size) return(0);
1d8b84
+    if (len < buf->size - buf->use)
1d8b84
+        return(0);
1d8b84
+    if (len > UINT_MAX - buf->use)
1d8b84
+        return(-1);
1d8b84
 
1d8b84
-    /*
1d8b84
-     * Windows has a BIG problem on realloc timing, so we try to double
1d8b84
-     * the buffer size (if that's enough) (bug 146697)
1d8b84
-     * Apparently BSD too, and it's probably best for linux too
1d8b84
-     * On an embedded system this may be something to change
1d8b84
-     */
1d8b84
-#if 1
1d8b84
-    if (buf->size > len)
1d8b84
-        size = buf->size * 2;
1d8b84
-    else
1d8b84
-        size = buf->use + len + 100;
1d8b84
-#else
1d8b84
-    size = buf->use + len + 100;
1d8b84
-#endif
1d8b84
+    if (buf->size > (size_t) len) {
1d8b84
+        size = buf->size > UINT_MAX / 2 ? UINT_MAX : buf->size * 2;
1d8b84
+    } else {
1d8b84
+        size = buf->use + len;
1d8b84
+        size = size > UINT_MAX - 100 ? UINT_MAX : size + 100;
1d8b84
+    }
1d8b84
 
1d8b84
     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
1d8b84
         size_t start_buf = buf->content - buf->contentIO;
1d8b84
@@ -7466,7 +7465,10 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size)
1d8b84
 	case XML_BUFFER_ALLOC_IO:
1d8b84
 	case XML_BUFFER_ALLOC_DOUBLEIT:
1d8b84
 	    /*take care of empty case*/
1d8b84
-	    newSize = (buf->size ? buf->size : size + 10);
1d8b84
+            if (buf->size == 0)
1d8b84
+                newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);
1d8b84
+            else
1d8b84
+                newSize = buf->size;
1d8b84
 	    while (size > newSize) {
1d8b84
 	        if (newSize > UINT_MAX / 2) {
1d8b84
 	            xmlTreeErrMemory("growing buffer");
1d8b84
@@ -7476,7 +7478,7 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size)
1d8b84
 	    }
1d8b84
 	    break;
1d8b84
 	case XML_BUFFER_ALLOC_EXACT:
1d8b84
-	    newSize = size+10;
1d8b84
+	    newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);;
1d8b84
 	    break;
1d8b84
         case XML_BUFFER_ALLOC_HYBRID:
1d8b84
             if (buf->use < BASE_BUFFER_SIZE)
1d8b84
@@ -7494,7 +7496,7 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size)
1d8b84
             break;
1d8b84
 
1d8b84
 	default:
1d8b84
-	    newSize = size+10;
1d8b84
+	    newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10);;
1d8b84
 	    break;
1d8b84
     }
1d8b84
 
1d8b84
@@ -7580,8 +7582,10 @@ xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
1d8b84
     if (len < 0) return -1;
1d8b84
     if (len == 0) return 0;
1d8b84
 
1d8b84
-    needSize = buf->use + len + 2;
1d8b84
-    if (needSize > buf->size){
1d8b84
+    if ((unsigned) len >= buf->size - buf->use) {
1d8b84
+        if ((unsigned) len >= UINT_MAX - buf->use)
1d8b84
+            return XML_ERR_NO_MEMORY;
1d8b84
+        needSize = buf->use + len + 1;
1d8b84
         if (!xmlBufferResize(buf, needSize)){
1d8b84
 	    xmlTreeErrMemory("growing buffer");
1d8b84
             return XML_ERR_NO_MEMORY;
1d8b84
@@ -7694,29 +7698,7 @@ xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
1d8b84
  */
1d8b84
 int
1d8b84
 xmlBufferCCat(xmlBufferPtr buf, const char *str) {
1d8b84
-    const char *cur;
1d8b84
-
1d8b84
-    if (buf == NULL)
1d8b84
-        return(-1);
1d8b84
-    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
1d8b84
-    if (str == NULL) {
1d8b84
-#ifdef DEBUG_BUFFER
1d8b84
-        xmlGenericError(xmlGenericErrorContext,
1d8b84
-		"xmlBufferCCat: str == NULL\n");
1d8b84
-#endif
1d8b84
-	return -1;
1d8b84
-    }
1d8b84
-    for (cur = str;*cur != 0;cur++) {
1d8b84
-        if (buf->use  + 10 >= buf->size) {
1d8b84
-            if (!xmlBufferResize(buf, buf->use+10)){
1d8b84
-		xmlTreeErrMemory("growing buffer");
1d8b84
-                return XML_ERR_NO_MEMORY;
1d8b84
-            }
1d8b84
-        }
1d8b84
-        buf->content[buf->use++] = *cur;
1d8b84
-    }
1d8b84
-    buf->content[buf->use] = 0;
1d8b84
-    return 0;
1d8b84
+    return xmlBufferCat(buf, (const xmlChar *) str);
1d8b84
 }
1d8b84
 
1d8b84
 /**
1d8b84
-- 
1d8b84
2.36.0
1d8b84