summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845>2009-08-18 14:19:39 +0000
committerjoe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845>2009-08-18 14:19:39 +0000
commitca7d59a7943c3c2668c71dcb2cc74b88b444e8ea (patch)
treea84838b02874bdfe491aced8605f7a8999d6b214
parent68e86b913759e4dfcccf00f3e543cc6111a7e4f9 (diff)
downloadneon-ca7d59a7943c3c2668c71dcb2cc74b88b444e8ea.tar.gz
Merge r1687 from trunk:
Security fix for CVE-2009-2473: prevent the "billion laughs" attack against expat: * src/ne_xml.c (ne_xml_create) [HAVE_EXPAT]: Register entity decl handler. [HAVE_LIBXML]: Use xmlCtxtUseOptions interface. (entity_declaration): New function. * test/xml.c (fail_parse): Add billion laughs test case. * test/run.sh: Limit run-time CPU use to 120 seconds. git-svn-id: http://svn.webdav.org/repos/projects/neon/branches/0.28.x@1688 61a7d7f5-40b7-0310-9c16-bb0ea8cb1845
-rw-r--r--src/ne_xml.c44
-rw-r--r--test/run.sh1
-rw-r--r--test/xml.c38
3 files changed, 82 insertions, 1 deletions
diff --git a/src/ne_xml.c b/src/ne_xml.c
index 7c95a2e..3870701 100644
--- a/src/ne_xml.c
+++ b/src/ne_xml.c
@@ -1,6 +1,6 @@
/*
Wrapper interface to XML parser
- Copyright (C) 1999-2007, Joe Orton <joe@manyfish.co.uk>
+ Copyright (C) 1999-2007, 2009, Joe Orton <joe@manyfish.co.uk>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -405,6 +405,28 @@ static void end_element(void *userdata, const ne_xml_char *name)
destroy_element(elm);
}
+#if defined(HAVE_EXPAT) && XML_MAJOR_VERSION > 1
+/* Stop the parser if an entity declaration is hit. */
+static void entity_declaration(void *userData, const XML_Char *entityName,
+ int is_parameter_entity, const XML_Char *value,
+ int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName)
+{
+ ne_xml_parser *parser = userData;
+
+ NE_DEBUG(NE_DBG_XMLPARSE, "XML: entity declaration [%s]. Failing.\n",
+ entityName);
+
+ XML_StopParser(parser->parser, XML_FALSE);
+}
+#elif defined(HAVE_EXPAT)
+/* A noop default_handler. */
+static void default_handler(void *userData, const XML_Char *s, int len)
+{
+}
+#endif
+
/* Find a namespace definition for 'prefix' in given element, where
* length of prefix is 'pfxlen'. Returns the URI or NULL. */
static const char *resolve_nspace(const struct element *elm,
@@ -459,14 +481,34 @@ ne_xml_parser *ne_xml_create(void)
XML_SetCharacterDataHandler(p->parser, char_data);
XML_SetUserData(p->parser, (void *) p);
XML_SetXmlDeclHandler(p->parser, decl_handler);
+
+ /* Prevent the "billion laughs" attack against expat by disabling
+ * internal entity expansion. With 2.x, forcibly stop the parser
+ * if an entity is declared - this is safer and a more obvious
+ * failure mode. With older versions, installing a noop
+ * DefaultHandler means that internal entities will be expanded as
+ * the empty string, which is also sufficient to prevent the
+ * attack. */
+#if XML_MAJOR_VERSION > 1
+ XML_SetEntityDeclHandler(p->parser, entity_declaration);
#else
+ XML_SetDefaultHandler(p->parser, default_handler);
+#endif
+
+#else /* HAVE_LIBXML */
p->parser = xmlCreatePushParserCtxt(&sax_handler,
(void *)p, NULL, 0, NULL);
if (p->parser == NULL) {
abort();
}
+#if LIBXML_VERSION < 20602
p->parser->replaceEntities = 1;
+#else
+ /* Enable expansion of entities, and disable network access. */
+ xmlCtxtUseOptions(p->parser, XML_PARSE_NOENT | XML_PARSE_NONET);
#endif
+
+#endif /* HAVE_LIBXML || HAVE_EXPAT */
return p;
}
diff --git a/test/run.sh b/test/run.sh
index 4e9c308..71e75f5 100644
--- a/test/run.sh
+++ b/test/run.sh
@@ -3,6 +3,7 @@
rm -f debug.log child.log
ulimit -c unlimited
+ulimit -t 120
unset LANG
unset LC_MESSAGES
diff --git a/test/xml.c b/test/xml.c
index ac979a2..eafa94d 100644
--- a/test/xml.c
+++ b/test/xml.c
@@ -441,6 +441,44 @@ static int fail_parse(void)
"\xEF\xBB" PFX "<hello/>",
"\xEF" PFX "<hello/>",
+"<?xml version=\"1.0\"?>\
+<!DOCTYPE billion [\
+<!ELEMENT billion (#PCDATA)>\
+<!ENTITY laugh0 \"ha\">\
+<!ENTITY laugh1 \"&laugh0;&laugh0;\">\
+<!ENTITY laugh2 \"&laugh1;&laugh1;\">\
+<!ENTITY laugh3 \"&laugh2;&laugh2;\">\
+<!ENTITY laugh4 \"&laugh3;&laugh3;\">\
+<!ENTITY laugh5 \"&laugh4;&laugh4;\">\
+<!ENTITY laugh6 \"&laugh5;&laugh5;\">\
+<!ENTITY laugh7 \"&laugh6;&laugh6;\">\
+<!ENTITY laugh8 \"&laugh7;&laugh7;\">\
+<!ENTITY laugh9 \"&laugh8;&laugh8;\">\
+<!ENTITY laugh10 \"&laugh9;&laugh9;\">\
+<!ENTITY laugh11 \"&laugh10;&laugh10;\">\
+<!ENTITY laugh12 \"&laugh11;&laugh11;\">\
+<!ENTITY laugh13 \"&laugh12;&laugh12;\">\
+<!ENTITY laugh14 \"&laugh13;&laugh13;\">\
+<!ENTITY laugh15 \"&laugh14;&laugh14;\">\
+<!ENTITY laugh16 \"&laugh15;&laugh15;\">\
+<!ENTITY laugh17 \"&laugh16;&laugh16;\">\
+<!ENTITY laugh18 \"&laugh17;&laugh17;\">\
+<!ENTITY laugh19 \"&laugh18;&laugh18;\">\
+<!ENTITY laugh20 \"&laugh19;&laugh19;\">\
+<!ENTITY laugh21 \"&laugh20;&laugh20;\">\
+<!ENTITY laugh22 \"&laugh21;&laugh21;\">\
+<!ENTITY laugh23 \"&laugh22;&laugh22;\">\
+<!ENTITY laugh24 \"&laugh23;&laugh23;\">\
+<!ENTITY laugh25 \"&laugh24;&laugh24;\">\
+<!ENTITY laugh26 \"&laugh25;&laugh25;\">\
+<!ENTITY laugh27 \"&laugh26;&laugh26;\">\
+<!ENTITY laugh28 \"&laugh27;&laugh27;\">\
+<!ENTITY laugh29 \"&laugh28;&laugh28;\">\
+<!ENTITY laugh30 \"&laugh29;&laugh29;\">\
+]>\
+<billion>&laugh30;</billion>\
+",
+
NULL
};
int n;