mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-01-13 13:17:36 +03:00
Heap-based buffer overread in htmlCurrentChar
For https://bugzilla.gnome.org/show_bug.cgi?id=758606 * parserInternals.c: (xmlNextChar): Add an test to catch other issues on ctxt->input corruption proactively. For non-UTF-8 charsets, xmlNextChar() failed to check for the end of the input buffer and would continuing reading. Fix this by pulling out the check for the end of the input buffer into common code, and return if we reach the end of the input buffer prematurely. * result/HTML/758606.html: Added. * result/HTML/758606.html.err: Added. * result/HTML/758606.html.sax: Added. * result/HTML/758606_2.html: Added. * result/HTML/758606_2.html.err: Added. * result/HTML/758606_2.html.sax: Added. * test/HTML/758606.html: Added test case. * test/HTML/758606_2.html: Added test case.
This commit is contained in:
parent
0090675905
commit
0bcd05c5cd
@ -55,6 +55,10 @@
|
||||
#include <libxml/globals.h>
|
||||
#include <libxml/chvalid.h>
|
||||
|
||||
#define CUR(ctxt) ctxt->input->cur
|
||||
#define END(ctxt) ctxt->input->end
|
||||
#define VALID_CTXT(ctxt) (CUR(ctxt) <= END(ctxt))
|
||||
|
||||
#include "buf.h"
|
||||
#include "enc.h"
|
||||
|
||||
@ -422,103 +426,105 @@ xmlNextChar(xmlParserCtxtPtr ctxt)
|
||||
(ctxt->input == NULL))
|
||||
return;
|
||||
|
||||
if (ctxt->charset == XML_CHAR_ENCODING_UTF8) {
|
||||
if ((*ctxt->input->cur == 0) &&
|
||||
(xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0) &&
|
||||
(ctxt->instate != XML_PARSER_COMMENT)) {
|
||||
/*
|
||||
* If we are at the end of the current entity and
|
||||
* the context allows it, we pop consumed entities
|
||||
* automatically.
|
||||
* the auto closing should be blocked in other cases
|
||||
*/
|
||||
if (!(VALID_CTXT(ctxt))) {
|
||||
xmlErrInternal(ctxt, "Parser input data memory error\n", NULL);
|
||||
ctxt->errNo = XML_ERR_INTERNAL_ERROR;
|
||||
xmlStopParser(ctxt);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*ctxt->input->cur == 0) &&
|
||||
(xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) {
|
||||
if ((ctxt->instate != XML_PARSER_COMMENT))
|
||||
xmlPopInput(ctxt);
|
||||
} else {
|
||||
const unsigned char *cur;
|
||||
unsigned char c;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2.11 End-of-Line Handling
|
||||
* the literal two-character sequence "#xD#xA" or a standalone
|
||||
* literal #xD, an XML processor must pass to the application
|
||||
* the single character #xA.
|
||||
*/
|
||||
if (*(ctxt->input->cur) == '\n') {
|
||||
ctxt->input->line++; ctxt->input->col = 1;
|
||||
} else
|
||||
ctxt->input->col++;
|
||||
if (ctxt->charset == XML_CHAR_ENCODING_UTF8) {
|
||||
const unsigned char *cur;
|
||||
unsigned char c;
|
||||
|
||||
/*
|
||||
* We are supposed to handle UTF8, check it's valid
|
||||
* From rfc2044: encoding of the Unicode values on UTF-8:
|
||||
*
|
||||
* UCS-4 range (hex.) UTF-8 octet sequence (binary)
|
||||
* 0000 0000-0000 007F 0xxxxxxx
|
||||
* 0000 0080-0000 07FF 110xxxxx 10xxxxxx
|
||||
* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
|
||||
*
|
||||
* Check for the 0x110000 limit too
|
||||
*/
|
||||
cur = ctxt->input->cur;
|
||||
/*
|
||||
* 2.11 End-of-Line Handling
|
||||
* the literal two-character sequence "#xD#xA" or a standalone
|
||||
* literal #xD, an XML processor must pass to the application
|
||||
* the single character #xA.
|
||||
*/
|
||||
if (*(ctxt->input->cur) == '\n') {
|
||||
ctxt->input->line++; ctxt->input->col = 1;
|
||||
} else
|
||||
ctxt->input->col++;
|
||||
|
||||
c = *cur;
|
||||
if (c & 0x80) {
|
||||
if (c == 0xC0)
|
||||
goto encoding_error;
|
||||
if (cur[1] == 0) {
|
||||
/*
|
||||
* We are supposed to handle UTF8, check it's valid
|
||||
* From rfc2044: encoding of the Unicode values on UTF-8:
|
||||
*
|
||||
* UCS-4 range (hex.) UTF-8 octet sequence (binary)
|
||||
* 0000 0000-0000 007F 0xxxxxxx
|
||||
* 0000 0080-0000 07FF 110xxxxx 10xxxxxx
|
||||
* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
|
||||
*
|
||||
* Check for the 0x110000 limit too
|
||||
*/
|
||||
cur = ctxt->input->cur;
|
||||
|
||||
c = *cur;
|
||||
if (c & 0x80) {
|
||||
if (c == 0xC0)
|
||||
goto encoding_error;
|
||||
if (cur[1] == 0) {
|
||||
xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
|
||||
cur = ctxt->input->cur;
|
||||
}
|
||||
if ((cur[1] & 0xc0) != 0x80)
|
||||
goto encoding_error;
|
||||
if ((c & 0xe0) == 0xe0) {
|
||||
unsigned int val;
|
||||
|
||||
if (cur[2] == 0) {
|
||||
xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
|
||||
cur = ctxt->input->cur;
|
||||
}
|
||||
if ((cur[1] & 0xc0) != 0x80)
|
||||
if ((cur[2] & 0xc0) != 0x80)
|
||||
goto encoding_error;
|
||||
if ((c & 0xe0) == 0xe0) {
|
||||
unsigned int val;
|
||||
|
||||
if (cur[2] == 0) {
|
||||
if ((c & 0xf0) == 0xf0) {
|
||||
if (cur[3] == 0) {
|
||||
xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
|
||||
cur = ctxt->input->cur;
|
||||
}
|
||||
if ((cur[2] & 0xc0) != 0x80)
|
||||
if (((c & 0xf8) != 0xf0) ||
|
||||
((cur[3] & 0xc0) != 0x80))
|
||||
goto encoding_error;
|
||||
if ((c & 0xf0) == 0xf0) {
|
||||
if (cur[3] == 0) {
|
||||
xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
|
||||
cur = ctxt->input->cur;
|
||||
}
|
||||
if (((c & 0xf8) != 0xf0) ||
|
||||
((cur[3] & 0xc0) != 0x80))
|
||||
goto encoding_error;
|
||||
/* 4-byte code */
|
||||
ctxt->input->cur += 4;
|
||||
val = (cur[0] & 0x7) << 18;
|
||||
val |= (cur[1] & 0x3f) << 12;
|
||||
val |= (cur[2] & 0x3f) << 6;
|
||||
val |= cur[3] & 0x3f;
|
||||
} else {
|
||||
/* 3-byte code */
|
||||
ctxt->input->cur += 3;
|
||||
val = (cur[0] & 0xf) << 12;
|
||||
val |= (cur[1] & 0x3f) << 6;
|
||||
val |= cur[2] & 0x3f;
|
||||
}
|
||||
if (((val > 0xd7ff) && (val < 0xe000)) ||
|
||||
((val > 0xfffd) && (val < 0x10000)) ||
|
||||
(val >= 0x110000)) {
|
||||
xmlErrEncodingInt(ctxt, XML_ERR_INVALID_CHAR,
|
||||
"Char 0x%X out of allowed range\n",
|
||||
val);
|
||||
}
|
||||
} else
|
||||
/* 2-byte code */
|
||||
ctxt->input->cur += 2;
|
||||
/* 4-byte code */
|
||||
ctxt->input->cur += 4;
|
||||
val = (cur[0] & 0x7) << 18;
|
||||
val |= (cur[1] & 0x3f) << 12;
|
||||
val |= (cur[2] & 0x3f) << 6;
|
||||
val |= cur[3] & 0x3f;
|
||||
} else {
|
||||
/* 3-byte code */
|
||||
ctxt->input->cur += 3;
|
||||
val = (cur[0] & 0xf) << 12;
|
||||
val |= (cur[1] & 0x3f) << 6;
|
||||
val |= cur[2] & 0x3f;
|
||||
}
|
||||
if (((val > 0xd7ff) && (val < 0xe000)) ||
|
||||
((val > 0xfffd) && (val < 0x10000)) ||
|
||||
(val >= 0x110000)) {
|
||||
xmlErrEncodingInt(ctxt, XML_ERR_INVALID_CHAR,
|
||||
"Char 0x%X out of allowed range\n",
|
||||
val);
|
||||
}
|
||||
} else
|
||||
/* 1-byte code */
|
||||
ctxt->input->cur++;
|
||||
/* 2-byte code */
|
||||
ctxt->input->cur += 2;
|
||||
} else
|
||||
/* 1-byte code */
|
||||
ctxt->input->cur++;
|
||||
|
||||
ctxt->nbChars++;
|
||||
if (*ctxt->input->cur == 0)
|
||||
xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
|
||||
}
|
||||
ctxt->nbChars++;
|
||||
if (*ctxt->input->cur == 0)
|
||||
xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
|
||||
} else {
|
||||
/*
|
||||
* Assume it's a fixed length encoding (1) with
|
||||
|
2
result/HTML/758606.html
Normal file
2
result/HTML/758606.html
Normal file
@ -0,0 +1,2 @@
|
||||
<!DOCTYPE >
|
||||
|
16
result/HTML/758606.html.err
Normal file
16
result/HTML/758606.html.err
Normal file
@ -0,0 +1,16 @@
|
||||
./test/HTML/758606.html:1: HTML parser error : Comment not terminated
|
||||
<!--
|
||||
<!--<!doctype
|
||||
^
|
||||
./test/HTML/758606.html:1: HTML parser error : Invalid char in CDATA 0xC
|
||||
<!--<!doctype
|
||||
^
|
||||
./test/HTML/758606.html:1: HTML parser error : Misplaced DOCTYPE declaration
|
||||
<!--<!doctype
|
||||
^
|
||||
./test/HTML/758606.html:2: HTML parser error : htmlParseDocTypeDecl : no DOCTYPE name !
|
||||
|
||||
^
|
||||
./test/HTML/758606.html:2: HTML parser error : DOCTYPE improperly terminated
|
||||
|
||||
^
|
10
result/HTML/758606.html.sax
Normal file
10
result/HTML/758606.html.sax
Normal file
@ -0,0 +1,10 @@
|
||||
SAX.setDocumentLocator()
|
||||
SAX.startDocument()
|
||||
SAX.error: Comment not terminated
|
||||
<!--
|
||||
SAX.error: Invalid char in CDATA 0xC
|
||||
SAX.error: Misplaced DOCTYPE declaration
|
||||
SAX.error: htmlParseDocTypeDecl : no DOCTYPE name !
|
||||
SAX.error: DOCTYPE improperly terminated
|
||||
SAX.internalSubset((null), , )
|
||||
SAX.endDocument()
|
2
result/HTML/758606_2.html
Normal file
2
result/HTML/758606_2.html
Normal file
@ -0,0 +1,2 @@
|
||||
<!DOCTYPE >
|
||||
<html><body><p>‘</p></body></html>
|
16
result/HTML/758606_2.html.err
Normal file
16
result/HTML/758606_2.html.err
Normal file
@ -0,0 +1,16 @@
|
||||
./test/HTML/758606_2.html:1: HTML parser error : Comment not terminated
|
||||
<!--
|
||||
<!--‘<!dOctYPE
|
||||
^
|
||||
./test/HTML/758606_2.html:1: HTML parser error : Invalid char in CDATA 0xC
|
||||
<!--‘<!dOctYPE
|
||||
^
|
||||
./test/HTML/758606_2.html:1: HTML parser error : Misplaced DOCTYPE declaration
|
||||
‘<!dOctYPE
|
||||
^
|
||||
./test/HTML/758606_2.html:2: HTML parser error : htmlParseDocTypeDecl : no DOCTYPE name !
|
||||
|
||||
^
|
||||
./test/HTML/758606_2.html:2: HTML parser error : DOCTYPE improperly terminated
|
||||
|
||||
^
|
17
result/HTML/758606_2.html.sax
Normal file
17
result/HTML/758606_2.html.sax
Normal file
@ -0,0 +1,17 @@
|
||||
SAX.setDocumentLocator()
|
||||
SAX.startDocument()
|
||||
SAX.error: Comment not terminated
|
||||
<!--
|
||||
SAX.error: Invalid char in CDATA 0xC
|
||||
SAX.startElement(html)
|
||||
SAX.startElement(body)
|
||||
SAX.startElement(p)
|
||||
SAX.characters(‘, 2)
|
||||
SAX.error: Misplaced DOCTYPE declaration
|
||||
SAX.error: htmlParseDocTypeDecl : no DOCTYPE name !
|
||||
SAX.error: DOCTYPE improperly terminated
|
||||
SAX.internalSubset((null), , )
|
||||
SAX.endElement(p)
|
||||
SAX.endElement(body)
|
||||
SAX.endElement(html)
|
||||
SAX.endDocument()
|
1
test/HTML/758606.html
Normal file
1
test/HTML/758606.html
Normal file
@ -0,0 +1 @@
|
||||
<!--<!doctype
|
1
test/HTML/758606_2.html
Normal file
1
test/HTML/758606_2.html
Normal file
@ -0,0 +1 @@
|
||||
<!--‘<!dOctYPE
|
Loading…
Reference in New Issue
Block a user