1From c50196c13d348025a4843305902bb37df64bae36 Mon Sep 17 00:00:00 2001 2From: David Kilzer <ddkilzer@apple.com> 3Date: Sun, 10 Apr 2022 20:02:47 -0700 4Subject: [PATCH 289/300] Fix use-after-free bugs when calling 5 xmlTextReaderClose() before xmlFreeTextReader() on post-validating parser 6 7When creating an xmlTextReaderPtr using xmlReaderForMemory(), 8there are two optional API functions that can be used: 9- xmlTextReaderClose() may be called prior to calling 10 xmlFreeTextReader() to free parsing resources and close the 11 xmlTextReaderPtr without freeing it. 12- xmlTextReaderCurrentDoc() may be called to return an 13 xmlDocPtr that's owned by the caller, and must be free using 14 xmlFreeDoc() after calling xmlFreeTextReader(). 15 16The use-after-free issues occur when calling 17xmlTextReaderClose() before xmlFreeTextReader(), with different 18issues occurring depending on whether xmlTextReaderCurrentDoc() 19is also called. 20 21* xmlreader.c: 22(xmlFreeTextReader): 23- Move code to xmlTextReaderClose(), remove duplicate code, and 24 call xmlTextReaderClose() if it hasn't been called yet. 25(xmlTextReaderClose): 26- Move call to xmlFreeNode(reader->faketext) from 27 xmlFreeTextReader() to fix a use-after-free bug when calling 28 xmlTextReaderClose() before xmlFreeTextReader(), but not when 29 using xmlTextReaderCurrentDoc(). The bug was introduced in 30 2002 by commit beb70bd39. In 2009 commit f4653dcd8 fixed the 31 use-after-free that occurred every time xmlFreeTextReader() 32 was called, but not the case where xmlTextReaderClose() was 33 called first. 34- Move post-parsing validation code from xmlFreeTextReader() to 35 fix a second use-after-free when calling xmlTextReaderClose() 36 before xmlFreeTextReader(). This regressed in v2.9.10 with 37 commit 57a3af56f. 38 39Reference:https://github.com/GNOME/libxml2/commit/c50196c13d348025a4843305902bb37df64bae36 40Conflict:NA 41 42--- 43 xmlreader.c | 40 ++++++++++++++++++---------------------- 44 1 file changed, 18 insertions(+), 22 deletions(-) 45 46diff --git a/xmlreader.c b/xmlreader.c 47index 72e40b0..989b7c1 100644 48--- a/xmlreader.c 49+++ b/xmlreader.c 50@@ -2319,36 +2319,16 @@ xmlFreeTextReader(xmlTextReaderPtr reader) { 51 xmlFree(reader->patternTab); 52 } 53 #endif 54- if (reader->faketext != NULL) { 55- xmlFreeNode(reader->faketext); 56- } 57+ if (reader->mode != XML_TEXTREADER_MODE_CLOSED) 58+ xmlTextReaderClose(reader); 59 if (reader->ctxt != NULL) { 60 if (reader->dict == reader->ctxt->dict) 61 reader->dict = NULL; 62-#ifdef LIBXML_VALID_ENABLED 63- if ((reader->ctxt->vctxt.vstateTab != NULL) && 64- (reader->ctxt->vctxt.vstateMax > 0)){ 65-#ifdef LIBXML_REGEXP_ENABLED 66- while (reader->ctxt->vctxt.vstateNr > 0) 67- xmlValidatePopElement(&reader->ctxt->vctxt, NULL, NULL, NULL); 68-#endif /* LIBXML_REGEXP_ENABLED */ 69- xmlFree(reader->ctxt->vctxt.vstateTab); 70- reader->ctxt->vctxt.vstateTab = NULL; 71- reader->ctxt->vctxt.vstateMax = 0; 72- } 73-#endif /* LIBXML_VALID_ENABLED */ 74- if (reader->ctxt->myDoc != NULL) { 75- if (reader->preserve == 0) 76- xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc); 77- reader->ctxt->myDoc = NULL; 78- } 79 if (reader->allocs & XML_TEXTREADER_CTXT) 80 xmlFreeParserCtxt(reader->ctxt); 81 } 82 if (reader->sax != NULL) 83 xmlFree(reader->sax); 84- if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) 85- xmlFreeParserInputBuffer(reader->input); 86 if (reader->buffer != NULL) 87 xmlBufFree(reader->buffer); 88 if (reader->entTab != NULL) 89@@ -2379,7 +2359,23 @@ xmlTextReaderClose(xmlTextReaderPtr reader) { 90 reader->node = NULL; 91 reader->curnode = NULL; 92 reader->mode = XML_TEXTREADER_MODE_CLOSED; 93+ if (reader->faketext != NULL) { 94+ xmlFreeNode(reader->faketext); 95+ reader->faketext = NULL; 96+ } 97 if (reader->ctxt != NULL) { 98+#ifdef LIBXML_VALID_ENABLED 99+ if ((reader->ctxt->vctxt.vstateTab != NULL) && 100+ (reader->ctxt->vctxt.vstateMax > 0)){ 101+#ifdef LIBXML_REGEXP_ENABLED 102+ while (reader->ctxt->vctxt.vstateNr > 0) 103+ xmlValidatePopElement(&reader->ctxt->vctxt, NULL, NULL, NULL); 104+#endif /* LIBXML_REGEXP_ENABLED */ 105+ xmlFree(reader->ctxt->vctxt.vstateTab); 106+ reader->ctxt->vctxt.vstateTab = NULL; 107+ reader->ctxt->vctxt.vstateMax = 0; 108+ } 109+#endif /* LIBXML_VALID_ENABLED */ 110 xmlStopParser(reader->ctxt); 111 if (reader->ctxt->myDoc != NULL) { 112 if (reader->preserve == 0) 113-- 1142.27.0 115 116