diff options
-rw-r--r-- | contrib/xml2/expected/xml2.out | 15 | ||||
-rw-r--r-- | contrib/xml2/expected/xml2_1.out | 15 | ||||
-rw-r--r-- | contrib/xml2/sql/xml2.sql | 15 | ||||
-rw-r--r-- | contrib/xml2/xslt_proc.c | 79 | ||||
-rw-r--r-- | doc/src/sgml/xml2.sgml | 8 |
5 files changed, 103 insertions, 29 deletions
diff --git a/contrib/xml2/expected/xml2.out b/contrib/xml2/expected/xml2.out index 3bf676fb400..eba6ae60364 100644 --- a/contrib/xml2/expected/xml2.out +++ b/contrib/xml2/expected/xml2.out @@ -207,3 +207,18 @@ SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></empl (1 row) +-- possible security exploit +SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>', +$$<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:sax="http://icl.com/saxon" + extension-element-prefixes="sax"> + + <xsl:template match="//foo"> + <sax:output href="0wn3d.txt" method="text"> + <xsl:value-of select="'0wn3d via xml2 extension and libxslt'"/> + <xsl:apply-templates/> + </sax:output> + </xsl:template> +</xsl:stylesheet>$$); +ERROR: failed to apply stylesheet diff --git a/contrib/xml2/expected/xml2_1.out b/contrib/xml2/expected/xml2_1.out index fda626e08c7..bac90e5a2a9 100644 --- a/contrib/xml2/expected/xml2_1.out +++ b/contrib/xml2/expected/xml2_1.out @@ -151,3 +151,18 @@ 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 +-- possible security exploit +SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>', +$$<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:sax="http://icl.com/saxon" + extension-element-prefixes="sax"> + + <xsl:template match="//foo"> + <sax:output href="0wn3d.txt" method="text"> + <xsl:value-of select="'0wn3d via xml2 extension and libxslt'"/> + <xsl:apply-templates/> + </sax:output> + </xsl:template> +</xsl:stylesheet>$$); +ERROR: xslt_process() is not available without libxslt diff --git a/contrib/xml2/sql/xml2.sql b/contrib/xml2/sql/xml2.sql index 4a996af7167..ac49cfa7c52 100644 --- a/contrib/xml2/sql/xml2.sql +++ b/contrib/xml2/sql/xml2.sql @@ -122,3 +122,18 @@ SELECT xslt_process('<employee><name>cim</name><age>30</age><pay>400</pay></empl </xsl:element> </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); + +-- possible security exploit +SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>', +$$<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:sax="http://icl.com/saxon" + extension-element-prefixes="sax"> + + <xsl:template match="//foo"> + <sax:output href="0wn3d.txt" method="text"> + <xsl:value-of select="'0wn3d via xml2 extension and libxslt'"/> + <xsl:apply-templates/> + </sax:output> + </xsl:template> +</xsl:stylesheet>$$); diff --git a/contrib/xml2/xslt_proc.c b/contrib/xml2/xslt_proc.c index 1bfeedfa885..6603526392d 100644 --- a/contrib/xml2/xslt_proc.c +++ b/contrib/xml2/xslt_proc.c @@ -26,6 +26,7 @@ #include <libxslt/xslt.h> #include <libxslt/xsltInternals.h> +#include <libxslt/security.h> #include <libxslt/transform.h> #include <libxslt/xsltutils.h> #endif /* USE_LIBXSLT */ @@ -60,7 +61,10 @@ xslt_process(PG_FUNCTION_ARGS) xsltStylesheetPtr stylesheet = NULL; xmlDocPtr doctree; xmlDocPtr restree; - xmlDocPtr ssdoc = NULL; + xmlDocPtr ssdoc; + xsltSecurityPrefsPtr xslt_sec_prefs; + bool xslt_sec_prefs_error; + xsltTransformContextPtr xslt_ctxt; xmlChar *resstr; int resstat; int reslen; @@ -80,34 +84,27 @@ xslt_process(PG_FUNCTION_ARGS) /* Setup parser */ pgxml_parser_init(); - /* Check to see if document is a file or a literal */ - - if (VARDATA(doct)[0] == '<') - doctree = xmlParseMemory((char *) VARDATA(doct), VARSIZE(doct) - VARHDRSZ); - else - doctree = xmlParseFile(text_to_cstring(doct)); + /* Parse document */ + doctree = xmlParseMemory((char *) VARDATA(doct), + VARSIZE(doct) - VARHDRSZ); if (doctree == NULL) xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, "error parsing XML document"); /* Same for stylesheet */ - if (VARDATA(ssheet)[0] == '<') - { - ssdoc = xmlParseMemory((char *) VARDATA(ssheet), - VARSIZE(ssheet) - VARHDRSZ); - if (ssdoc == NULL) - { - xmlFreeDoc(doctree); - xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, - "error parsing stylesheet as XML document"); - } + ssdoc = xmlParseMemory((char *) VARDATA(ssheet), + VARSIZE(ssheet) - VARHDRSZ); - stylesheet = xsltParseStylesheetDoc(ssdoc); + if (ssdoc == NULL) + { + xmlFreeDoc(doctree); + xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, + "error parsing stylesheet as XML document"); } - else - stylesheet = xsltParseStylesheetFile((xmlChar *) text_to_cstring(ssheet)); + /* After this call we need not free ssdoc separately */ + stylesheet = xsltParseStylesheetDoc(ssdoc); if (stylesheet == NULL) { @@ -117,12 +114,50 @@ xslt_process(PG_FUNCTION_ARGS) "failed to parse stylesheet"); } - restree = xsltApplyStylesheet(stylesheet, doctree, params); + xslt_ctxt = xsltNewTransformContext(stylesheet, doctree); + + xslt_sec_prefs_error = false; + if ((xslt_sec_prefs = xsltNewSecurityPrefs()) == NULL) + xslt_sec_prefs_error = true; + + if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_FILE, + xsltSecurityForbid) != 0) + xslt_sec_prefs_error = true; + if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_FILE, + xsltSecurityForbid) != 0) + xslt_sec_prefs_error = true; + if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_CREATE_DIRECTORY, + xsltSecurityForbid) != 0) + xslt_sec_prefs_error = true; + if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_NETWORK, + xsltSecurityForbid) != 0) + xslt_sec_prefs_error = true; + if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_NETWORK, + xsltSecurityForbid) != 0) + xslt_sec_prefs_error = true; + if (xsltSetCtxtSecurityPrefs(xslt_sec_prefs, xslt_ctxt) != 0) + xslt_sec_prefs_error = true; + + if (xslt_sec_prefs_error) + { + xsltFreeStylesheet(stylesheet); + xmlFreeDoc(doctree); + xsltFreeSecurityPrefs(xslt_sec_prefs); + xsltFreeTransformContext(xslt_ctxt); + xsltCleanupGlobals(); + xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, + "could not set libxslt security preferences"); + } + + restree = xsltApplyStylesheetUser(stylesheet, doctree, params, + NULL, NULL, xslt_ctxt); if (restree == NULL) { xsltFreeStylesheet(stylesheet); xmlFreeDoc(doctree); + xsltFreeSecurityPrefs(xslt_sec_prefs); + xsltFreeTransformContext(xslt_ctxt); xsltCleanupGlobals(); xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, "failed to apply stylesheet"); @@ -133,6 +168,8 @@ xslt_process(PG_FUNCTION_ARGS) xsltFreeStylesheet(stylesheet); xmlFreeDoc(restree); xmlFreeDoc(doctree); + xsltFreeSecurityPrefs(xslt_sec_prefs); + xsltFreeTransformContext(xslt_ctxt); xsltCleanupGlobals(); diff --git a/doc/src/sgml/xml2.sgml b/doc/src/sgml/xml2.sgml index 47bac31f0c7..ce5a2f0645b 100644 --- a/doc/src/sgml/xml2.sgml +++ b/doc/src/sgml/xml2.sgml @@ -437,14 +437,6 @@ xslt_process(text document, text stylesheet, text paramlist) returns text </para> <para> - Also note that if either the document or stylesheet values do not - begin with a < then they will be treated as URLs and libxslt will - fetch them. It follows that you can use <function>xslt_process</> as a - means to fetch the contents of URLs — you should be aware of the - security implications of this. - </para> - - <para> There is also a two-parameter version of <function>xslt_process</> which does not pass any parameters to the transformation. </para> |