aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Veillard <veillard@redhat.com>2015-04-14 17:41:48 +0800
committerDaniel Veillard <veillard@redhat.com>2015-04-14 17:41:48 +0800
commit213f1fe0d76d30eaed6e5853057defc43e6df2c9 (patch)
tree31a733dc047ef2ed98aab69d2ac38acac9442421
parent8985cde70901c62d3f0f04da225e73b7344a52d7 (diff)
downloadandroid_external_libxml2-213f1fe0d76d30eaed6e5853057defc43e6df2c9.tar.gz
android_external_libxml2-213f1fe0d76d30eaed6e5853057defc43e6df2c9.tar.bz2
android_external_libxml2-213f1fe0d76d30eaed6e5853057defc43e6df2c9.zip
CVE-2015-1819 Enforce the reader to run in constant memory
One of the operation on the reader could resolve entities leading to the classic expansion issue. Make sure the buffer used for xmlreader operation is bounded. Introduce a new allocation type for the buffers for this effect.
-rw-r--r--buf.c43
-rw-r--r--include/libxml/tree.h3
-rw-r--r--xmlreader.c20
3 files changed, 63 insertions, 3 deletions
diff --git a/buf.c b/buf.c
index 6efc7b67..07922ff6 100644
--- a/buf.c
+++ b/buf.c
@@ -27,6 +27,7 @@
#include <libxml/tree.h>
#include <libxml/globals.h>
#include <libxml/tree.h>
+#include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
#include "buf.h"
#define WITH_BUFFER_COMPAT
@@ -299,7 +300,8 @@ xmlBufSetAllocationScheme(xmlBufPtr buf,
if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
(scheme == XML_BUFFER_ALLOC_EXACT) ||
(scheme == XML_BUFFER_ALLOC_HYBRID) ||
- (scheme == XML_BUFFER_ALLOC_IMMUTABLE)) {
+ (scheme == XML_BUFFER_ALLOC_IMMUTABLE) ||
+ (scheme == XML_BUFFER_ALLOC_BOUNDED)) {
buf->alloc = scheme;
if (buf->buffer)
buf->buffer->alloc = scheme;
@@ -458,6 +460,18 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
size = buf->use + len + 100;
#endif
+ if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
+ /*
+ * Used to provide parsing limits
+ */
+ if ((buf->use + len >= XML_MAX_TEXT_LENGTH) ||
+ (buf->size >= XML_MAX_TEXT_LENGTH)) {
+ xmlBufMemoryError(buf, "buffer error: text too long\n");
+ return(0);
+ }
+ if (size >= XML_MAX_TEXT_LENGTH)
+ size = XML_MAX_TEXT_LENGTH;
+ }
if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
size_t start_buf = buf->content - buf->contentIO;
@@ -739,6 +753,15 @@ xmlBufResize(xmlBufPtr buf, size_t size)
CHECK_COMPAT(buf)
if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
+ if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
+ /*
+ * Used to provide parsing limits
+ */
+ if (size >= XML_MAX_TEXT_LENGTH) {
+ xmlBufMemoryError(buf, "buffer error: text too long\n");
+ return(0);
+ }
+ }
/* Don't resize if we don't have to */
if (size < buf->size)
@@ -867,6 +890,15 @@ xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
needSize = buf->use + len + 2;
if (needSize > buf->size){
+ if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
+ /*
+ * Used to provide parsing limits
+ */
+ if (needSize >= XML_MAX_TEXT_LENGTH) {
+ xmlBufMemoryError(buf, "buffer error: text too long\n");
+ return(-1);
+ }
+ }
if (!xmlBufResize(buf, needSize)){
xmlBufMemoryError(buf, "growing buffer");
return XML_ERR_NO_MEMORY;
@@ -938,6 +970,15 @@ xmlBufAddHead(xmlBufPtr buf, const xmlChar *str, int len) {
}
needSize = buf->use + len + 2;
if (needSize > buf->size){
+ if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
+ /*
+ * Used to provide parsing limits
+ */
+ if (needSize >= XML_MAX_TEXT_LENGTH) {
+ xmlBufMemoryError(buf, "buffer error: text too long\n");
+ return(-1);
+ }
+ }
if (!xmlBufResize(buf, needSize)){
xmlBufMemoryError(buf, "growing buffer");
return XML_ERR_NO_MEMORY;
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
index 2f90717c..4a9b3bc6 100644
--- a/include/libxml/tree.h
+++ b/include/libxml/tree.h
@@ -76,7 +76,8 @@ typedef enum {
XML_BUFFER_ALLOC_EXACT, /* grow only to the minimal size */
XML_BUFFER_ALLOC_IMMUTABLE, /* immutable buffer */
XML_BUFFER_ALLOC_IO, /* special allocation scheme used for I/O */
- XML_BUFFER_ALLOC_HYBRID /* exact up to a threshold, and doubleit thereafter */
+ XML_BUFFER_ALLOC_HYBRID, /* exact up to a threshold, and doubleit thereafter */
+ XML_BUFFER_ALLOC_BOUNDED /* limit the upper size of the buffer */
} xmlBufferAllocationScheme;
/**
diff --git a/xmlreader.c b/xmlreader.c
index f19e1233..471e7e2a 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -2091,6 +2091,9 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
"xmlNewTextReader : malloc failed\n");
return(NULL);
}
+ /* no operation on a reader should require a huge buffer */
+ xmlBufSetAllocationScheme(ret->buffer,
+ XML_BUFFER_ALLOC_BOUNDED);
ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
if (ret->sax == NULL) {
xmlBufFree(ret->buffer);
@@ -3616,6 +3619,7 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) {
return(((xmlNsPtr) node)->href);
case XML_ATTRIBUTE_NODE:{
xmlAttrPtr attr = (xmlAttrPtr) node;
+ const xmlChar *ret;
if ((attr->children != NULL) &&
(attr->children->type == XML_TEXT_NODE) &&
@@ -3629,10 +3633,21 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) {
"xmlTextReaderSetup : malloc failed\n");
return (NULL);
}
+ xmlBufSetAllocationScheme(reader->buffer,
+ XML_BUFFER_ALLOC_BOUNDED);
} else
xmlBufEmpty(reader->buffer);
xmlBufGetNodeContent(reader->buffer, node);
- return(xmlBufContent(reader->buffer));
+ ret = xmlBufContent(reader->buffer);
+ if (ret == NULL) {
+ /* error on the buffer best to reallocate */
+ xmlBufFree(reader->buffer);
+ reader->buffer = xmlBufCreateSize(100);
+ xmlBufSetAllocationScheme(reader->buffer,
+ XML_BUFFER_ALLOC_BOUNDED);
+ ret = BAD_CAST "";
+ }
+ return(ret);
}
break;
}
@@ -5131,6 +5146,9 @@ xmlTextReaderSetup(xmlTextReaderPtr reader,
"xmlTextReaderSetup : malloc failed\n");
return (-1);
}
+ /* no operation on a reader should require a huge buffer */
+ xmlBufSetAllocationScheme(reader->buffer,
+ XML_BUFFER_ALLOC_BOUNDED);
if (reader->sax == NULL)
reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
if (reader->sax == NULL) {