Package: xmlrpc-c Version: 1.06.27-1 Followup-For: Bug #687672 User: ubuntu-de...@lists.ubuntu.com Usertags: origin-ubuntu quantal ubuntu-patch
I've also backported the same changes to 1.06.27-1 for our Lucid xmlrpc-c package. It looks to apply cleanly to the Squeeze package. Here's the changelog: * Run the tests as part of the build process - debian/patches/FTBFS-tests.patch: Fix issues when running make check. Based on upstream patches. - debian/rules: Run make check after building * SECURITY UPDATE: Denial of service via hash collisions - debian/patches/CVE-2012-0876.patch: Add random salt value to hash inputs. Based on upstream patch. - CVE-2012-0876 * SECURITY UPDATE: Denial of service via memory leak - debian/patches/CVE-2012-1148.patch: Properly reallocate memory. Based on upstream patch. - CVE-2012-1148 I hope it is of some help. -- System Information: Debian Release: wheezy/sid APT prefers quantal-updates APT policy: (500, 'quantal-updates'), (500, 'quantal-security'), (500, 'quantal') Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 3.5.0-14-generic (SMP w/4 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash
diff -u xmlrpc-c-1.06.27/debian/changelog xmlrpc-c-1.06.27/debian/changelog diff -u xmlrpc-c-1.06.27/debian/rules xmlrpc-c-1.06.27/debian/rules --- xmlrpc-c-1.06.27/debian/rules +++ xmlrpc-c-1.06.27/debian/rules @@ -55,6 +55,7 @@ build-arch-stamp: config.status dh_testdir $(MAKE) CADD=-fPIC + $(MAKE) CADD=-fPIC check touch build-arch-stamp build-indep: build-indep-stamp diff -u xmlrpc-c-1.06.27/debian/patches/series xmlrpc-c-1.06.27/debian/patches/series --- xmlrpc-c-1.06.27/debian/patches/series +++ xmlrpc-c-1.06.27/debian/patches/series @@ -5,0 +6,3 @@ +FTBFS-tests.patch +CVE-2012-0876.patch +CVE-2012-1148.patch only in patch2: unchanged: --- xmlrpc-c-1.06.27.orig/debian/patches/CVE-2012-0876.patch +++ xmlrpc-c-1.06.27/debian/patches/CVE-2012-0876.patch @@ -0,0 +1,556 @@ +Description: Prevent predictable hash collisions by using a random salt value + Backported from the upstream Expat sources to the embedded copy of Expat in + xmlrpc-c. +Origin: backport, http://xmlrpc-c.svn.sourceforge.net/viewvc/xmlrpc-c?view=revision&revision=2391 +Index: xmlrpc-c-1.06.27/lib/expat/xmlparse/xmlparse.c +=================================================================== +--- xmlrpc-c-1.06.27.orig/lib/expat/xmlparse/xmlparse.c 2012-09-06 14:54:24.144075962 -0700 ++++ xmlrpc-c-1.06.27/lib/expat/xmlparse/xmlparse.c 2012-09-06 14:54:26.416075915 -0700 +@@ -16,6 +16,8 @@ + */ + + #include <stddef.h> ++#include <limits.h> /* UINT_MAX */ ++#include <time.h> /* time() */ + + #include "xmlrpc_config.h" + #include "c_util.h" +@@ -40,6 +42,8 @@ + typedef char ICHAR; + #endif + ++static ++int setContext(XML_Parser parser, const XML_Char *context); + + #ifndef XML_NS + +@@ -256,12 +260,15 @@ + static void normalizePublicId(XML_Char *s); + static int dtdInit(DTD *); + static void dtdDestroy(DTD *); +-static int dtdCopy(DTD *newDtd, const DTD *oldDtd); +-static int copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); ++static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd); ++static int copyEntityTable(XML_Parser, HASH_TABLE *, STRING_POOL *, ++ const HASH_TABLE *); + #ifdef XML_DTD + static void dtdSwap(DTD *, DTD *); + #endif /* XML_DTD */ +-static NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize); ++static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name, ++ size_t createSize); ++static int startParsing(XML_Parser parser); + static void hashTableInit(HASH_TABLE *); + static void hashTableDestroy(HASH_TABLE *); + static void hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); +@@ -370,6 +377,7 @@ + enum XML_ParamEntityParsing m_paramEntityParsing; + XML_Parser m_parentParser; + #endif ++ unsigned long m_hash_secret_salt; + } Parser; + + #define userData (((Parser *)parser)->m_userData) +@@ -449,6 +457,7 @@ + #define parentParser (((Parser *)parser)->m_parentParser) + #define paramEntityParsing (((Parser *)parser)->m_paramEntityParsing) + #endif /* XML_DTD */ ++#define hash_secret_salt (((Parser *)parser)->m_hash_secret_salt) + + #ifdef _MSC_VER + #ifdef _DEBUG +@@ -527,6 +536,7 @@ + parentParser = 0; + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; + #endif ++ hash_secret_salt = 0; + ns = 0; + poolInit(&tempPool); + poolInit(&temp2Pool); +@@ -546,20 +556,6 @@ + XML_Parser + xmlrpc_XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) + { +- static +- const XML_Char implicitContext[] = { +- XML_T('x'), XML_T('m'), XML_T('l'), XML_T('='), +- XML_T('h'), XML_T('t'), XML_T('t'), XML_T('p'), XML_T(':'), +- XML_T('/'), XML_T('/'), XML_T('w'), XML_T('w'), XML_T('w'), +- XML_T('.'), XML_T('w'), XML_T('3'), +- XML_T('.'), XML_T('o'), XML_T('r'), XML_T('g'), +- XML_T('/'), XML_T('X'), XML_T('M'), XML_T('L'), +- XML_T('/'), XML_T('1'), XML_T('9'), XML_T('9'), XML_T('8'), +- XML_T('/'), XML_T('n'), XML_T('a'), XML_T('m'), XML_T('e'), +- XML_T('s'), XML_T('p'), XML_T('a'), XML_T('c'), XML_T('e'), +- XML_T('\0') +- }; +- + XML_Parser parser = xmlrpc_XML_ParserCreate(encodingName); + if (parser) { + XmlInitEncodingNS(&initEncoding, &encoding, 0); +@@ -567,10 +563,6 @@ + internalEncoding = XmlGetInternalEncodingNS(); + namespaceSeparator = nsSep; + } +- if (!setContext(parser, implicitContext)) { +- xmlrpc_XML_ParserFree(parser); +- return 0; +- } + return parser; + } + +@@ -618,6 +610,12 @@ + #ifdef XML_DTD + int oldParamEntityParsing = paramEntityParsing; + #endif ++ /* Note that the new parser shares the same hash secret as the old ++ parser, so that dtdCopy and copyEntityTable can lookup values ++ from hash tables associated with either parser without us having ++ to worry which hash secrets each table has. ++ */ ++ unsigned long oldhash_secret_salt = hash_secret_salt; + parser = (ns + ? xmlrpc_XML_ParserCreateNS(encodingName, namespaceSeparator) + : xmlrpc_XML_ParserCreate(encodingName)); +@@ -648,11 +646,12 @@ + if (oldExternalEntityRefHandlerArg != oldParser) + externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; + defaultExpandInternalEntities = oldDefaultExpandInternalEntities; ++ hash_secret_salt = oldhash_secret_salt; + #ifdef XML_DTD + paramEntityParsing = oldParamEntityParsing; + if (context) { + #endif /* XML_DTD */ +- if (!dtdCopy(&dtd, oldDtd) || !setContext(parser, context)) { ++ if (!dtdCopy(parser, &dtd, oldDtd) || !setContext(parser, context)) { + xmlrpc_XML_ParserFree(parser); + return 0; + } +@@ -929,6 +928,11 @@ + int + xmlrpc_XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) + { ++ if (!startParsing(parser)) { ++ errorCode = XML_ERROR_NO_MEMORY; ++ return 0; ++ } ++ + if (len == 0) { + if (!isFinal) + return 1; +@@ -990,6 +994,12 @@ + xmlrpc_XML_ParseBuffer(XML_Parser parser, int len, int isFinal) + { + const char *start = bufferPtr; ++ ++ if (!startParsing(parser)) { ++ errorCode = XML_ERROR_NO_MEMORY; ++ return 0; ++ } ++ + positionPtr = start; + bufferEnd += len; + parseEndByteIndex += len; +@@ -1323,7 +1333,7 @@ + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; +- entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0); ++ entity = (ENTITY *)lookup(parser, &dtd.generalEntities, name, 0); + poolDiscard(&dtd.pool); + if (!entity) { + if (dtd.complete || dtd.standalone) +@@ -1692,13 +1702,14 @@ + /* lookup the element type name */ + if (tagNamePtr) { + elementType = (ELEMENT_TYPE *) +- lookup(&dtd.elementTypes, tagNamePtr->str, 0); ++ lookup(parser, &dtd.elementTypes, tagNamePtr->str, 0); + if (!elementType) { + tagNamePtr->str = poolCopyString(&dtd.pool, tagNamePtr->str); + if (!tagNamePtr->str) + return XML_ERROR_NO_MEMORY; + elementType = (ELEMENT_TYPE *) +- lookup(&dtd.elementTypes, tagNamePtr->str, sizeof(ELEMENT_TYPE)); ++ lookup(parser, &dtd.elementTypes, tagNamePtr->str, ++ sizeof(ELEMENT_TYPE)); + if (!elementType) + return XML_ERROR_NO_MEMORY; + if (ns && !setElementTypePrefix(parser, elementType)) +@@ -1833,7 +1844,7 @@ + if (appAtts[i][-1] == 2) { + ATTRIBUTE_ID *id; + ((XML_Char *)(appAtts[i]))[-1] = 0; +- id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, appAtts[i], 0); ++ id = (ATTRIBUTE_ID *)lookup(parser, &dtd.attributeIds, appAtts[i], 0); + if (id->prefix->binding) { + int j; + const BINDING *b = id->prefix->binding; +@@ -2383,7 +2394,7 @@ + #endif /* XML_DTD */ + case XML_ROLE_DOCTYPE_PUBLIC_ID: + #ifdef XML_DTD +- declEntity = (ENTITY *)lookup(&dtd.paramEntities, ++ declEntity = (ENTITY *)lookup(parser, &dtd.paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) +@@ -2410,7 +2421,7 @@ + dtd.complete = 0; + #ifdef XML_DTD + if (paramEntityParsing && externalEntityRefHandler) { +- ENTITY *entity = (ENTITY *)lookup(&dtd.paramEntities, ++ ENTITY *entity = (ENTITY *)lookup(parser, &dtd.paramEntities, + externalSubsetName, + 0); + if (!externalEntityRefHandler(externalEntityRefHandlerArg, +@@ -2439,7 +2450,7 @@ + if (!name) + return XML_ERROR_NO_MEMORY; + declElementType = (ELEMENT_TYPE *) +- lookup(&dtd.elementTypes, name, sizeof(ELEMENT_TYPE)); ++ lookup(parser, &dtd.elementTypes, name, sizeof(ELEMENT_TYPE)); + if (!declElementType) + return XML_ERROR_NO_MEMORY; + if (declElementType->name != name) +@@ -2503,7 +2514,8 @@ + poolFinish(&dtd.pool); + if (internalParsedEntityDeclHandler + /* Check it's not a parameter entity */ +- && ((ENTITY *)lookup(&dtd.generalEntities, declEntity->name, 0) ++ && ((ENTITY *)lookup(parser, &dtd.generalEntities, ++ declEntity->name, 0) + == declEntity)) { + *eventEndPP = s; + internalParsedEntityDeclHandler(handlerArg, +@@ -2531,7 +2543,7 @@ + break; + #else /* XML_DTD */ + if (!declEntity) { +- declEntity = (ENTITY *)lookup(&dtd.paramEntities, ++ declEntity = (ENTITY *)lookup(parser, &dtd.paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) +@@ -2590,7 +2602,7 @@ + return XML_ERROR_NO_MEMORY; + if (dtd.complete) { + declEntity = (ENTITY *) +- lookup(&dtd.generalEntities, name, sizeof(ENTITY)); ++ lookup(parser, &dtd.generalEntities, name, sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { +@@ -2613,7 +2625,7 @@ + if (!name) + return XML_ERROR_NO_MEMORY; + declEntity = (ENTITY *) +- lookup(&dtd.paramEntities, name, sizeof(ENTITY)); ++ lookup(parser, &dtd.paramEntities, name, sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { +@@ -2736,7 +2748,7 @@ + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; +- entity = (ENTITY *)lookup(&dtd.paramEntities, name, 0); ++ entity = (ENTITY *)lookup(parser, &dtd.paramEntities, name, 0); + poolDiscard(&dtd.pool); + if (!entity) { + /* FIXME what to do if !dtd.complete? */ +@@ -3004,7 +3016,7 @@ + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; +- entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0); ++ entity = (ENTITY *)lookup(parser, &dtd.generalEntities, name, 0); + poolDiscard(&temp2Pool); + if (!entity) { + if (dtd.complete) { +@@ -3071,7 +3083,7 @@ + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; +- entity = (ENTITY *)lookup(&dtd.paramEntities, name, 0); ++ entity = (ENTITY *)lookup(parser, &dtd.paramEntities, name, 0); + poolDiscard(&tempPool); + if (!entity) { + if (enc == encoding) +@@ -3320,7 +3332,7 @@ + if (!poolAppendChar(&dtd.pool, XML_T('\0'))) + return 0; + prefix = (PREFIX *) +- lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); ++ lookup(parser, &dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); + if (!prefix) + return 0; + if (prefix->name == poolStart(&dtd.pool)) +@@ -3348,7 +3360,8 @@ + if (!name) + return 0; + ++name; +- id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, name, sizeof(ATTRIBUTE_ID)); ++ id = (ATTRIBUTE_ID *)lookup(parser, &dtd.attributeIds, name, ++ sizeof(ATTRIBUTE_ID)); + if (!id) + return 0; + if (id->name != name) +@@ -3366,7 +3379,8 @@ + if (name[5] == '\0') + id->prefix = &dtd.defaultPrefix; + else +- id->prefix = (PREFIX *)lookup(&dtd.prefixes, name + 6, sizeof(PREFIX)); ++ id->prefix = (PREFIX *)lookup(parser, &dtd.prefixes, name + 6, ++ sizeof(PREFIX)); + id->xmlns = 1; + } + else { +@@ -3381,7 +3395,8 @@ + if (!poolAppendChar(&dtd.pool, XML_T('\0'))) + return 0; + id->prefix = (PREFIX *) +- lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); ++ lookup(parser, &dtd.prefixes, poolStart(&dtd.pool), ++ sizeof(PREFIX)); + if (id->prefix->name == poolStart(&dtd.pool)) + poolFinish(&dtd.pool); + else +@@ -3474,7 +3489,8 @@ + ENTITY *e; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return 0; +- e = (ENTITY *)lookup(&dtd.generalEntities, poolStart(&tempPool), 0); ++ e = (ENTITY *)lookup(parser, &dtd.generalEntities, poolStart(&tempPool), ++ 0); + if (e) + e->open = 1; + if (*s != XML_T('\0')) +@@ -3490,7 +3506,7 @@ + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return 0; + prefix = (PREFIX *) +- lookup(&dtd.prefixes, poolStart(&tempPool), sizeof(PREFIX)); ++ lookup(parser, &dtd.prefixes, poolStart(&tempPool), sizeof(PREFIX)); + if (!prefix) + return 0; + if (prefix->name == poolStart(&tempPool)) { +@@ -3600,7 +3616,7 @@ + /* Do a deep copy of the DTD. Return 0 for out of memory; non-zero otherwise. + The new DTD has already been initialized. */ + +-static int dtdCopy(DTD *newDtd, const DTD *oldDtd) ++static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd) + { + HASH_TABLE_ITER iter; + +@@ -3615,7 +3631,7 @@ + name = poolCopyString(&(newDtd->pool), oldP->name); + if (!name) + return 0; +- if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) ++ if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) + return 0; + } + +@@ -3638,7 +3654,7 @@ + return 0; + ++name; + newA = (ATTRIBUTE_ID *) +- lookup(&(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); ++ lookup(oldParser, &(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); + if (!newA) + return 0; + newA->maybeTokenized = oldA->maybeTokenized; +@@ -3648,7 +3664,7 @@ + newA->prefix = &newDtd->defaultPrefix; + else + newA->prefix = (PREFIX *) +- lookup(&(newDtd->prefixes), oldA->prefix->name, 0); ++ lookup(oldParser, &(newDtd->prefixes), oldA->prefix->name, 0); + } + } + +@@ -3667,7 +3683,7 @@ + if (!name) + return 0; + newE = (ELEMENT_TYPE *) +- lookup(&(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); ++ lookup(oldParser, &(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); + if (!newE) + return 0; + if (oldE->nDefaultAtts) { +@@ -3678,14 +3694,15 @@ + } + if (oldE->idAtt) + newE->idAtt = (ATTRIBUTE_ID *) +- lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); ++ lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); + newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; + if (oldE->prefix) + newE->prefix = (PREFIX *) +- lookup(&(newDtd->prefixes), oldE->prefix->name, 0); ++ lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); + for (i = 0; i < newE->nDefaultAtts; i++) { + newE->defaultAtts[i].id = (ATTRIBUTE_ID *) +- lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); ++ lookup(oldParser, &(newDtd->attributeIds), ++ oldE->defaultAtts[i].id->name, 0); + newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; + if (oldE->defaultAtts[i].value) { + newE->defaultAtts[i].value = +@@ -3699,13 +3716,13 @@ + } + + /* Copy the entity tables. */ +- if (!copyEntityTable(&(newDtd->generalEntities), ++ if (!copyEntityTable(oldParser, &(newDtd->generalEntities), + &(newDtd->pool), + &(oldDtd->generalEntities))) + return 0; + + #ifdef XML_DTD +- if (!copyEntityTable(&(newDtd->paramEntities), ++ if (!copyEntityTable(oldParser, &(newDtd->paramEntities), + &(newDtd->pool), + &(oldDtd->paramEntities))) + return 0; +@@ -3716,7 +3733,8 @@ + return 1; + } + +-static int copyEntityTable(HASH_TABLE *newTable, ++static int copyEntityTable(XML_Parser oldParser, ++ HASH_TABLE *newTable, + STRING_POOL *newPool, + const HASH_TABLE *oldTable) + { +@@ -3735,7 +3753,7 @@ + name = poolCopyString(newPool, oldE->name); + if (!name) + return 0; +- newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); ++ newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); + if (!newE) + return 0; + if (oldE->systemId) { +@@ -3773,6 +3791,44 @@ + return 1; + } + ++static unsigned long ++generate_hash_secret_salt(void) ++{ ++ unsigned int seed = time(NULL) % UINT_MAX; ++ srand(seed); ++ return rand(); ++} ++ ++static int ++startParsing(XML_Parser parser) ++{ ++ static ++ const XML_Char implicitContext[] = { ++ XML_T('x'), XML_T('m'), XML_T('l'), XML_T('='), ++ XML_T('h'), XML_T('t'), XML_T('t'), XML_T('p'), XML_T(':'), ++ XML_T('/'), XML_T('/'), XML_T('w'), XML_T('w'), XML_T('w'), ++ XML_T('.'), XML_T('w'), XML_T('3'), ++ XML_T('.'), XML_T('o'), XML_T('r'), XML_T('g'), ++ XML_T('/'), XML_T('X'), XML_T('M'), XML_T('L'), ++ XML_T('/'), XML_T('1'), XML_T('9'), XML_T('9'), XML_T('8'), ++ XML_T('/'), XML_T('n'), XML_T('a'), XML_T('m'), XML_T('e'), ++ XML_T('s'), XML_T('p'), XML_T('a'), XML_T('c'), XML_T('e'), ++ XML_T('\0') ++ }; ++ ++#ifdef XML_DTD ++ if (parentParser != NULL) ++ return 1; ++#endif ++ ++ /* hash functions must be initialized before setContext() is called */ ++ if (hash_secret_salt == 0) ++ hash_secret_salt = generate_hash_secret_salt(); ++ if (parser) ++ return setContext(parser, implicitContext); ++ return 0; ++} ++ + #define INIT_SIZE 64 + + static +@@ -3785,16 +3841,16 @@ + } + + static +-unsigned long hash(KEY s) ++unsigned long hash(XML_Parser parser, KEY s) + { +- unsigned long h = 0; ++ unsigned long h = hash_secret_salt; + while (*s) + h = (h << 5) + h + (unsigned char)*s++; + return h; + } + + static +-NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize) ++NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) + { + size_t i; + if (table->size == 0) { +@@ -3805,10 +3861,10 @@ + return 0; + table->size = INIT_SIZE; + table->usedLim = INIT_SIZE / 2; +- i = hash(name) & (table->size - 1); ++ i = hash(parser, name) & (table->size - 1); + } + else { +- unsigned long h = hash(name); ++ unsigned long h = hash(parser, name); + for (i = h & (table->size - 1); + table->v[i]; + i == 0 ? i = table->size - 1 : --i) { +@@ -3826,7 +3882,7 @@ + for (i = 0; i < table->size; i++) + if (table->v[i]) { + size_t j; +- for (j = hash(table->v[i]->name) & (newSize - 1); ++ for (j = hash(parser, table->v[i]->name) & (newSize - 1); + newV[j]; + j == 0 ? j = newSize - 1 : --j) + ; +@@ -3890,6 +3946,13 @@ + return 0; + } + ++int ++XML_SetHashSalt(XML_Parser parser, ++ unsigned long hash_salt) ++{ ++ hash_secret_salt = hash_salt; ++ return 1; ++} + + static + void poolInit(STRING_POOL *pool) +Index: xmlrpc-c-1.06.27/lib/expat/xmlparse/xmlparse.h +=================================================================== +--- xmlrpc-c-1.06.27.orig/lib/expat/xmlparse/xmlparse.h 2012-08-29 11:55:00.777227617 -0700 ++++ xmlrpc-c-1.06.27/lib/expat/xmlparse/xmlparse.h 2012-09-06 14:54:35.064075737 -0700 +@@ -477,6 +477,14 @@ + xmlrpc_XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + ++/* Sets the hash salt to use for internal hash calculations. ++ Helps in preventing DoS attacks based on predicting hash ++ function behavior. This must be called before parsing is started. ++ Returns 1 if successful, 0 when called after parsing has started. ++*/ ++int ++XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); ++ + enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, only in patch2: unchanged: --- xmlrpc-c-1.06.27.orig/debian/patches/FTBFS-tests.patch +++ xmlrpc-c-1.06.27/debian/patches/FTBFS-tests.patch @@ -0,0 +1,76 @@ +Description: Fix issues when running make check + Fixes FTBFS issues from missing #include's. Also fixes bad test cases so that + make check can be used successfully. +Origin: backport, http://xmlrpc-c.svn.sourceforge.net/viewvc/xmlrpc-c?revision=1630&view=revision +Origin: upstream, http://xmlrpc-c.svn.sourceforge.net/viewvc/xmlrpc-c?revision=1564&view=revision +Origin: upstream, http://xmlrpc-c.svn.sourceforge.net/viewvc/xmlrpc-c?revision=784&view=revision +Index: xmlrpc-c-1.06.27/src/cpp/test/test.cpp +=================================================================== +--- xmlrpc-c-1.06.27.orig/src/cpp/test/test.cpp 2012-09-06 16:12:40.139979593 -0700 ++++ xmlrpc-c-1.06.27/src/cpp/test/test.cpp 2012-09-07 10:28:25.593424135 -0700 +@@ -4,6 +4,7 @@ + #include <vector> + #include <sstream> + #include <memory> ++#include <cstring> + #include <time.h> + + #include "xmlrpc-c/girerr.hpp" +Index: xmlrpc-c-1.06.27/src/cpp/test/server_abyss.cpp +=================================================================== +--- xmlrpc-c-1.06.27.orig/src/cpp/test/server_abyss.cpp 2012-09-06 16:12:40.139979593 -0700 ++++ xmlrpc-c-1.06.27/src/cpp/test/server_abyss.cpp 2012-09-07 10:26:12.241426871 -0700 +@@ -13,6 +13,7 @@ + #include <vector> + #include <sstream> + #include <memory> ++#include <cstring> + #include <time.h> + + #include "xmlrpc-c/girerr.hpp" +Index: xmlrpc-c-1.06.27/src/cpp/test/testclient.cpp +=================================================================== +--- xmlrpc-c-1.06.27.orig/src/cpp/test/testclient.cpp 2012-09-06 16:12:40.139979593 -0700 ++++ xmlrpc-c-1.06.27/src/cpp/test/testclient.cpp 2012-09-07 10:25:22.425427893 -0700 +@@ -33,7 +33,7 @@ + class sampleAddMethod : public method { + public: + sampleAddMethod() { +- this->_signature = "ii"; ++ this->_signature = "i:ii"; + this->_help = "This method adds two integers together"; + } + void +@@ -438,12 +438,28 @@ + + rpcPtr rpc2P("blowme", paramList0); + +- // This fails because the server doesn't exist +- EXPECT_ERROR(rpc2P->start(&client0, &carriageParmCurl);); ++ // This RPC fails to execute because the server doesn't exist, ++ // But libcurl "starts" it just fine. ++ rpc2P->start(&client0, &carriageParmCurl); ++ ++ transportc0.finishAsync(5000); ++ ++ TEST(rpc2P->isFinished()); ++ ++ TEST(!rpc2P->isSuccessful()); ++ ++ // Because the RPC did not return an XML-RPC failure (because the ++ // server doesn't exist), this throws: ++ EXPECT_ERROR(rpc2P->getFault();); + + rpcPtr rpc3P("blowme", paramList0); +- // This fails because the server doesn't exist +- EXPECT_ERROR(rpc3P->start(connection0);); ++ // This RPC fails to execute because the server doesn't exist ++ rpc3P->start(connection0); ++ ++ transportc0.finishAsync(5000); ++ TEST(rpc2P->isFinished()); ++ TEST(!rpc2P->isSuccessful()); ++ + #else + // This fails because there is no Curl transport in the library. + EXPECT_ERROR(clientXmlTransport_curl transportc0;); only in patch2: unchanged: --- xmlrpc-c-1.06.27.orig/debian/patches/CVE-2012-1148.patch +++ xmlrpc-c-1.06.27/debian/patches/CVE-2012-1148.patch @@ -0,0 +1,147 @@ +Description: Don't leak memory when realloc() returns NULL + Backported from the upstream Expat sources to the embedded copy of Expat in + xmlrpc-c. +Origin: backport, http://xmlrpc-c.svn.sourceforge.net/viewvc/xmlrpc-c?view=revision&revision=2393 +Index: xmlrpc-c-1.06.27/lib/expat/xmlparse/xmlparse.c +=================================================================== +--- xmlrpc-c-1.06.27.orig/lib/expat/xmlparse/xmlparse.c 2012-08-29 01:07:09.907092848 -0700 ++++ xmlrpc-c-1.06.27/lib/expat/xmlparse/xmlparse.c 2012-08-29 01:07:14.851092966 -0700 +@@ -967,15 +967,16 @@ + nLeftOver = s + len - end; + if (nLeftOver) { + if (buffer == 0 || nLeftOver > bufferLim - buffer) { ++ char *temp; + /* FIXME avoid integer overflow */ +- buffer = buffer == 0 ? malloc(len * 2) : realloc(buffer, len * 2); +- /* FIXME storage leak if realloc fails */ +- if (!buffer) { ++ temp = buffer == 0 ? malloc(len * 2) : realloc(buffer, len * 2); ++ if (!temp) { + errorCode = XML_ERROR_NO_MEMORY; + eventPtr = eventEndPtr = 0; + processor = errorProcessor; + return 0; + } ++ buffer = temp; + bufferLim = buffer + len * 2; + } + memcpy(buffer, end, nLeftOver); +@@ -1424,11 +1425,13 @@ + /* Need to guarantee that: + tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)) <= tag->bufEnd - sizeof(XML_Char) */ + if (tag->rawNameLength + (int)(sizeof(XML_Char) - 1) + (int)sizeof(XML_Char) > tag->bufEnd - tag->buf) { ++ char *temp; + int bufSize = tag->rawNameLength * 4; + bufSize = ROUND_UP(bufSize, sizeof(XML_Char)); +- tag->buf = realloc(tag->buf, bufSize); +- if (!tag->buf) ++ temp = realloc(tag->buf, bufSize); ++ if (!temp) + return XML_ERROR_NO_MEMORY; ++ tag->buf = temp; + tag->bufEnd = tag->buf + bufSize; + } + memcpy(tag->buf, tag->rawName, tag->rawNameLength); +@@ -1441,6 +1444,7 @@ + for (;;) { + const char *rawNameEnd = tag->rawName + tag->rawNameLength; + const char *fromPtr = tag->rawName; ++ char *temp; + int bufSize; + if (nextPtr) + toPtr = (XML_Char *)(tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char))); +@@ -1453,9 +1457,10 @@ + if (fromPtr == rawNameEnd) + break; + bufSize = (tag->bufEnd - tag->buf) << 1; +- tag->buf = realloc(tag->buf, bufSize); +- if (!tag->buf) ++ temp = realloc(tag->buf, bufSize); ++ if (!temp) + return XML_ERROR_NO_MEMORY; ++ tag->buf = temp; + tag->bufEnd = tag->buf + bufSize; + if (nextPtr) + tag->rawName = tag->buf; +@@ -1721,10 +1726,12 @@ + n = XmlGetAttributes(enc, attStr, attsSize, atts); + if (n + nDefaultAtts > attsSize) { + int oldAttsSize = attsSize; ++ ATTRIBUTE *temp; + attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; +- atts = realloc((void *)atts, attsSize * sizeof(ATTRIBUTE)); +- if (!atts) ++ temp = realloc((void *)atts, attsSize * sizeof(ATTRIBUTE)); ++ if (!temp) + return XML_ERROR_NO_MEMORY; ++ atts = temp; + if (n > oldAttsSize) + XmlGetAttributes(enc, attStr, n, atts); + } +@@ -1930,9 +1937,10 @@ + if (freeBindingList) { + b = freeBindingList; + if (len > b->uriAlloc) { +- b->uri = realloc(b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); +- if (!b->uri) ++ XML_Char *temp = realloc(b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); ++ if (!temp) + return 0; ++ b->uri = temp; + b->uriAlloc = len + EXPAND_SPARE; + } + freeBindingList = b->nextTagBinding; +@@ -2717,12 +2725,16 @@ + #endif /* XML_DTD */ + case XML_ROLE_GROUP_OPEN: + if (prologState.level >= groupSize) { +- if (groupSize) +- groupConnector = realloc(groupConnector, groupSize *= 2); +- else ++ if (groupSize) { ++ char *temp = realloc(groupConnector, groupSize *= 2); ++ if (!temp) ++ return XML_ERROR_NO_MEMORY; ++ groupConnector = temp; ++ } else { + groupConnector = malloc(groupSize = 32); +- if (!groupConnector) +- return XML_ERROR_NO_MEMORY; ++ if (!groupConnector) ++ return XML_ERROR_NO_MEMORY; ++ } + } + groupConnector[prologState.level] = 0; + break; +@@ -3300,10 +3312,13 @@ + malloc(type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); + } + else { ++ DEFAULT_ATTRIBUTE *temp; + type->allocDefaultAtts *= 2; +- type->defaultAtts = +- realloc(type->defaultAtts, +- type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); ++ temp = realloc(type->defaultAtts, ++ type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); ++ if (!temp) ++ return 0; ++ type->defaultAtts = temp; + } + if (!type->defaultAtts) + return 0; +@@ -4090,10 +4105,11 @@ + } + if (pool->blocks && pool->start == pool->blocks->s) { + int blockSize = (pool->end - pool->start)*2; +- pool->blocks = realloc(pool->blocks, offsetof(BLOCK, s) + +- blockSize * sizeof(XML_Char)); +- if (!pool->blocks) ++ BLOCK *temp = realloc(pool->blocks, offsetof(BLOCK, s) + ++ blockSize * sizeof(XML_Char)); ++ if (!temp) + return 0; ++ pool->blocks = temp; + pool->blocks->size = blockSize; + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s;