Skip to content

Commit ac7e13d

Browse files
committed
Prevent access to external files/URLs via contrib/xml2's xslt_process().
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
1 parent 24cc5f8 commit ac7e13d

File tree

5 files changed

+103
-29
lines changed

5 files changed

+103
-29
lines changed

contrib/xml2/expected/xml2.out

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,18 @@ values
145145
Value</attribute></attributes>');
146146
create index idx_xpath on t1 ( xpath_string
147147
('/attributes/attribute[@name="attr_1"]/text()', xml_data::text));
148+
-- possible security exploit
149+
SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>',
150+
$$<xsl:stylesheet version="1.0"
151+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
152+
xmlns:sax="http://icl.com/saxon"
153+
extension-element-prefixes="sax">
154+
155+
<xsl:template match="//foo">
156+
<sax:output href="0wn3d.txt" method="text">
157+
<xsl:value-of select="'0wn3d via xml2 extension and libxslt'"/>
158+
<xsl:apply-templates/>
159+
</sax:output>
160+
</xsl:template>
161+
</xsl:stylesheet>$$);
162+
ERROR: failed to apply stylesheet

contrib/xml2/expected/xml2_1.out

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,18 @@ values
107107
Value</attribute></attributes>');
108108
create index idx_xpath on t1 ( xpath_string
109109
('/attributes/attribute[@name="attr_1"]/text()', xml_data::text));
110+
-- possible security exploit
111+
SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>',
112+
$$<xsl:stylesheet version="1.0"
113+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
114+
xmlns:sax="http://icl.com/saxon"
115+
extension-element-prefixes="sax">
116+
117+
<xsl:template match="//foo">
118+
<sax:output href="0wn3d.txt" method="text">
119+
<xsl:value-of select="'0wn3d via xml2 extension and libxslt'"/>
120+
<xsl:apply-templates/>
121+
</sax:output>
122+
</xsl:template>
123+
</xsl:stylesheet>$$);
124+
ERROR: xslt_process() is not available without libxslt

contrib/xml2/sql/xml2.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,18 @@ Value</attribute></attributes>');
8080

8181
create index idx_xpath on t1 ( xpath_string
8282
('/attributes/attribute[@name="attr_1"]/text()', xml_data::text));
83+
84+
-- possible security exploit
85+
SELECT xslt_process('<xml><foo>Hello from XML</foo></xml>',
86+
$$<xsl:stylesheet version="1.0"
87+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
88+
xmlns:sax="http://icl.com/saxon"
89+
extension-element-prefixes="sax">
90+
91+
<xsl:template match="//foo">
92+
<sax:output href="0wn3d.txt" method="text">
93+
<xsl:value-of select="'0wn3d via xml2 extension and libxslt'"/>
94+
<xsl:apply-templates/>
95+
</sax:output>
96+
</xsl:template>
97+
</xsl:stylesheet>$$);

contrib/xml2/xslt_proc.c

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include <libxslt/xslt.h>
2828
#include <libxslt/xsltInternals.h>
29+
#include <libxslt/security.h>
2930
#include <libxslt/transform.h>
3031
#include <libxslt/xsltutils.h>
3132
#endif /* USE_LIBXSLT */
@@ -62,7 +63,10 @@ xslt_process(PG_FUNCTION_ARGS)
6263
xsltStylesheetPtr stylesheet = NULL;
6364
xmlDocPtr doctree;
6465
xmlDocPtr restree;
65-
xmlDocPtr ssdoc = NULL;
66+
xmlDocPtr ssdoc;
67+
xsltSecurityPrefsPtr xslt_sec_prefs;
68+
bool xslt_sec_prefs_error;
69+
xsltTransformContextPtr xslt_ctxt;
6670
xmlChar *resstr;
6771
int resstat;
6872
int reslen;
@@ -79,34 +83,27 @@ xslt_process(PG_FUNCTION_ARGS)
7983
/* Setup parser */
8084
pgxml_parser_init();
8185

82-
/* Check to see if document is a file or a literal */
83-
84-
if (VARDATA(doct)[0] == '<')
85-
doctree = xmlParseMemory((char *) VARDATA(doct), VARSIZE(doct) - VARHDRSZ);
86-
else
87-
doctree = xmlParseFile(text_to_cstring(doct));
86+
/* Parse document */
87+
doctree = xmlParseMemory((char *) VARDATA(doct),
88+
VARSIZE(doct) - VARHDRSZ);
8889

8990
if (doctree == NULL)
9091
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
9192
"error parsing XML document");
9293

9394
/* Same for stylesheet */
94-
if (VARDATA(ssheet)[0] == '<')
95-
{
96-
ssdoc = xmlParseMemory((char *) VARDATA(ssheet),
97-
VARSIZE(ssheet) - VARHDRSZ);
98-
if (ssdoc == NULL)
99-
{
100-
xmlFreeDoc(doctree);
101-
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
102-
"error parsing stylesheet as XML document");
103-
}
95+
ssdoc = xmlParseMemory((char *) VARDATA(ssheet),
96+
VARSIZE(ssheet) - VARHDRSZ);
10497

105-
stylesheet = xsltParseStylesheetDoc(ssdoc);
98+
if (ssdoc == NULL)
99+
{
100+
xmlFreeDoc(doctree);
101+
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
102+
"error parsing stylesheet as XML document");
106103
}
107-
else
108-
stylesheet = xsltParseStylesheetFile((xmlChar *) text_to_cstring(ssheet));
109104

105+
/* After this call we need not free ssdoc separately */
106+
stylesheet = xsltParseStylesheetDoc(ssdoc);
110107

111108
if (stylesheet == NULL)
112109
{
@@ -116,12 +113,50 @@ xslt_process(PG_FUNCTION_ARGS)
116113
"failed to parse stylesheet");
117114
}
118115

119-
restree = xsltApplyStylesheet(stylesheet, doctree, params);
116+
xslt_ctxt = xsltNewTransformContext(stylesheet, doctree);
117+
118+
xslt_sec_prefs_error = false;
119+
if ((xslt_sec_prefs = xsltNewSecurityPrefs()) == NULL)
120+
xslt_sec_prefs_error = true;
121+
122+
if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_FILE,
123+
xsltSecurityForbid) != 0)
124+
xslt_sec_prefs_error = true;
125+
if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_FILE,
126+
xsltSecurityForbid) != 0)
127+
xslt_sec_prefs_error = true;
128+
if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_CREATE_DIRECTORY,
129+
xsltSecurityForbid) != 0)
130+
xslt_sec_prefs_error = true;
131+
if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_NETWORK,
132+
xsltSecurityForbid) != 0)
133+
xslt_sec_prefs_error = true;
134+
if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_NETWORK,
135+
xsltSecurityForbid) != 0)
136+
xslt_sec_prefs_error = true;
137+
if (xsltSetCtxtSecurityPrefs(xslt_sec_prefs, xslt_ctxt) != 0)
138+
xslt_sec_prefs_error = true;
139+
140+
if (xslt_sec_prefs_error)
141+
{
142+
xsltFreeStylesheet(stylesheet);
143+
xmlFreeDoc(doctree);
144+
xsltFreeSecurityPrefs(xslt_sec_prefs);
145+
xsltFreeTransformContext(xslt_ctxt);
146+
xsltCleanupGlobals();
147+
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
148+
"could not set libxslt security preferences");
149+
}
150+
151+
restree = xsltApplyStylesheetUser(stylesheet, doctree, params,
152+
NULL, NULL, xslt_ctxt);
120153

121154
if (restree == NULL)
122155
{
123156
xsltFreeStylesheet(stylesheet);
124157
xmlFreeDoc(doctree);
158+
xsltFreeSecurityPrefs(xslt_sec_prefs);
159+
xsltFreeTransformContext(xslt_ctxt);
125160
xsltCleanupGlobals();
126161
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
127162
"failed to apply stylesheet");
@@ -132,6 +167,8 @@ xslt_process(PG_FUNCTION_ARGS)
132167
xsltFreeStylesheet(stylesheet);
133168
xmlFreeDoc(restree);
134169
xmlFreeDoc(doctree);
170+
xsltFreeSecurityPrefs(xslt_sec_prefs);
171+
xsltFreeTransformContext(xslt_ctxt);
135172

136173
xsltCleanupGlobals();
137174

doc/src/sgml/xml2.sgml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -436,14 +436,6 @@ xslt_process(text document, text stylesheet, text paramlist) returns text
436436
contain commas!
437437
</para>
438438

439-
<para>
440-
Also note that if either the document or stylesheet values do not
441-
begin with a &lt; then they will be treated as URLs and libxslt will
442-
fetch them. It follows that you can use <function>xslt_process</> as a
443-
means to fetch the contents of URLs &mdash; you should be aware of the
444-
security implications of this.
445-
</para>
446-
447439
<para>
448440
There is also a two-parameter version of <function>xslt_process</> which
449441
does not pass any parameters to the transformation.

0 commit comments

Comments
 (0)