xml2: Fix crash with namespace nodes in xpath_nodeset()

pgxmlNodeSetToText() passed nodeTab[i]->doc to xmlNodeDump() without
checking the node type, which could cause a crash as a
XML_NAMESPACE_DECL maps to a xmlNs struct.  The passed-in code would
then be dereferenced in xmlNodeDump().

This commit switches the code to render XML_NAMESPACE_DECL nodes with
xmlXPathCastNodeToString(), like xpath_table().  Some tests are added,
written by me.

Author: Andrey Chernyy <andrey.cherny@tantorlabs.com>
Co-authored-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/20260611031436.5afde3cb@andrnote
Backpatch-through: 14
This commit is contained in:
Michael Paquier 2026-06-11 14:29:28 +09:00
parent a7e0e42a22
commit bc5775149f
4 changed files with 31 additions and 4 deletions

View file

@ -207,6 +207,14 @@ SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></empl
(1 row)
-- xpath_nodeset() with namespace node
SELECT xpath_nodeset('<root xmlns:foo="http://icl.com/saxon"/>',
'//namespace::foo');
xpath_nodeset
----------------------
http://icl.com/saxon
(1 row)
-- possible security exploit
SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>',
$$<xsl:stylesheet version="1.0"

View file

@ -151,6 +151,14 @@ SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></empl
</xsl:template>
</xsl:stylesheet>$$::text, 'n1="v1",n2="v2",n3="v3",n4="v4",n5="v5",n6="v6",n7="v7",n8="v8",n9="v9",n10="v10",n11="v11",n12="v12"'::text);
ERROR: xslt_process() is not available without libxslt
-- xpath_nodeset() with namespace node
SELECT xpath_nodeset('<root xmlns:foo="http://icl.com/saxon"/>',
'//namespace::foo');
xpath_nodeset
----------------------
http://icl.com/saxon
(1 row)
-- possible security exploit
SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>',
$$<xsl:stylesheet version="1.0"

View file

@ -123,6 +123,10 @@ SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></empl
</xsl:template>
</xsl:stylesheet>$$::text, 'n1="v1",n2="v2",n3="v3",n4="v4",n5="v5",n6="v6",n7="v7",n8="v8",n9="v9",n10="v10",n11="v11",n12="v12"'::text);
-- xpath_nodeset() with namespace node
SELECT xpath_nodeset('<root xmlns:foo="http://icl.com/saxon"/>',
'//namespace::foo');
-- possible security exploit
SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>',
$$<xsl:stylesheet version="1.0"

View file

@ -147,16 +147,23 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
}
else
{
xmlNodePtr node = nodeset->nodeTab[i];
if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
{
xmlBufferWriteChar(buf, "<");
xmlBufferWriteCHAR(buf, septagname);
xmlBufferWriteChar(buf, ">");
}
xmlNodeDump(buf,
nodeset->nodeTab[i]->doc,
nodeset->nodeTab[i],
1, 0);
/*
* XML_NAMESPACE_DECL nodes are xmlNs structs, that cannot
* be processed by xmlNodeDump().
*/
if (node->type == XML_NAMESPACE_DECL)
xmlBufferWriteCHAR(buf, xmlXPathCastNodeToString(node));
else
xmlNodeDump(buf, node->doc, node, 1, 0);
if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
{