Skip to content

Commit d5622ac

Browse files
committed
Replace usages of xmlXPathCompile() with xmlXPathCtxtCompile().
In existing releases of libxml2, xmlXPathCompile can be driven to stack overflow because it fails to protect itself against too-deeply-nested input. While there is an upstream fix as of yesterday, it will take years for that to propagate into all shipping versions. In the meantime, we can protect our own usages basically for free by calling xmlXPathCtxtCompile instead. (The actual bug is that libxml2 keeps its nesting counter in the xmlXPathContext, and its parsing code was willing to just skip counting nesting levels if it didn't have a context. So if we supply a context, all is well. It seems odd actually that it works at all to not supply a context, because this means that XPath parsing does not have access to XML namespace info. Apparently libxml2 never checks namespaces until runtime? Anyway, this seems like good future-proofing even if its only immediate effect is to dodge a bug.) Sadly, this hack only offers protection with libxml2 2.9.11 and newer. Before that there are multiple similar problems, so if you are processing untrusted XML it behooves you to get a newer version. But we have some pretty old libxml2 in the buildfarm, so it seems impractical to add a regression test to verify this fix. Per bug #18617 from Jingzhou Fu. Back-patch to all supported versions. Discussion: https://postgr.es/m/18617-1cee4d2ed1f4e7ae@postgresql.org Discussion: https://gitlab.gnome.org/GNOME/libxml2/-/issues/799
1 parent 43ce181 commit d5622ac

File tree

2 files changed

+17
-5
lines changed

2 files changed

+17
-5
lines changed

contrib/xml2/xpath.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
386386
workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
387387

388388
/* compile the path */
389-
comppath = xmlXPathCompile(xpath);
389+
comppath = xmlXPathCtxtCompile(workspace->ctxt, xpath);
390390
if (comppath == NULL)
391391
xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
392392
"XPath Syntax Error");
@@ -649,7 +649,7 @@ xpath_table(PG_FUNCTION_ARGS)
649649
ctxt->node = xmlDocGetRootElement(doctree);
650650

651651
/* compile the path */
652-
comppath = xmlXPathCompile(xpaths[j]);
652+
comppath = xmlXPathCtxtCompile(ctxt, xpaths[j]);
653653
if (comppath == NULL)
654654
xml_ereport(xmlerrcxt, ERROR,
655655
ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,

src/backend/utils/adt/xml.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4448,7 +4448,13 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
44484448
}
44494449
}
44504450

4451-
xpathcomp = xmlXPathCompile(xpath_expr);
4451+
/*
4452+
* Note: here and elsewhere, be careful to use xmlXPathCtxtCompile not
4453+
* xmlXPathCompile. In libxml2 2.13.3 and older, the latter function
4454+
* fails to defend itself against recursion-to-stack-overflow. See
4455+
* https://gitlab.gnome.org/GNOME/libxml2/-/issues/799
4456+
*/
4457+
xpathcomp = xmlXPathCtxtCompile(xpathctx, xpath_expr);
44524458
if (xpathcomp == NULL || xmlerrcxt->err_occurred)
44534459
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
44544460
"invalid XPath expression");
@@ -4819,7 +4825,10 @@ XmlTableSetRowFilter(TableFuncScanState *state, const char *path)
48194825

48204826
xstr = pg_xmlCharStrndup(path, strlen(path));
48214827

4822-
xtCxt->xpathcomp = xmlXPathCompile(xstr);
4828+
/* We require XmlTableSetDocument to have been done already */
4829+
Assert(xtCxt->xpathcxt != NULL);
4830+
4831+
xtCxt->xpathcomp = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);
48234832
if (xtCxt->xpathcomp == NULL || xtCxt->xmlerrcxt->err_occurred)
48244833
xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_SYNTAX_ERROR,
48254834
"invalid XPath expression");
@@ -4850,7 +4859,10 @@ XmlTableSetColumnFilter(TableFuncScanState *state, const char *path, int colnum)
48504859

48514860
xstr = pg_xmlCharStrndup(path, strlen(path));
48524861

4853-
xtCxt->xpathscomp[colnum] = xmlXPathCompile(xstr);
4862+
/* We require XmlTableSetDocument to have been done already */
4863+
Assert(xtCxt->xpathcxt != NULL);
4864+
4865+
xtCxt->xpathscomp[colnum] = xmlXPathCtxtCompile(xtCxt->xpathcxt, xstr);
48544866
if (xtCxt->xpathscomp[colnum] == NULL || xtCxt->xmlerrcxt->err_occurred)
48554867
xml_ereport(xtCxt->xmlerrcxt, ERROR, ERRCODE_DATA_EXCEPTION,
48564868
"invalid XPath expression");

0 commit comments

Comments
 (0)