Commit 213f1fe0 authored by Daniel Veillard's avatar Daniel Veillard

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.
parent 8985cde7
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <libxml/tree.h> #include <libxml/tree.h>
#include <libxml/globals.h> #include <libxml/globals.h>
#include <libxml/tree.h> #include <libxml/tree.h>
#include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
#include "buf.h" #include "buf.h"
#define WITH_BUFFER_COMPAT #define WITH_BUFFER_COMPAT
...@@ -299,7 +300,8 @@ xmlBufSetAllocationScheme(xmlBufPtr buf, ...@@ -299,7 +300,8 @@ xmlBufSetAllocationScheme(xmlBufPtr buf,
if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) || if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
(scheme == XML_BUFFER_ALLOC_EXACT) || (scheme == XML_BUFFER_ALLOC_EXACT) ||
(scheme == XML_BUFFER_ALLOC_HYBRID) || (scheme == XML_BUFFER_ALLOC_HYBRID) ||
(scheme == XML_BUFFER_ALLOC_IMMUTABLE)) { (scheme == XML_BUFFER_ALLOC_IMMUTABLE) ||
(scheme == XML_BUFFER_ALLOC_BOUNDED)) {
buf->alloc = scheme; buf->alloc = scheme;
if (buf->buffer) if (buf->buffer)
buf->buffer->alloc = scheme; buf->buffer->alloc = scheme;
...@@ -458,6 +460,18 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) { ...@@ -458,6 +460,18 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
size = buf->use + len + 100; size = buf->use + len + 100;
#endif #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)) { if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
size_t start_buf = buf->content - buf->contentIO; size_t start_buf = buf->content - buf->contentIO;
...@@ -739,6 +753,15 @@ xmlBufResize(xmlBufPtr buf, size_t size) ...@@ -739,6 +753,15 @@ xmlBufResize(xmlBufPtr buf, size_t size)
CHECK_COMPAT(buf) CHECK_COMPAT(buf)
if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); 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 */ /* Don't resize if we don't have to */
if (size < buf->size) if (size < buf->size)
...@@ -867,6 +890,15 @@ xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) { ...@@ -867,6 +890,15 @@ xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
needSize = buf->use + len + 2; needSize = buf->use + len + 2;
if (needSize > buf->size){ 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)){ if (!xmlBufResize(buf, needSize)){
xmlBufMemoryError(buf, "growing buffer"); xmlBufMemoryError(buf, "growing buffer");
return XML_ERR_NO_MEMORY; return XML_ERR_NO_MEMORY;
...@@ -938,6 +970,15 @@ xmlBufAddHead(xmlBufPtr buf, const xmlChar *str, int len) { ...@@ -938,6 +970,15 @@ xmlBufAddHead(xmlBufPtr buf, const xmlChar *str, int len) {
} }
needSize = buf->use + len + 2; needSize = buf->use + len + 2;
if (needSize > buf->size){ 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)){ if (!xmlBufResize(buf, needSize)){
xmlBufMemoryError(buf, "growing buffer"); xmlBufMemoryError(buf, "growing buffer");
return XML_ERR_NO_MEMORY; return XML_ERR_NO_MEMORY;
......
...@@ -76,7 +76,8 @@ typedef enum { ...@@ -76,7 +76,8 @@ typedef enum {
XML_BUFFER_ALLOC_EXACT, /* grow only to the minimal size */ XML_BUFFER_ALLOC_EXACT, /* grow only to the minimal size */
XML_BUFFER_ALLOC_IMMUTABLE, /* immutable buffer */ XML_BUFFER_ALLOC_IMMUTABLE, /* immutable buffer */
XML_BUFFER_ALLOC_IO, /* special allocation scheme used for I/O */ 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; } xmlBufferAllocationScheme;
/** /**
......
...@@ -2091,6 +2091,9 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { ...@@ -2091,6 +2091,9 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
"xmlNewTextReader : malloc failed\n"); "xmlNewTextReader : malloc failed\n");
return(NULL); 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)); ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
if (ret->sax == NULL) { if (ret->sax == NULL) {
xmlBufFree(ret->buffer); xmlBufFree(ret->buffer);
...@@ -3616,6 +3619,7 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) { ...@@ -3616,6 +3619,7 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) {
return(((xmlNsPtr) node)->href); return(((xmlNsPtr) node)->href);
case XML_ATTRIBUTE_NODE:{ case XML_ATTRIBUTE_NODE:{
xmlAttrPtr attr = (xmlAttrPtr) node; xmlAttrPtr attr = (xmlAttrPtr) node;
const xmlChar *ret;
if ((attr->children != NULL) && if ((attr->children != NULL) &&
(attr->children->type == XML_TEXT_NODE) && (attr->children->type == XML_TEXT_NODE) &&
...@@ -3629,10 +3633,21 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) { ...@@ -3629,10 +3633,21 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) {
"xmlTextReaderSetup : malloc failed\n"); "xmlTextReaderSetup : malloc failed\n");
return (NULL); return (NULL);
} }
xmlBufSetAllocationScheme(reader->buffer,
XML_BUFFER_ALLOC_BOUNDED);
} else } else
xmlBufEmpty(reader->buffer); xmlBufEmpty(reader->buffer);
xmlBufGetNodeContent(reader->buffer, node); 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; break;
} }
...@@ -5131,6 +5146,9 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, ...@@ -5131,6 +5146,9 @@ xmlTextReaderSetup(xmlTextReaderPtr reader,
"xmlTextReaderSetup : malloc failed\n"); "xmlTextReaderSetup : malloc failed\n");
return (-1); return (-1);
} }
/* no operation on a reader should require a huge buffer */
xmlBufSetAllocationScheme(reader->buffer,
XML_BUFFER_ALLOC_BOUNDED);
if (reader->sax == NULL) if (reader->sax == NULL)
reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler)); reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
if (reader->sax == NULL) { if (reader->sax == NULL) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment