Package: xmlrpc-c
Version: 1.06.27-1
Followup-For: Bug #687672
User: [email protected]
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;