diff options
-rw-r--r-- | src/backend/utils/adt/xml.c | 28 | ||||
-rw-r--r-- | src/test/regress/expected/xml.out | 20 | ||||
-rw-r--r-- | src/test/regress/expected/xml_1.out | 14 | ||||
-rw-r--r-- | src/test/regress/sql/xml.sql | 6 |
4 files changed, 68 insertions, 0 deletions
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 0c0d3554c32..d8b892b6163 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -48,6 +48,7 @@ #ifdef USE_LIBXML #include <libxml/chvalid.h> #include <libxml/parser.h> +#include <libxml/parserInternals.h> #include <libxml/tree.h> #include <libxml/uri.h> #include <libxml/xmlerror.h> @@ -86,6 +87,8 @@ int xmloption; static StringInfo xml_err_buf = NULL; +static xmlParserInputPtr xmlPgEntityLoader(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt); static void xml_errorHandler(void *ctxt, const char *msg,...); static void xml_ereport_by_code(int level, int sqlcode, const char *msg, int errcode); @@ -886,6 +889,9 @@ pg_xml_init(void) /* Now that xml_err_buf exists, safe to call xml_errorHandler */ xmlSetGenericErrorFunc(NULL, xml_errorHandler); + /* set up our entity loader, too */ + xmlSetExternalEntityLoader(xmlPgEntityLoader); + #ifdef USE_LIBXMLCONTEXT /* Set up memory allocation our way, too */ xml_memory_init(); @@ -910,6 +916,9 @@ pg_xml_init(void) * about, anyway. */ xmlSetGenericErrorFunc(NULL, xml_errorHandler); + + /* set up our entity loader, too */ + xmlSetExternalEntityLoader(xmlPgEntityLoader); } } @@ -1323,6 +1332,25 @@ xml_pstrdup(const char *string) /* + * xmlPgEntityLoader --- entity loader callback function + * + * Silently prevent any external entity URL from being loaded. We don't want + * to throw an error, so instead make the entity appear to expand to an empty + * string. + * + * We would prefer to allow loading entities that exist in the system's + * global XML catalog; but the available libxml2 APIs make that a complex + * and fragile task. For now, just shut down all external access. + */ +static xmlParserInputPtr +xmlPgEntityLoader(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) +{ + return xmlNewStringInputStream(ctxt, (const xmlChar *) ""); +} + + +/* * xml_ereport --- report an XML-related error * * The "msg" is the SQL-level message; some can be adopted from the SQL/XML diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index ecca5896a70..7db5f917bed 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -502,3 +502,23 @@ SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>'); {<b>two</b>,<b>etc</b>} (1 row) +-- External entity references should not leak filesystem information. +SELECT XMLPARSE(DOCUMENT '<!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/passwd">]><foo>&c;</foo>'); + xmlparse +----------------------------------------------------------------- + <!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/passwd">]><foo>&c;</foo> +(1 row) + +SELECT XMLPARSE(DOCUMENT '<!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/no.such.file">]><foo>&c;</foo>'); + xmlparse +----------------------------------------------------------------------- + <!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/no.such.file">]><foo>&c;</foo> +(1 row) + +-- This might or might not load the requested DTD, but it mustn't throw error. +SELECT XMLPARSE(DOCUMENT '<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"><chapter> </chapter>'); + xmlparse +------------------------------------------------------------------------------------------------------------------------------------------------------ + <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"><chapter> </chapter> +(1 row) + diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index d542b0689a9..d654056b08b 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -456,3 +456,17 @@ LINE 1: SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>'... ^ DETAIL: This functionality requires the server to be built with libxml support. HINT: You need to rebuild PostgreSQL using --with-libxml. +-- External entity references should not leak filesystem information. +SELECT XMLPARSE(DOCUMENT '<!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/passwd">]><foo>&c;</foo>'); +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT XMLPARSE(DOCUMENT '<!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/no.such.file">]><foo>&c;</foo>'); +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- This might or might not load the requested DTD, but it mustn't throw error. +SELECT XMLPARSE(DOCUMENT '<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"><chapter> </chapter>'); +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index 086eedd2700..1e5026b04c8 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -163,3 +163,9 @@ SELECT xpath('', '<!-- error -->'); SELECT xpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>'); SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]); SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>'); + +-- External entity references should not leak filesystem information. +SELECT XMLPARSE(DOCUMENT '<!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/passwd">]><foo>&c;</foo>'); +SELECT XMLPARSE(DOCUMENT '<!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/no.such.file">]><foo>&c;</foo>'); +-- This might or might not load the requested DTD, but it mustn't throw error. +SELECT XMLPARSE(DOCUMENT '<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"><chapter> </chapter>'); |