Re: BUG #18617: PostgreSQL Server Subprocess Crashes by the XPATH Function Expression with Crafted Arguments - Mailing list pgsql-bugs

From Tom Lane
Subject Re: BUG #18617: PostgreSQL Server Subprocess Crashes by the XPATH Function Expression with Crafted Arguments
Date
Msg-id 356363.1726333674@sss.pgh.pa.us
Whole thread Raw
In response to Re: BUG #18617: PostgreSQL Server Subprocess Crashes by the XPATH Function Expression with Crafted Arguments  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-bugs
I wrote:
> Based on Nick Wellnhofer's response there, I've experimented with the
> attached WIP patch, and it does seem to prevent the problem as long as
> you have a non-ancient libxml2.  This is only WIP because there are
> other xmlXPathCompile calls we'd have to fix.

Here's a fleshed-out patch.  I first thought that the XmlTableRoutine
code might need significant surgery, but it turns out not to be a
problem as long as we're willing to assume that XmlTableSetDocument
is called before XmlTableSetRowFilter or XmlTableSetColumnFilter.
Since the sole caller does it like that, this doesn't seem too
onerous.  I put in Asserts to check that, though.

> Nick also suggested that we not bother with a separate xmlXPathCompile
> call if we're just going to throw away the compiled expression after
> one use.  Perhaps that's good cleanup, not sure.  I don't know if
> anyone has serious ambitions of re-using the compiled XPath
> expressions.

I looked at this but realized that it'd cause a user-visible change
in error messages.  For instance, in xpath_internal we have

        xpathcomp = xmlXPathCtxtCompile(xpathctx, xpath_expr);
        if (xpathcomp == NULL || xmlerrcxt->err_occurred)
            xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
                        "invalid XPath expression");

        xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
        if (xpathobj == NULL || xmlerrcxt->err_occurred)
            xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR,
                        "could not create XPath object");

So syntax errors in the XPath expression draw "invalid XPath
expression", but if we merged these into one they'd draw
"could not create XPath object", or at least the same message
as execution-time errors.  That seems strictly worse for users,
and even if it were OK it's not the sort of thing I'd like to
change in minor releases.  So I think we're best off just doing
the minimum change s/xmlXPathCompile/xmlXPathCtxtCompile/.

I would have liked to include a regression test case showing
that the stack overflow is prevented, but I think we can't
since it would fail with pre-2.9.11 libxml2.

BTW, surely ERRCODE_INTERNAL_ERROR is the wrong errcode to use
here?  But that's a matter for a different patch.

            regards, tom lane

diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c
index f94b622d92..0fdf735faf 100644
--- a/contrib/xml2/xpath.c
+++ b/contrib/xml2/xpath.c
@@ -386,7 +386,7 @@ pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace)
             workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);

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

                         /* compile the path */
-                        comppath = xmlXPathCompile(xpaths[j]);
+                        comppath = xmlXPathCtxtCompile(ctxt, xpaths[j]);
                         if (comppath == NULL)
                             xml_ereport(xmlerrcxt, ERROR,
                                         ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 1a07876cd5..41b1a5c6b0 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -4448,7 +4448,13 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
             }
         }

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

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

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

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

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

pgsql-bugs by date:

Previous
From: Muralikrishna Bandaru
Date:
Subject: Re: pl/perl extension fails on Windows
Next
From: "David G. Johnston"
Date:
Subject: Re: Case clause doesn't report syntactic error