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

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