]> granicus.if.org Git - postgresql/commitdiff
Prevent access to external files/URLs via contrib/xml2's xslt_process().
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 14 Aug 2012 22:28:53 +0000 (18:28 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 14 Aug 2012 22:32:44 +0000 (18:32 -0400)
libxslt offers the ability to read and write both files and URLs through
stylesheet commands, thus allowing unprivileged database users to both read
and write data with the privileges of the database server.  Disable that
through proper use of libxslt's security options.

Also, remove xslt_process()'s ability to fetch documents and stylesheets
from external files/URLs.  While this was a documented "feature", it was
long regarded as a terrible idea.  The fix for CVE-2012-3489 broke that
capability, and rather than expend effort on trying to fix it, we're just
going to summarily remove it.

While the ability to write as well as read makes this security hole
considerably worse than CVE-2012-3489, the problem is mitigated by the fact
that xslt_process() is not available unless contrib/xml2 is installed,
and the longstanding warnings about security risks from that should have
discouraged prudent DBAs from installing it in security-exposed databases.

Reported and fixed by Peter Eisentraut.

Security: CVE-2012-3488

contrib/xml2/expected/xml2.out
contrib/xml2/expected/xml2_1.out
contrib/xml2/sql/xml2.sql
contrib/xml2/xslt_proc.c
doc/src/sgml/xml2.sgml

index 7dd05fad9ac2f9a6cf8f56e6af8dd51f3a9dad24..8bc741e364f345d318dafedd2c8e39bf63074660 100644 (file)
@@ -145,3 +145,18 @@ values
 Value</attribute></attributes>');
 create index idx_xpath on t1 ( xpath_string
 ('/attributes/attribute[@name="attr_1"]/text()', xml_data::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>$$);
+ERROR:  failed to apply stylesheet
index 80cefb54df32b8125d890564e97ed6dba57c5936..5f267b4cd62ea806a5893ad27cd9fc1f2426c478 100644 (file)
@@ -107,3 +107,18 @@ values
 Value</attribute></attributes>');
 create index idx_xpath on t1 ( xpath_string
 ('/attributes/attribute[@name="attr_1"]/text()', xml_data::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>$$);
+ERROR:  xslt_process() is not available without libxslt
index 73723b6be1026a5c17c73baccbf10bb945a90716..71d3535d14f4487fc8f7b64311e8ae58f90ef11c 100644 (file)
@@ -80,3 +80,18 @@ Value</attribute></attributes>');
 
 create index idx_xpath on t1 ( xpath_string
 ('/attributes/attribute[@name="attr_1"]/text()', xml_data::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>$$);
index 5e4b7a61b4e62c9471f574a7d4da8cef1e6f5990..a56b297c90b8e32f97ea1b8e0033477cbf32423a 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <libxslt/xslt.h>
 #include <libxslt/xsltInternals.h>
+#include <libxslt/security.h>
 #include <libxslt/transform.h>
 #include <libxslt/xsltutils.h>
 
@@ -64,7 +65,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;
@@ -81,34 +85,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)
        {
@@ -118,12 +115,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");
@@ -134,6 +169,8 @@ xslt_process(PG_FUNCTION_ARGS)
        xsltFreeStylesheet(stylesheet);
        xmlFreeDoc(restree);
        xmlFreeDoc(doctree);
+       xsltFreeSecurityPrefs(xslt_sec_prefs);
+       xsltFreeTransformContext(xslt_ctxt);
 
        xsltCleanupGlobals();
 
index 51faaccd208177adea512d7a6307183ed8525021..80a3a45bed22a9dc51fa9f512127efcf9885fec6 100644 (file)
@@ -394,14 +394,6 @@ WHERE t.author_id = p.person_id;
     contain commas!
    </para>
 
-   <para>
-    Also note that if either the document or stylesheet values do not
-    begin with a &lt; 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 &mdash; 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.