diff --git a/contrib/xml2/expected/xml2.out b/contrib/xml2/expected/xml2.out
index 7dd05fad9ac..8bc741e364f 100644
--- a/contrib/xml2/expected/xml2.out
+++ b/contrib/xml2/expected/xml2.out
@@ -145,3 +145,18 @@ values
Value');
create index idx_xpath on t1 ( xpath_string
('/attributes/attribute[@name="attr_1"]/text()', xml_data::text));
+-- possible security exploit
+SELECT xslt_process('Hello from XML',
+$$
+
+
+
+
+
+
+
+$$);
+ERROR: failed to apply stylesheet
diff --git a/contrib/xml2/expected/xml2_1.out b/contrib/xml2/expected/xml2_1.out
index 80cefb54df3..5f267b4cd62 100644
--- a/contrib/xml2/expected/xml2_1.out
+++ b/contrib/xml2/expected/xml2_1.out
@@ -107,3 +107,18 @@ values
Value');
create index idx_xpath on t1 ( xpath_string
('/attributes/attribute[@name="attr_1"]/text()', xml_data::text));
+-- possible security exploit
+SELECT xslt_process('Hello from XML',
+$$
+
+
+
+
+
+
+
+$$);
+ERROR: xslt_process() is not available without libxslt
diff --git a/contrib/xml2/sql/xml2.sql b/contrib/xml2/sql/xml2.sql
index 73723b6be10..71d3535d14f 100644
--- a/contrib/xml2/sql/xml2.sql
+++ b/contrib/xml2/sql/xml2.sql
@@ -80,3 +80,18 @@ Value');
create index idx_xpath on t1 ( xpath_string
('/attributes/attribute[@name="attr_1"]/text()', xml_data::text));
+
+-- possible security exploit
+SELECT xslt_process('Hello from XML',
+$$
+
+
+
+
+
+
+
+$$);
diff --git a/contrib/xml2/xslt_proc.c b/contrib/xml2/xslt_proc.c
index 5e4b7a61b4e..a56b297c90b 100644
--- a/contrib/xml2/xslt_proc.c
+++ b/contrib/xml2/xslt_proc.c
@@ -26,6 +26,7 @@
#include
#include
+#include
#include
#include
@@ -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)
{
- 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");
- }
-
- stylesheet = xsltParseStylesheetDoc(ssdoc);
+ 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();
diff --git a/doc/src/sgml/xml2.sgml b/doc/src/sgml/xml2.sgml
index 51faaccd208..80a3a45bed2 100644
--- a/doc/src/sgml/xml2.sgml
+++ b/doc/src/sgml/xml2.sgml
@@ -394,14 +394,6 @@ WHERE t.author_id = p.person_id;
contain commas!
-
- 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 xslt_process> as a
- means to fetch the contents of URLs — you should be aware of the
- security implications of this.
-
-
There is also a two-parameter version of xslt_process> which
does not pass any parameters to the transformation.