From: Florian Fainelli Date: Fri, 28 Sep 2012 10:35:14 +0000 (+0000) Subject: libxml2: backport Debian patches to fix multiple CVEs X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=c6bee75d340ea2c35f3071e26b151fa3fa44c719;p=openwrt%2Fsvn-archive%2Fpackages.git libxml2: backport Debian patches to fix multiple CVEs SVN-Revision: 33578 --- diff --git a/libs/libxml2/Makefile b/libs/libxml2/Makefile index d837ac3b3..25e93fd50 100644 --- a/libs/libxml2/Makefile +++ b/libs/libxml2/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2006-2010 OpenWrt.org +# Copyright (C) 2006-2012 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=libxml2 PKG_VERSION:=2.7.8 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=http://gd.tuwien.ac.at/languages/libxml/ \ diff --git a/libs/libxml2/patches/001-debian_CVEs.patch b/libs/libxml2/patches/001-debian_CVEs.patch new file mode 100644 index 000000000..6b34bf685 --- /dev/null +++ b/libs/libxml2/patches/001-debian_CVEs.patch @@ -0,0 +1,1028 @@ +--- libxml2-2.7.8/dict.c 2010-10-12 08:25:31.000000000 +0200 ++++ libxml2-2.7.8.patched/dict.c 2012-09-28 12:08:37.432414664 +0200 +@@ -2,7 +2,7 @@ + * dict.c: dictionary of reusable strings, just used to avoid allocation + * and freeing operations. + * +- * Copyright (C) 2003 Daniel Veillard. ++ * Copyright (C) 2003-2012 Daniel Veillard. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -19,6 +19,28 @@ + #define IN_LIBXML + #include "libxml.h" + ++#ifdef HAVE_STDLIB_H ++#include ++#endif ++#ifdef HAVE_TIME_H ++#include ++#endif ++ ++/* ++ * Following http://www.ocert.org/advisories/ocert-2011-003.html ++ * it seems that having hash randomization might be a good idea ++ * when using XML with untrusted data ++ * Note1: that it works correctly only if compiled with WITH_BIG_KEY ++ * which is the default. ++ * Note2: the fast function used for a small dict won't protect very ++ * well but since the attack is based on growing a very big hash ++ * list we will use the BigKey algo as soon as the hash size grows ++ * over MIN_DICT_SIZE so this actually works ++ */ ++#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME) ++#define DICT_RANDOMIZATION ++#endif ++ + #include + #ifdef HAVE_STDINT_H + #include +@@ -44,23 +66,23 @@ + #define WITH_BIG_KEY + + #ifdef WITH_BIG_KEY +-#define xmlDictComputeKey(dict, name, len) \ +- (((dict)->size == MIN_DICT_SIZE) ? \ +- xmlDictComputeFastKey(name, len) : \ +- xmlDictComputeBigKey(name, len)) +- +-#define xmlDictComputeQKey(dict, prefix, plen, name, len) \ +- (((prefix) == NULL) ? \ +- (xmlDictComputeKey(dict, name, len)) : \ +- (((dict)->size == MIN_DICT_SIZE) ? \ +- xmlDictComputeFastQKey(prefix, plen, name, len) : \ +- xmlDictComputeBigQKey(prefix, plen, name, len))) ++#define xmlDictComputeKey(dict, name, len) \ ++ (((dict)->size == MIN_DICT_SIZE) ? \ ++ xmlDictComputeFastKey(name, len, (dict)->seed) : \ ++ xmlDictComputeBigKey(name, len, (dict)->seed)) ++ ++#define xmlDictComputeQKey(dict, prefix, plen, name, len) \ ++ (((prefix) == NULL) ? \ ++ (xmlDictComputeKey(dict, name, len)) : \ ++ (((dict)->size == MIN_DICT_SIZE) ? \ ++ xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \ ++ xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed))) + + #else /* !WITH_BIG_KEY */ +-#define xmlDictComputeKey(dict, name, len) \ +- xmlDictComputeFastKey(name, len) +-#define xmlDictComputeQKey(dict, prefix, plen, name, len) \ +- xmlDictComputeFastQKey(prefix, plen, name, len) ++#define xmlDictComputeKey(dict, name, len) \ ++ xmlDictComputeFastKey(name, len, (dict)->seed) ++#define xmlDictComputeQKey(dict, prefix, plen, name, len) \ ++ xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) + #endif /* WITH_BIG_KEY */ + + /* +@@ -98,6 +120,8 @@ + xmlDictStringsPtr strings; + + struct _xmlDict *subdict; ++ /* used for randomization */ ++ int seed; + }; + + /* +@@ -125,6 +149,9 @@ + if ((xmlDictMutex = xmlNewRMutex()) == NULL) + return(0); + ++#ifdef DICT_RANDOMIZATION ++ srand(time(NULL)); ++#endif + xmlDictInitialized = 1; + return(1); + } +@@ -277,13 +304,13 @@ + */ + + static uint32_t +-xmlDictComputeBigKey(const xmlChar* data, int namelen) { ++xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) { + uint32_t hash; + int i; + + if (namelen <= 0 || data == NULL) return(0); + +- hash = 0; ++ hash = seed; + + for (i = 0;i < namelen; i++) { + hash += data[i]; +@@ -310,12 +337,12 @@ + */ + static unsigned long + xmlDictComputeBigQKey(const xmlChar *prefix, int plen, +- const xmlChar *name, int len) ++ const xmlChar *name, int len, int seed) + { + uint32_t hash; + int i; + +- hash = 0; ++ hash = seed; + + for (i = 0;i < plen; i++) { + hash += prefix[i]; +@@ -346,8 +373,8 @@ + * for low hash table fill. + */ + static unsigned long +-xmlDictComputeFastKey(const xmlChar *name, int namelen) { +- unsigned long value = 0L; ++xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) { ++ unsigned long value = seed; + + if (name == NULL) return(0); + value = *name; +@@ -381,9 +408,9 @@ + */ + static unsigned long + xmlDictComputeFastQKey(const xmlChar *prefix, int plen, +- const xmlChar *name, int len) ++ const xmlChar *name, int len, int seed) + { +- unsigned long value = 0L; ++ unsigned long value = (unsigned long) seed; + + if (plen == 0) + value += 30 * (unsigned long) ':'; +@@ -460,6 +487,11 @@ + dict->subdict = NULL; + if (dict->dict) { + memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry)); ++#ifdef DICT_RANDOMIZATION ++ dict->seed = rand(); ++#else ++ dict->seed = 0; ++#endif + return(dict); + } + xmlFree(dict); +@@ -486,6 +518,7 @@ + #ifdef DICT_DEBUG_PATTERNS + fprintf(stderr, "R"); + #endif ++ dict->seed = sub->seed; + dict->subdict = sub; + xmlDictReference(dict->subdict); + } +--- libxml2-2.7.8/encoding.c 2010-11-04 17:40:06.000000000 +0100 ++++ libxml2-2.7.8.patched/encoding.c 2012-09-28 12:08:37.440414665 +0200 +@@ -1928,7 +1928,7 @@ + if (in == NULL) return(-1); + + /* calculate space available */ +- written = out->size - out->use; ++ written = out->size - out->use - 1; /* count '\0' */ + toconv = in->use; + /* + * echo '' | wc -c => 38 +@@ -2059,7 +2059,7 @@ + toconv = in->use; + if (toconv == 0) + return (0); +- written = out->size - out->use; ++ written = out->size - out->use - 1; /* count '\0' */ + if (toconv * 2 >= written) { + xmlBufferGrow(out, out->size + toconv * 2); + written = out->size - out->use - 1; +--- libxml2-2.7.8/entities.c 2010-10-12 08:25:32.000000000 +0200 ++++ libxml2-2.7.8.patched/entities.c 2012-09-28 12:08:37.432414664 +0200 +@@ -528,13 +528,13 @@ + * Macro used to grow the current buffer. + */ + #define growBufferReentrant() { \ +- buffer_size *= 2; \ +- buffer = (xmlChar *) \ +- xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \ +- if (buffer == NULL) { \ +- xmlEntitiesErrMemory("xmlEncodeEntitiesReentrant: realloc failed");\ +- return(NULL); \ +- } \ ++ xmlChar *tmp; \ ++ size_t new_size = buffer_size * 2; \ ++ if (new_size < buffer_size) goto mem_error; \ ++ tmp = (xmlChar *) xmlRealloc(buffer, new_size); \ ++ if (tmp == NULL) goto mem_error; \ ++ buffer = tmp; \ ++ buffer_size = new_size; \ + } + + +@@ -555,7 +555,7 @@ + const xmlChar *cur = input; + xmlChar *buffer = NULL; + xmlChar *out = NULL; +- int buffer_size = 0; ++ size_t buffer_size = 0; + int html = 0; + + if (input == NULL) return(NULL); +@@ -574,8 +574,8 @@ + out = buffer; + + while (*cur != '\0') { +- if (out - buffer > buffer_size - 100) { +- int indx = out - buffer; ++ size_t indx = out - buffer; ++ if (indx + 100 > buffer_size) { + + growBufferReentrant(); + out = &buffer[indx]; +@@ -692,6 +692,11 @@ + } + *out = 0; + return(buffer); ++ ++mem_error: ++ xmlEntitiesErrMemory("xmlEncodeEntitiesReentrant: realloc failed"); ++ xmlFree(buffer); ++ return(NULL); + } + + /** +@@ -709,7 +714,7 @@ + const xmlChar *cur = input; + xmlChar *buffer = NULL; + xmlChar *out = NULL; +- int buffer_size = 0; ++ size_t buffer_size = 0; + if (input == NULL) return(NULL); + + /* +@@ -724,8 +729,8 @@ + out = buffer; + + while (*cur != '\0') { +- if (out - buffer > buffer_size - 10) { +- int indx = out - buffer; ++ size_t indx = out - buffer; ++ if (indx + 10 > buffer_size) { + + growBufferReentrant(); + out = &buffer[indx]; +@@ -774,6 +779,11 @@ + } + *out = 0; + return(buffer); ++ ++mem_error: ++ xmlEntitiesErrMemory("xmlEncodeSpecialChars: realloc failed"); ++ xmlFree(buffer); ++ return(NULL); + } + + /** +--- libxml2-2.7.8/hash.c 2010-10-12 08:25:32.000000000 +0200 ++++ libxml2-2.7.8.patched/hash.c 2012-09-28 12:08:37.392414663 +0200 +@@ -3,7 +3,7 @@ + * + * Reference: Your favorite introductory book on algorithms + * +- * Copyright (C) 2000 Bjorn Reese and Daniel Veillard. ++ * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above +@@ -21,6 +21,22 @@ + #include "libxml.h" + + #include ++#ifdef HAVE_STDLIB_H ++#include ++#endif ++#ifdef HAVE_TIME_H ++#include ++#endif ++ ++/* ++ * Following http://www.ocert.org/advisories/ocert-2011-003.html ++ * it seems that having hash randomization might be a good idea ++ * when using XML with untrusted data ++ */ ++#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME) ++#define HASH_RANDOMIZATION ++#endif ++ + #include + #include + #include +@@ -31,6 +47,10 @@ + + /* #define DEBUG_GROW */ + ++#ifdef HASH_RANDOMIZATION ++static int hash_initialized = 0; ++#endif ++ + /* + * A single entry in the hash table + */ +@@ -53,6 +73,9 @@ + int size; + int nbElems; + xmlDictPtr dict; ++#ifdef HASH_RANDOMIZATION ++ int random_seed; ++#endif + }; + + /* +@@ -65,6 +88,9 @@ + unsigned long value = 0L; + char ch; + ++#ifdef HASH_RANDOMIZATION ++ value = table->random_seed; ++#endif + if (name != NULL) { + value += 30 * (*name); + while ((ch = *name++) != 0) { +@@ -92,6 +118,9 @@ + unsigned long value = 0L; + char ch; + ++#ifdef HASH_RANDOMIZATION ++ value = table->random_seed; ++#endif + if (prefix != NULL) + value += 30 * (*prefix); + else +@@ -156,6 +185,13 @@ + table->table = xmlMalloc(size * sizeof(xmlHashEntry)); + if (table->table) { + memset(table->table, 0, size * sizeof(xmlHashEntry)); ++#ifdef HASH_RANDOMIZATION ++ if (!hash_initialized) { ++ srand(time(NULL)); ++ hash_initialized = 1; ++ } ++ table->random_seed = rand(); ++#endif + return(table); + } + xmlFree(table); +--- libxml2-2.7.8/parser.c 2010-11-04 16:55:45.000000000 +0100 ++++ libxml2-2.7.8.patched/parser.c 2012-09-28 12:08:37.440414665 +0200 +@@ -40,6 +40,7 @@ + #endif + + #include ++#include + #include + #include + #include +@@ -114,10 +115,10 @@ + * parser option. + */ + static int +-xmlParserEntityCheck(xmlParserCtxtPtr ctxt, unsigned long size, ++xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, + xmlEntityPtr ent) + { +- unsigned long consumed = 0; ++ size_t consumed = 0; + + if ((ctxt == NULL) || (ctxt->options & XML_PARSE_HUGE)) + return (0); +@@ -2580,15 +2581,17 @@ + + /* + * Macro used to grow the current buffer. ++ * buffer##_size is expected to be a size_t ++ * mem_error: is expected to handle memory allocation failures + */ + #define growBuffer(buffer, n) { \ + xmlChar *tmp; \ +- buffer##_size *= 2; \ +- buffer##_size += n; \ +- tmp = (xmlChar *) \ +- xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \ ++ size_t new_size = buffer##_size * 2 + n; \ ++ if (new_size < buffer##_size) goto mem_error; \ ++ tmp = (xmlChar *) xmlRealloc(buffer, new_size); \ + if (tmp == NULL) goto mem_error; \ + buffer = tmp; \ ++ buffer##_size = new_size; \ + } + + /** +@@ -2614,14 +2617,14 @@ + xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, + int what, xmlChar end, xmlChar end2, xmlChar end3) { + xmlChar *buffer = NULL; +- int buffer_size = 0; ++ size_t buffer_size = 0; ++ size_t nbchars = 0; + + xmlChar *current = NULL; + xmlChar *rep = NULL; + const xmlChar *last; + xmlEntityPtr ent; + int c,l; +- int nbchars = 0; + + if ((ctxt == NULL) || (str == NULL) || (len < 0)) + return(NULL); +@@ -2638,7 +2641,7 @@ + * allocate a translation buffer. + */ + buffer_size = XML_PARSER_BIG_BUFFER_SIZE; +- buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar)); ++ buffer = (xmlChar *) xmlMallocAtomic(buffer_size); + if (buffer == NULL) goto mem_error; + + /* +@@ -2658,7 +2661,7 @@ + if (val != 0) { + COPY_BUF(0,buffer,nbchars,val); + } +- if (nbchars > buffer_size - XML_PARSER_BUFFER_SIZE) { ++ if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { + growBuffer(buffer, XML_PARSER_BUFFER_SIZE); + } + } else if ((c == '&') && (what & XML_SUBSTITUTE_REF)) { +@@ -2676,7 +2679,7 @@ + (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { + if (ent->content != NULL) { + COPY_BUF(0,buffer,nbchars,ent->content[0]); +- if (nbchars > buffer_size - XML_PARSER_BUFFER_SIZE) { ++ if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { + growBuffer(buffer, XML_PARSER_BUFFER_SIZE); + } + } else { +@@ -2693,8 +2696,7 @@ + current = rep; + while (*current != 0) { /* non input consuming loop */ + buffer[nbchars++] = *current++; +- if (nbchars > +- buffer_size - XML_PARSER_BUFFER_SIZE) { ++ if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { + if (xmlParserEntityCheck(ctxt, nbchars, ent)) + goto int_error; + growBuffer(buffer, XML_PARSER_BUFFER_SIZE); +@@ -2708,8 +2710,8 @@ + const xmlChar *cur = ent->name; + + buffer[nbchars++] = '&'; +- if (nbchars > buffer_size - i - XML_PARSER_BUFFER_SIZE) { +- growBuffer(buffer, XML_PARSER_BUFFER_SIZE); ++ if (nbchars + i + XML_PARSER_BUFFER_SIZE > buffer_size) { ++ growBuffer(buffer, i + XML_PARSER_BUFFER_SIZE); + } + for (;i > 0;i--) + buffer[nbchars++] = *cur++; +@@ -2736,8 +2738,7 @@ + current = rep; + while (*current != 0) { /* non input consuming loop */ + buffer[nbchars++] = *current++; +- if (nbchars > +- buffer_size - XML_PARSER_BUFFER_SIZE) { ++ if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { + if (xmlParserEntityCheck(ctxt, nbchars, ent)) + goto int_error; + growBuffer(buffer, XML_PARSER_BUFFER_SIZE); +@@ -2750,8 +2751,8 @@ + } else { + COPY_BUF(l,buffer,nbchars,c); + str += l; +- if (nbchars > buffer_size - XML_PARSER_BUFFER_SIZE) { +- growBuffer(buffer, XML_PARSER_BUFFER_SIZE); ++ if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { ++ growBuffer(buffer, XML_PARSER_BUFFER_SIZE); + } + } + if (str < last) +@@ -3755,8 +3756,8 @@ + xmlChar limit = 0; + xmlChar *buf = NULL; + xmlChar *rep = NULL; +- int len = 0; +- int buf_size = 0; ++ size_t len = 0; ++ size_t buf_size = 0; + int c, l, in_space = 0; + xmlChar *current = NULL; + xmlEntityPtr ent; +@@ -3778,7 +3779,7 @@ + * allocate a translation buffer. + */ + buf_size = XML_PARSER_BUFFER_SIZE; +- buf = (xmlChar *) xmlMallocAtomic(buf_size * sizeof(xmlChar)); ++ buf = (xmlChar *) xmlMallocAtomic(buf_size); + if (buf == NULL) goto mem_error; + + /* +@@ -3795,7 +3796,7 @@ + + if (val == '&') { + if (ctxt->replaceEntities) { +- if (len > buf_size - 10) { ++ if (len + 10 > buf_size) { + growBuffer(buf, 10); + } + buf[len++] = '&'; +@@ -3804,7 +3805,7 @@ + * The reparsing will be done in xmlStringGetNodeList() + * called by the attribute() function in SAX.c + */ +- if (len > buf_size - 10) { ++ if (len + 10 > buf_size) { + growBuffer(buf, 10); + } + buf[len++] = '&'; +@@ -3814,7 +3815,7 @@ + buf[len++] = ';'; + } + } else if (val != 0) { +- if (len > buf_size - 10) { ++ if (len + 10 > buf_size) { + growBuffer(buf, 10); + } + len += xmlCopyChar(0, &buf[len], val); +@@ -3826,7 +3827,7 @@ + ctxt->nbentities += ent->owner; + if ((ent != NULL) && + (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { +- if (len > buf_size - 10) { ++ if (len + 10 > buf_size) { + growBuffer(buf, 10); + } + if ((ctxt->replaceEntities == 0) && +@@ -3854,7 +3855,7 @@ + current++; + } else + buf[len++] = *current++; +- if (len > buf_size - 10) { ++ if (len + 10 > buf_size) { + growBuffer(buf, 10); + } + } +@@ -3862,7 +3863,7 @@ + rep = NULL; + } + } else { +- if (len > buf_size - 10) { ++ if (len + 10 > buf_size) { + growBuffer(buf, 10); + } + if (ent->content != NULL) +@@ -3890,7 +3891,7 @@ + * Just output the reference + */ + buf[len++] = '&'; +- while (len > buf_size - i - 10) { ++ while (len + i + 10 > buf_size) { + growBuffer(buf, i + 10); + } + for (;i > 0;i--) +@@ -3903,7 +3904,7 @@ + if ((len != 0) || (!normalize)) { + if ((!normalize) || (!in_space)) { + COPY_BUF(l,buf,len,0x20); +- while (len > buf_size - 10) { ++ while (len + 10 > buf_size) { + growBuffer(buf, 10); + } + } +@@ -3912,7 +3913,7 @@ + } else { + in_space = 0; + COPY_BUF(l,buf,len,c); +- if (len > buf_size - 10) { ++ if (len + 10 > buf_size) { + growBuffer(buf, 10); + } + } +@@ -3937,7 +3938,18 @@ + } + } else + NEXT; +- if (attlen != NULL) *attlen = len; ++ ++ /* ++ * There we potentially risk an overflow, don't allow attribute value of ++ * lenght more than INT_MAX it is a very reasonnable assumption ! ++ */ ++ if (len >= INT_MAX) { ++ xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, ++ "AttValue lenght too long\n"); ++ goto mem_error; ++ } ++ ++ if (attlen != NULL) *attlen = (int) len; + return(buf); + + mem_error: +@@ -4949,7 +4961,8 @@ + (ctxt->sax->processingInstruction != NULL)) + ctxt->sax->processingInstruction(ctxt->userData, + target, NULL); +- ctxt->instate = state; ++ if (ctxt->instate != XML_PARSER_EOF) ++ ctxt->instate = state; + return; + } + buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); +@@ -5029,7 +5042,8 @@ + } else { + xmlFatalErr(ctxt, XML_ERR_PI_NOT_STARTED, NULL); + } +- ctxt->instate = state; ++ if (ctxt->instate != XML_PARSER_EOF) ++ ctxt->instate = state; + } + } + +@@ -9588,6 +9602,8 @@ + else + name = xmlParseStartTag(ctxt); + #endif /* LIBXML_SAX1_ENABLED */ ++ if (ctxt->instate == XML_PARSER_EOF) ++ return; + if (name == NULL) { + spacePop(ctxt); + return; +@@ -10967,6 +10983,8 @@ + else + name = xmlParseStartTag(ctxt); + #endif /* LIBXML_SAX1_ENABLED */ ++ if (ctxt->instate == XML_PARSER_EOF) ++ goto done; + if (name == NULL) { + spacePop(ctxt); + ctxt->instate = XML_PARSER_EOF; +@@ -11153,7 +11171,9 @@ + else + xmlParseEndTag1(ctxt, 0); + #endif /* LIBXML_SAX1_ENABLED */ +- if (ctxt->nameNr == 0) { ++ if (ctxt->instate == XML_PARSER_EOF) { ++ /* Nothing */ ++ } else if (ctxt->nameNr == 0) { + ctxt->instate = XML_PARSER_EPILOG; + } else { + ctxt->instate = XML_PARSER_CONTENT; +--- libxml2-2.7.8/xmllint.c 2010-11-03 15:49:11.000000000 +0100 ++++ libxml2-2.7.8.patched/xmllint.c 2012-09-28 12:08:37.436414665 +0200 +@@ -2976,7 +2976,7 @@ + printf("\t--huge : remove any internal arbitrary parser limits\n"); + printf("\t--noent : substitute entity references by their value\n"); + printf("\t--noout : don't output the result tree\n"); +- printf("\t--path 'paths': provide a set of paths for resources\n"); ++ printf("\t--path 'paths' : provide a set of paths for resources\n"); + printf("\t--load-trace : print trace of all external entites loaded\n"); + printf("\t--nonet : refuse to fetch DTDs or entities over network\n"); + printf("\t--nocompact : do not generate compact text nodes\n"); +@@ -3032,7 +3032,7 @@ + printf("\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES\n"); + printf("\t otherwise XML Catalogs starting from \n"); + printf("\t %s are activated by default\n", XML_XML_DEFAULT_CATALOG); +- printf("\t--nocatalogs: deactivate all catalogs\n"); ++ printf("\t--nocatalogs : deactivate all catalogs\n"); + #endif + printf("\t--auto : generate a small doc on the fly\n"); + #ifdef LIBXML_XINCLUDE_ENABLED +--- libxml2-2.7.8/xpath.c 2010-11-03 20:18:27.000000000 +0100 ++++ libxml2-2.7.8.patched/xpath.c 2012-09-28 12:08:37.444414664 +0200 +@@ -252,6 +252,7 @@ + "Encoding error\n", + "Char out of XML range\n", + "Invalid or incomplete context\n", ++ "Stack usage errror\n", + "?? Unknown error ??\n" /* Must be last in the list! */ + }; + #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ +@@ -2398,6 +2399,42 @@ + ************************************************************************/ + + /** ++ * xmlXPathSetFrame: ++ * @ctxt: an XPath parser context ++ * ++ * Set the callee evaluation frame ++ * ++ * Returns the previous frame value to be restored once done ++ */ ++static int ++xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { ++ int ret; ++ ++ if (ctxt == NULL) ++ return(0); ++ ret = ctxt->valueFrame; ++ ctxt->valueFrame = ctxt->valueNr; ++ return(ret); ++} ++ ++/** ++ * xmlXPathPopFrame: ++ * @ctxt: an XPath parser context ++ * @frame: the previous frame value ++ * ++ * Remove the callee evaluation frame ++ */ ++static void ++xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { ++ if (ctxt == NULL) ++ return; ++ if (ctxt->valueNr < ctxt->valueFrame) { ++ xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); ++ } ++ ctxt->valueFrame = frame; ++} ++ ++/** + * valuePop: + * @ctxt: an XPath evaluation context + * +@@ -2412,6 +2449,12 @@ + + if ((ctxt == NULL) || (ctxt->valueNr <= 0)) + return (NULL); ++ ++ if (ctxt->valueNr <= ctxt->valueFrame) { ++ xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); ++ return (NULL); ++ } ++ + ctxt->valueNr--; + if (ctxt->valueNr > 0) + ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; +@@ -3522,13 +3565,13 @@ + } else if (cur->nodeNr == cur->nodeMax) { + xmlNodePtr *temp; + +- cur->nodeMax *= 2; +- temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * ++ temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * + sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "growing nodeset\n"); + return; + } ++ cur->nodeMax *= 2; + cur->nodeTab = temp; + } + cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); +@@ -3627,14 +3670,14 @@ + } else if (cur->nodeNr == cur->nodeMax) { + xmlNodePtr *temp; + +- cur->nodeMax *= 2; +- temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * ++ temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * + sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "growing nodeset\n"); + return; + } + cur->nodeTab = temp; ++ cur->nodeMax *= 2; + } + if (val->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) val; +@@ -3738,14 +3781,14 @@ + } else if (val1->nodeNr == val1->nodeMax) { + xmlNodePtr *temp; + +- val1->nodeMax *= 2; +- temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * ++ temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * + sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + val1->nodeTab = temp; ++ val1->nodeMax *= 2; + } + if (n2->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) n2; +@@ -3907,14 +3950,14 @@ + } else if (set1->nodeNr >= set1->nodeMax) { + xmlNodePtr *temp; + +- set1->nodeMax *= 2; + temp = (xmlNodePtr *) xmlRealloc( +- set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr)); ++ set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + set1->nodeTab = temp; ++ set1->nodeMax *= 2; + } + if (n2->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) n2; +@@ -3991,14 +4034,14 @@ + } else if (set1->nodeNr >= set1->nodeMax) { + xmlNodePtr *temp; + +- set1->nodeMax *= 2; + temp = (xmlNodePtr *) xmlRealloc( +- set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr)); ++ set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + set1->nodeTab = temp; ++ set1->nodeMax *= 2; + } + set1->nodeTab[set1->nodeNr++] = n2; + } +@@ -6154,6 +6197,7 @@ + ret->valueNr = 0; + ret->valueMax = 10; + ret->value = NULL; ++ ret->valueFrame = 0; + + ret->context = ctxt; + ret->comp = comp; +@@ -11712,6 +11756,7 @@ + xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; + xmlNodePtr oldContextNode, contextNode = NULL; + xmlXPathContextPtr xpctxt = ctxt->context; ++ int frame; + + #ifdef LIBXML_XPTR_ENABLED + /* +@@ -11731,6 +11776,8 @@ + */ + exprOp = &ctxt->comp->steps[op->ch2]; + for (i = 0; i < set->nodeNr; i++) { ++ xmlXPathObjectPtr tmp; ++ + if (set->nodeTab[i] == NULL) + continue; + +@@ -11758,18 +11805,25 @@ + xmlXPathNodeSetAddUnique(contextObj->nodesetval, + contextNode); + ++ frame = xmlXPathSetFrame(ctxt); + valuePush(ctxt, contextObj); + res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); ++ tmp = valuePop(ctxt); ++ xmlXPathPopFrame(ctxt, frame); + + if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { +- xmlXPathObjectPtr tmp; +- /* pop the result */ +- tmp = valuePop(ctxt); +- xmlXPathReleaseObject(xpctxt, tmp); +- /* then pop off contextObj, which will be freed later */ +- valuePop(ctxt); ++ while (tmp != contextObj) { ++ /* ++ * Free up the result ++ * then pop off contextObj, which will be freed later ++ */ ++ xmlXPathReleaseObject(xpctxt, tmp); ++ tmp = valuePop(ctxt); ++ } + goto evaluation_error; + } ++ /* push the result back onto the stack */ ++ valuePush(ctxt, tmp); + + if (res) + pos++; +@@ -13357,6 +13411,7 @@ + xmlGenericError(xmlGenericErrorContext, + "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", + (char *) op->value4, (char *)op->value5); ++ ctxt->error = XPATH_UNDEF_PREFIX_ERROR; + return (total); + } + val = xmlXPathVariableLookupNS(ctxt->context, +@@ -13373,7 +13428,9 @@ + xmlXPathFunction func; + const xmlChar *oldFunc, *oldFuncURI; + int i; ++ int frame; + ++ frame = xmlXPathSetFrame(ctxt); + if (op->ch1 != -1) + total += + xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); +@@ -13381,15 +13438,18 @@ + xmlGenericError(xmlGenericErrorContext, + "xmlXPathCompOpEval: parameter error\n"); + ctxt->error = XPATH_INVALID_OPERAND; ++ xmlXPathPopFrame(ctxt, frame); + return (total); + } +- for (i = 0; i < op->value; i++) ++ for (i = 0; i < op->value; i++) { + if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathCompOpEval: parameter error\n"); + ctxt->error = XPATH_INVALID_OPERAND; ++ xmlXPathPopFrame(ctxt, frame); + return (total); + } ++ } + if (op->cache != NULL) + XML_CAST_FPTR(func) = op->cache; + else { +@@ -13405,6 +13465,8 @@ + xmlGenericError(xmlGenericErrorContext, + "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", + (char *)op->value4, (char *)op->value5); ++ ctxt->error = XPATH_UNDEF_PREFIX_ERROR; ++ xmlXPathPopFrame(ctxt, frame); + return (total); + } + func = xmlXPathFunctionLookupNS(ctxt->context, +@@ -13426,6 +13488,7 @@ + func(ctxt, op->value); + ctxt->context->function = oldFunc; + ctxt->context->functionURI = oldFuncURI; ++ xmlXPathPopFrame(ctxt, frame); + return (total); + } + case XPATH_OP_ARG: +@@ -14329,6 +14392,7 @@ + ctxt->valueNr = 0; + ctxt->valueMax = 10; + ctxt->value = NULL; ++ ctxt->valueFrame = 0; + } + #ifdef XPATH_STREAMING + if (ctxt->comp->stream) { +--- libxml2-2.7.8/xpointer.c 2010-10-12 08:25:33.000000000 +0200 ++++ libxml2-2.7.8.patched/xpointer.c 2012-09-28 12:08:37.428414664 +0200 +@@ -1007,21 +1007,14 @@ + NEXT; + break; + } +- *cur++ = CUR; + } else if (CUR == '(') { + level++; +- *cur++ = CUR; + } else if (CUR == '^') { +- NEXT; +- if ((CUR == ')') || (CUR == '(') || (CUR == '^')) { +- *cur++ = CUR; +- } else { +- *cur++ = '^'; +- *cur++ = CUR; +- } +- } else { +- *cur++ = CUR; ++ if ((NXT(1) == ')') || (NXT(1) == '(') || (NXT(1) == '^')) { ++ NEXT; ++ } + } ++ *cur++ = CUR; + NEXT; + } + *cur = 0; +@@ -1269,6 +1262,7 @@ + ctxt->valueNr = 0; + ctxt->valueMax = 10; + ctxt->value = NULL; ++ ctxt->valueFrame = 0; + } + SKIP_BLANKS; + if (CUR == '/') { +--- libxml2-2.7.8/libxml.h 2010-10-12 08:25:32.000000000 +0200 ++++ libxml2-2.7.8.patched/libxml.h 2012-09-28 12:08:37.432414664 +0200 +@@ -13,6 +13,9 @@ + #ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE + #endif ++#ifndef _LARGEFILE64_SOURCE ++#define _LARGEFILE64_SOURCE ++#endif + #ifndef _FILE_OFFSET_BITS + #define _FILE_OFFSET_BITS 64 + #endif +--- libxml2-2.7.8/include/libxml/xpath.h 2010-10-12 08:25:32.000000000 +0200 ++++ libxml2-2.7.8.patched/include/libxml/xpath.h 2012-09-28 12:08:37.456414665 +0200 +@@ -68,7 +68,8 @@ + XPATH_UNDEF_PREFIX_ERROR, + XPATH_ENCODING_ERROR, + XPATH_INVALID_CHAR_ERROR, +- XPATH_INVALID_CTXT ++ XPATH_INVALID_CTXT, ++ XPATH_STACK_ERROR + } xmlXPathError; + + /* +@@ -380,6 +381,8 @@ + xmlXPathCompExprPtr comp; /* the precompiled expression */ + int xptr; /* it this an XPointer expression */ + xmlNodePtr ancestor; /* used for walking preceding axis */ ++ ++ int valueFrame; /* used to limit Pop on the stack */ + }; + + /************************************************************************