• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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