diff options
author | joe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845> | 2009-08-18 14:19:39 +0000 |
---|---|---|
committer | joe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845> | 2009-08-18 14:19:39 +0000 |
commit | ca7d59a7943c3c2668c71dcb2cc74b88b444e8ea (patch) | |
tree | a84838b02874bdfe491aced8605f7a8999d6b214 | |
parent | 68e86b913759e4dfcccf00f3e543cc6111a7e4f9 (diff) | |
download | neon-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.c | 44 | ||||
-rw-r--r-- | test/run.sh | 1 | ||||
-rw-r--r-- | test/xml.c | 38 |
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 @@ -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; |