More format string warnings with possible format string vulnerability
For https://bugzilla.gnome.org/show_bug.cgi?id=761029
adds a new xmlEscapeFormatString() function to escape composed format
strings
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 <libxml/xmlstring.h>
+
#ifndef NO_LARGEFILE_SOURCE
#ifndef _LARGEFILE_SOURCE
#define _LARGEFILE_SOURCE
@@ -93,6 +95,7 @@
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 345f354..56a3344 100644
--- a/relaxng.c
+++ b/relaxng.c
@@ -2215,7 +2215,8 @@
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 76f2119..e1b3a4f 100644
--- a/xmlschemas.c
+++ b/xmlschemas.c
@@ -1769,7 +1769,7 @@
}
FREE_AND_NULL(str)
- return (*buf);
+ return (xmlEscapeFormatString(buf));
}
/**
@@ -2249,6 +2249,13 @@
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.
@@ -2476,11 +2483,13 @@
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);
}
@@ -2617,7 +2626,7 @@
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");
@@ -3141,11 +3150,13 @@
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);
}
@@ -3158,7 +3169,9 @@
}
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 42e380f..cc85777 100644
--- a/xmlstring.c
+++ b/xmlstring.c
@@ -987,5 +987,60 @@
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"