From 6a2a4e753bbba26b2de3d32f11c28691bec967dc Mon Sep 17 00:00:00 2001 From: David Kilzer Date: Mon, 23 May 2016 14:58:41 +0800 Subject: [PATCH] More format string warnings with possible format string vulnerability To: libvir-list@redhat.com For https://bugzilla.gnome.org/show_bug.cgi?id=761029 adds a new xmlEscapeFormatString() function to escape composed format strings Signed-off-by: Daniel Veillard --- libxml.h | 3 +++ relaxng.c | 3 ++- xmlschemas.c | 39 ++++++++++++++++++++++++++------------- xmlstring.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 14 deletions(-) diff --git a/libxml.h b/libxml.h index 4558b70..88e515f 100644 --- a/libxml.h +++ b/libxml.h @@ -9,6 +9,8 @@ #ifndef __XML_LIBXML_H__ #define __XML_LIBXML_H__ +#include + #ifndef NO_LARGEFILE_SOURCE #ifndef _LARGEFILE_SOURCE #define _LARGEFILE_SOURCE @@ -93,6 +95,7 @@ int __xmlInitializeDict(void); int __xmlRandom(void); #endif +XMLPUBFUN xmlChar * XMLCALL xmlEscapeFormatString(xmlChar **msg); int xmlNop(void); #ifdef IN_LIBXML diff --git a/relaxng.c b/relaxng.c index b531081..99e9901 100644 --- a/relaxng.c +++ b/relaxng.c @@ -2215,7 +2215,8 @@ xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1, snprintf(msg, 1000, "Unknown error code %d\n", err); } msg[1000 - 1] = 0; - return (xmlStrdup((xmlChar *) msg)); + xmlChar *result = xmlCharStrdup(msg); + return (xmlEscapeFormatString(&result)); } /** diff --git a/xmlschemas.c b/xmlschemas.c index 398cdd8..1bcb0f0 100644 --- a/xmlschemas.c +++ b/xmlschemas.c @@ -1769,7 +1769,7 @@ xmlSchemaFormatItemForReport(xmlChar **buf, } FREE_AND_NULL(str) - return (*buf); + return (xmlEscapeFormatString(buf)); } /** @@ -2247,6 +2247,13 @@ xmlSchemaFormatNodeForError(xmlChar ** msg, TODO return (NULL); } + + /* + * xmlSchemaFormatItemForReport() also returns an escaped format + * string, so do this before calling it below (in the future). + */ + xmlEscapeFormatString(msg); + /* * VAL TODO: The output of the given schema component is currently * disabled. @@ -2474,11 +2481,13 @@ xmlSchemaSimpleTypeErr(xmlSchemaAbstractCtxtPtr actxt, msg = xmlStrcat(msg, BAD_CAST " '"); if (type->builtInType != 0) { msg = xmlStrcat(msg, BAD_CAST "xs:"); - msg = xmlStrcat(msg, type->name); - } else - msg = xmlStrcat(msg, - xmlSchemaFormatQName(&str, - type->targetNamespace, type->name)); + str = xmlStrdup(type->name); + } else { + const xmlChar *qName = xmlSchemaFormatQName(&str, type->targetNamespace, type->name); + if (!str) + str = xmlStrdup(qName); + } + msg = xmlStrcat(msg, xmlEscapeFormatString(&str)); msg = xmlStrcat(msg, BAD_CAST "'"); FREE_AND_NULL(str); } @@ -2615,7 +2624,7 @@ xmlSchemaComplexTypeErr(xmlSchemaAbstractCtxtPtr actxt, str = xmlStrcat(str, BAD_CAST ", "); } str = xmlStrcat(str, BAD_CAST " ).\n"); - msg = xmlStrcat(msg, BAD_CAST str); + msg = xmlStrcat(msg, xmlEscapeFormatString(&str)); FREE_AND_NULL(str) } else msg = xmlStrcat(msg, BAD_CAST "\n"); @@ -3139,11 +3148,13 @@ xmlSchemaPSimpleTypeErr(xmlSchemaParserCtxtPtr ctxt, msg = xmlStrcat(msg, BAD_CAST " '"); if (type->builtInType != 0) { msg = xmlStrcat(msg, BAD_CAST "xs:"); - msg = xmlStrcat(msg, type->name); - } else - msg = xmlStrcat(msg, - xmlSchemaFormatQName(&str, - type->targetNamespace, type->name)); + str = xmlStrdup(type->name); + } else { + const xmlChar *qName = xmlSchemaFormatQName(&str, type->targetNamespace, type->name); + if (!str) + str = xmlStrdup(qName); + } + msg = xmlStrcat(msg, xmlEscapeFormatString(&str)); msg = xmlStrcat(msg, BAD_CAST "'."); FREE_AND_NULL(str); } @@ -3156,7 +3167,9 @@ xmlSchemaPSimpleTypeErr(xmlSchemaParserCtxtPtr ctxt, } if (expected) { msg = xmlStrcat(msg, BAD_CAST " Expected is '"); - msg = xmlStrcat(msg, BAD_CAST expected); + xmlChar *expectedEscaped = xmlCharStrdup(expected); + msg = xmlStrcat(msg, xmlEscapeFormatString(&expectedEscaped)); + FREE_AND_NULL(expectedEscaped); msg = xmlStrcat(msg, BAD_CAST "'.\n"); } else msg = xmlStrcat(msg, BAD_CAST "\n"); diff --git a/xmlstring.c b/xmlstring.c index c66eef3..9164d2e 100644 --- a/xmlstring.c +++ b/xmlstring.c @@ -987,5 +987,60 @@ xmlUTF8Strsub(const xmlChar *utf, int start, int len) { return(xmlUTF8Strndup(utf, len)); } +/** + * xmlEscapeFormatString: + * @msg: a pointer to the string in which to escape '%' characters. + * Must be a heap-allocated buffer created by libxml2 that may be + * returned, or that may be freed and replaced. + * + * Replaces the string pointed to by 'msg' with an escaped string. + * Returns the same string with all '%' characters escaped. + */ +xmlChar * +xmlEscapeFormatString(xmlChar **msg) +{ + xmlChar *msgPtr = NULL; + xmlChar *result = NULL; + xmlChar *resultPtr = NULL; + size_t count = 0; + size_t msgLen = 0; + size_t resultLen = 0; + + if (!msg || !*msg) + return(NULL); + + for (msgPtr = *msg; *msgPtr != '\0'; ++msgPtr) { + ++msgLen; + if (*msgPtr == '%') + ++count; + } + + if (count == 0) + return(*msg); + + resultLen = msgLen + count + 1; + result = (xmlChar *) xmlMallocAtomic(resultLen * sizeof(xmlChar)); + if (result == NULL) { + /* Clear *msg to prevent format string vulnerabilities in + out-of-memory situations. */ + xmlFree(*msg); + *msg = NULL; + xmlErrMemory(NULL, NULL); + return(NULL); + } + + for (msgPtr = *msg, resultPtr = result; *msgPtr != '\0'; ++msgPtr, ++resultPtr) { + *resultPtr = *msgPtr; + if (*msgPtr == '%') + *(++resultPtr) = '%'; + } + result[resultLen - 1] = '\0'; + + xmlFree(*msg); + *msg = result; + + return *msg; +} + #define bottom_xmlstring #include "elfgcchack.h" -- 2.5.5