|
1 https://git.gnome.org/browse/libxml2/commit/?id=23f05e0c33987d6605387b300c4be5da2120a7ab |
|
2 CVE-2013-0338 |
|
3 |
|
4 From 23f05e0c33987d6605387b300c4be5da2120a7ab Mon Sep 17 00:00:00 2001 |
|
5 From: Daniel Veillard <[email protected]> |
|
6 Date: Tue, 19 Feb 2013 02:21:49 +0000 |
|
7 Subject: Detect excessive entities expansion upon replacement |
|
8 |
|
9 If entities expansion in the XML parser is asked for, |
|
10 it is possble to craft relatively small input document leading |
|
11 to excessive on-the-fly content generation. |
|
12 This patch accounts for those replacement and stop parsing |
|
13 after a given threshold. it can be bypassed as usual with the |
|
14 HUGE parser option. |
|
15 --- |
|
16 diff --git a/include/libxml/parser.h b/include/libxml/parser.h |
|
17 index e1346e4..3f5730d 100644 |
|
18 --- a/include/libxml/parser.h |
|
19 +++ b/include/libxml/parser.h |
|
20 @@ -310,6 +310,7 @@ struct _xmlParserCtxt { |
|
21 xmlParserNodeInfo *nodeInfoTab; /* array of nodeInfos */ |
|
22 |
|
23 int input_id; /* we need to label inputs */ |
|
24 + unsigned long sizeentcopy; /* volume of entity copy */ |
|
25 }; |
|
26 |
|
27 /** |
|
28 diff --git a/parser.c b/parser.c |
|
29 index 91f8c90..ddf3b5b 100644 |
|
30 --- a/parser.c |
|
31 +++ b/parser.c |
|
32 @@ -122,7 +122,7 @@ xmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID, |
|
33 */ |
|
34 static int |
|
35 xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, |
|
36 - xmlEntityPtr ent) |
|
37 + xmlEntityPtr ent, size_t replacement) |
|
38 { |
|
39 size_t consumed = 0; |
|
40 |
|
41 @@ -130,7 +130,24 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, |
|
42 return (0); |
|
43 if (ctxt->lastError.code == XML_ERR_ENTITY_LOOP) |
|
44 return (1); |
|
45 - if (size != 0) { |
|
46 + if (replacement != 0) { |
|
47 + if (replacement < XML_MAX_TEXT_LENGTH) |
|
48 + return(0); |
|
49 + |
|
50 + /* |
|
51 + * If the volume of entity copy reaches 10 times the |
|
52 + * amount of parsed data and over the large text threshold |
|
53 + * then that's very likely to be an abuse. |
|
54 + */ |
|
55 + if (ctxt->input != NULL) { |
|
56 + consumed = ctxt->input->consumed + |
|
57 + (ctxt->input->cur - ctxt->input->base); |
|
58 + } |
|
59 + consumed += ctxt->sizeentities; |
|
60 + |
|
61 + if (replacement < XML_PARSER_NON_LINEAR * consumed) |
|
62 + return(0); |
|
63 + } else if (size != 0) { |
|
64 /* |
|
65 * Do the check based on the replacement size of the entity |
|
66 */ |
|
67 @@ -176,7 +193,6 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, |
|
68 */ |
|
69 return (0); |
|
70 } |
|
71 - |
|
72 xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); |
|
73 return (1); |
|
74 } |
|
75 @@ -2743,7 +2759,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, |
|
76 while (*current != 0) { /* non input consuming loop */ |
|
77 buffer[nbchars++] = *current++; |
|
78 if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { |
|
79 - if (xmlParserEntityCheck(ctxt, nbchars, ent)) |
|
80 + if (xmlParserEntityCheck(ctxt, nbchars, ent, 0)) |
|
81 goto int_error; |
|
82 growBuffer(buffer, XML_PARSER_BUFFER_SIZE); |
|
83 } |
|
84 @@ -2785,7 +2801,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, |
|
85 while (*current != 0) { /* non input consuming loop */ |
|
86 buffer[nbchars++] = *current++; |
|
87 if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { |
|
88 - if (xmlParserEntityCheck(ctxt, nbchars, ent)) |
|
89 + if (xmlParserEntityCheck(ctxt, nbchars, ent, 0)) |
|
90 goto int_error; |
|
91 growBuffer(buffer, XML_PARSER_BUFFER_SIZE); |
|
92 } |
|
93 @@ -7203,7 +7219,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { |
|
94 xmlFreeNodeList(list); |
|
95 return; |
|
96 } |
|
97 - if (xmlParserEntityCheck(ctxt, 0, ent)) { |
|
98 + if (xmlParserEntityCheck(ctxt, 0, ent, 0)) { |
|
99 xmlFreeNodeList(list); |
|
100 return; |
|
101 } |
|
102 @@ -7361,6 +7377,13 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { |
|
103 xmlNodePtr nw = NULL, cur, firstChild = NULL; |
|
104 |
|
105 /* |
|
106 + * We are copying here, make sure there is no abuse |
|
107 + */ |
|
108 + ctxt->sizeentcopy += ent->length; |
|
109 + if (xmlParserEntityCheck(ctxt, 0, ent, ctxt->sizeentcopy)) |
|
110 + return; |
|
111 + |
|
112 + /* |
|
113 * when operating on a reader, the entities definitions |
|
114 * are always owning the entities subtree. |
|
115 if (ctxt->parseMode == XML_PARSE_READER) |
|
116 @@ -7400,6 +7423,14 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { |
|
117 } else if ((list == NULL) || (ctxt->inputNr > 0)) { |
|
118 xmlNodePtr nw = NULL, cur, next, last, |
|
119 firstChild = NULL; |
|
120 + |
|
121 + /* |
|
122 + * We are copying here, make sure there is no abuse |
|
123 + */ |
|
124 + ctxt->sizeentcopy += ent->length; |
|
125 + if (xmlParserEntityCheck(ctxt, 0, ent, ctxt->sizeentcopy)) |
|
126 + return; |
|
127 + |
|
128 /* |
|
129 * Copy the entity child list and make it the new |
|
130 * entity child list. The goal is to make sure any |
|
131 @@ -14767,6 +14798,7 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt) |
|
132 ctxt->catalogs = NULL; |
|
133 ctxt->nbentities = 0; |
|
134 ctxt->sizeentities = 0; |
|
135 + ctxt->sizeentcopy = 0; |
|
136 xmlInitNodeInfoSeq(&ctxt->node_seq); |
|
137 |
|
138 if (ctxt->attsDefault != NULL) { |
|
139 diff --git a/parserInternals.c b/parserInternals.c |
|
140 index 02032d5..f8a7041 100644 |
|
141 --- a/parserInternals.c |
|
142 +++ b/parserInternals.c |
|
143 @@ -1719,6 +1719,8 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) |
|
144 ctxt->charset = XML_CHAR_ENCODING_UTF8; |
|
145 ctxt->catalogs = NULL; |
|
146 ctxt->nbentities = 0; |
|
147 + ctxt->sizeentities = 0; |
|
148 + ctxt->sizeentcopy = 0; |
|
149 ctxt->input_id = 1; |
|
150 xmlInitNodeInfoSeq(&ctxt->node_seq); |
|
151 return(0); |
|
152 -- |
|
153 cgit v0.9.1 |