1From 9f93e8036e842329863bf20395b8fb8f73834d9e Mon Sep 17 00:00:00 2001 2From: Sebastian Pipping <sebastian@pipping.org> 3Date: Thu, 30 Dec 2021 22:46:03 +0100 4Subject: [PATCH] lib: Prevent integer overflow at multiple places 5 (CVE-2022-22822 to CVE-2022-22827) 6 7The involved functions are: 8- addBinding (CVE-2022-22822) 9- build_model (CVE-2022-22823) 10- defineAttribute (CVE-2022-22824) 11- lookup (CVE-2022-22825) 12- nextScaffoldPart (CVE-2022-22826) 13- storeAtts (CVE-2022-22827) 14--- 15 lib/xmlparse.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++- 16 1 file changed, 151 insertions(+), 2 deletions(-) 17 18diff --git a/lib/xmlparse.c b/lib/xmlparse.c 19index 8f24312..575e73e 100644 20--- a/lib/xmlparse.c 21+++ b/lib/xmlparse.c 22@@ -3261,13 +3261,38 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, 23 24 /* get the attributes from the tokenizer */ 25 n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts); 26+ 27+ /* Detect and prevent integer overflow */ 28+ if (n > INT_MAX - nDefaultAtts) { 29+ return XML_ERROR_NO_MEMORY; 30+ } 31+ 32 if (n + nDefaultAtts > parser->m_attsSize) { 33 int oldAttsSize = parser->m_attsSize; 34 ATTRIBUTE *temp; 35 #ifdef XML_ATTR_INFO 36 XML_AttrInfo *temp2; 37 #endif 38+ 39+ /* Detect and prevent integer overflow */ 40+ if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE) 41+ || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) { 42+ return XML_ERROR_NO_MEMORY; 43+ } 44+ 45 parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; 46+ 47+ /* Detect and prevent integer overflow. 48+ * The preprocessor guard addresses the "always false" warning 49+ * from -Wtype-limits on platforms where 50+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ 51+#if UINT_MAX >= SIZE_MAX 52+ if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) { 53+ parser->m_attsSize = oldAttsSize; 54+ return XML_ERROR_NO_MEMORY; 55+ } 56+#endif 57+ 58 temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts, 59 parser->m_attsSize * sizeof(ATTRIBUTE)); 60 if (temp == NULL) { 61@@ -3276,6 +3301,17 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, 62 } 63 parser->m_atts = temp; 64 #ifdef XML_ATTR_INFO 65+ /* Detect and prevent integer overflow. 66+ * The preprocessor guard addresses the "always false" warning 67+ * from -Wtype-limits on platforms where 68+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ 69+# if UINT_MAX >= SIZE_MAX 70+ if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) { 71+ parser->m_attsSize = oldAttsSize; 72+ return XML_ERROR_NO_MEMORY; 73+ } 74+# endif 75+ 76 temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo, 77 parser->m_attsSize * sizeof(XML_AttrInfo)); 78 if (temp2 == NULL) { 79@@ -3610,9 +3646,31 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, 80 tagNamePtr->prefixLen = prefixLen; 81 for (i = 0; localPart[i++];) 82 ; /* i includes null terminator */ 83+ 84+ /* Detect and prevent integer overflow */ 85+ if (binding->uriLen > INT_MAX - prefixLen 86+ || i > INT_MAX - (binding->uriLen + prefixLen)) { 87+ return XML_ERROR_NO_MEMORY; 88+ } 89+ 90 n = i + binding->uriLen + prefixLen; 91 if (n > binding->uriAlloc) { 92 TAG *p; 93+ 94+ /* Detect and prevent integer overflow */ 95+ if (n > INT_MAX - EXPAND_SPARE) { 96+ return XML_ERROR_NO_MEMORY; 97+ } 98+ /* Detect and prevent integer overflow. 99+ * The preprocessor guard addresses the "always false" warning 100+ * from -Wtype-limits on platforms where 101+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ 102+#if UINT_MAX >= SIZE_MAX 103+ if ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { 104+ return XML_ERROR_NO_MEMORY; 105+ } 106+#endif 107+ 108 uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char)); 109 if (! uri) 110 return XML_ERROR_NO_MEMORY; 111@@ -3708,6 +3766,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, 112 if (parser->m_freeBindingList) { 113 b = parser->m_freeBindingList; 114 if (len > b->uriAlloc) { 115+ /* Detect and prevent integer overflow */ 116+ if (len > INT_MAX - EXPAND_SPARE) { 117+ return XML_ERROR_NO_MEMORY; 118+ } 119+ 120+ /* Detect and prevent integer overflow. 121+ * The preprocessor guard addresses the "always false" warning 122+ * from -Wtype-limits on platforms where 123+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ 124+#if UINT_MAX >= SIZE_MAX 125+ if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { 126+ return XML_ERROR_NO_MEMORY; 127+ } 128+#endif 129+ 130 XML_Char *temp = (XML_Char *)REALLOC( 131 parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); 132 if (temp == NULL) 133@@ -3720,6 +3793,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, 134 b = (BINDING *)MALLOC(parser, sizeof(BINDING)); 135 if (! b) 136 return XML_ERROR_NO_MEMORY; 137+ 138+ /* Detect and prevent integer overflow */ 139+ if (len > INT_MAX - EXPAND_SPARE) { 140+ return XML_ERROR_NO_MEMORY; 141+ } 142+ /* Detect and prevent integer overflow. 143+ * The preprocessor guard addresses the "always false" warning 144+ * from -Wtype-limits on platforms where 145+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ 146+#if UINT_MAX >= SIZE_MAX 147+ if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { 148+ return XML_ERROR_NO_MEMORY; 149+ } 150+#endif 151+ 152 b->uri 153 = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE)); 154 if (! b->uri) { 155@@ -6141,7 +6229,24 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, 156 } 157 } else { 158 DEFAULT_ATTRIBUTE *temp; 159+ 160+ /* Detect and prevent integer overflow */ 161+ if (type->allocDefaultAtts > INT_MAX / 2) { 162+ return 0; 163+ } 164+ 165 int count = type->allocDefaultAtts * 2; 166+ 167+ /* Detect and prevent integer overflow. 168+ * The preprocessor guard addresses the "always false" warning 169+ * from -Wtype-limits on platforms where 170+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ 171+#if UINT_MAX >= SIZE_MAX 172+ if ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) { 173+ return 0; 174+ } 175+#endif 176+ 177 temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts, 178 (count * sizeof(DEFAULT_ATTRIBUTE))); 179 if (temp == NULL) 180@@ -6792,8 +6897,20 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { 181 /* check for overflow (table is half full) */ 182 if (table->used >> (table->power - 1)) { 183 unsigned char newPower = table->power + 1; 184+ 185+ /* Detect and prevent invalid shift */ 186+ if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) { 187+ return NULL; 188+ } 189+ 190 size_t newSize = (size_t)1 << newPower; 191 unsigned long newMask = (unsigned long)newSize - 1; 192+ 193+ /* Detect and prevent integer overflow */ 194+ if (newSize > (size_t)(-1) / sizeof(NAMED *)) { 195+ return NULL; 196+ } 197+ 198 size_t tsize = newSize * sizeof(NAMED *); 199 NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize); 200 if (! newV) 201@@ -7143,6 +7260,20 @@ nextScaffoldPart(XML_Parser parser) { 202 if (dtd->scaffCount >= dtd->scaffSize) { 203 CONTENT_SCAFFOLD *temp; 204 if (dtd->scaffold) { 205+ /* Detect and prevent integer overflow */ 206+ if (dtd->scaffSize > UINT_MAX / 2u) { 207+ return -1; 208+ } 209+ /* Detect and prevent integer overflow. 210+ * The preprocessor guard addresses the "always false" warning 211+ * from -Wtype-limits on platforms where 212+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ 213+#if UINT_MAX >= SIZE_MAX 214+ if (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) { 215+ return -1; 216+ } 217+#endif 218+ 219 temp = (CONTENT_SCAFFOLD *)REALLOC( 220 parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); 221 if (temp == NULL) 222@@ -7212,8 +7343,26 @@ build_model(XML_Parser parser) { 223 XML_Content *ret; 224 XML_Content *cpos; 225 XML_Char *str; 226- int allocsize = (dtd->scaffCount * sizeof(XML_Content) 227- + (dtd->contentStringLen * sizeof(XML_Char))); 228+ 229+ /* Detect and prevent integer overflow. 230+ * The preprocessor guard addresses the "always false" warning 231+ * from -Wtype-limits on platforms where 232+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ 233+#if UINT_MAX >= SIZE_MAX 234+ if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) { 235+ return NULL; 236+ } 237+ if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) { 238+ return NULL; 239+ } 240+#endif 241+ if (dtd->scaffCount * sizeof(XML_Content) 242+ > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) { 243+ return NULL; 244+ } 245+ 246+ const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content) 247+ + (dtd->contentStringLen * sizeof(XML_Char))); 248 249 ret = (XML_Content *)MALLOC(parser, allocsize); 250 if (! ret) 251-- 2521.8.3.1 253 254