1 |
From d12ce741a047cb0a2fa9f90c4aaa3a2298e92393 Mon Sep 17 00:00:00 2001 |
2 |
From: Daniel Veillard <veillard@redhat.com> |
3 |
Date: Tue, 19 Feb 2013 10:21:49 +0800 |
4 |
Subject: [PATCH] Detect excessive entities expansion upon replacement |
5 |
To: libvir-list@redhat.com |
6 |
|
7 |
If entities expansion in the XML parser is asked for, |
8 |
it is possble to craft relatively small input document leading |
9 |
to excessive on-the-fly content generation. |
10 |
This patch accounts for those replacement and stop parsing |
11 |
after a given threshold. it can be bypassed as usual with the |
12 |
HUGE parser option. |
13 |
|
14 |
Conflicts: |
15 |
include/libxml/parser.h |
16 |
parserInternals.c |
17 |
|
18 |
Signed-off-by: Daniel Veillard <veillard@redhat.com> |
19 |
--- |
20 |
include/libxml/parser.h | 2 ++ |
21 |
parser.c | 44 ++++++++++++++++++++++++++++++++++++++------ |
22 |
parserInternals.c | 2 ++ |
23 |
3 files changed, 42 insertions(+), 6 deletions(-) |
24 |
|
25 |
diff --git a/include/libxml/parser.h b/include/libxml/parser.h |
26 |
index 148ee03..7acb5dc 100644 |
27 |
--- a/include/libxml/parser.h |
28 |
+++ b/include/libxml/parser.h |
29 |
@@ -302,6 +302,8 @@ struct _xmlParserCtxt { |
30 |
xmlParserMode parseMode; /* the parser mode */ |
31 |
unsigned long nbentities; /* number of entities references */ |
32 |
unsigned long sizeentities; /* size of parsed entities */ |
33 |
+ |
34 |
+ unsigned long sizeentcopy; /* volume of entity copy */ |
35 |
|
36 |
/* for use by HTML non-recursive parser */ |
37 |
xmlParserNodeInfo *nodeInfo; /* Current NodeInfo */ |
38 |
diff --git a/parser.c b/parser.c |
39 |
index 9dc2232..d7da608 100644 |
40 |
--- a/parser.c |
41 |
+++ b/parser.c |
42 |
@@ -116,7 +116,7 @@ xmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID, |
43 |
*/ |
44 |
static int |
45 |
xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, |
46 |
- xmlEntityPtr ent) |
47 |
+ xmlEntityPtr ent, size_t replacement) |
48 |
{ |
49 |
size_t consumed = 0; |
50 |
|
51 |
@@ -124,7 +124,24 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, |
52 |
return (0); |
53 |
if (ctxt->lastError.code == XML_ERR_ENTITY_LOOP) |
54 |
return (1); |
55 |
- if (size != 0) { |
56 |
+ if (replacement != 0) { |
57 |
+ if (replacement < XML_MAX_TEXT_LENGTH) |
58 |
+ return(0); |
59 |
+ |
60 |
+ /* |
61 |
+ * If the volume of entity copy reaches 10 times the |
62 |
+ * amount of parsed data and over the large text threshold |
63 |
+ * then that's very likely to be an abuse. |
64 |
+ */ |
65 |
+ if (ctxt->input != NULL) { |
66 |
+ consumed = ctxt->input->consumed + |
67 |
+ (ctxt->input->cur - ctxt->input->base); |
68 |
+ } |
69 |
+ consumed += ctxt->sizeentities; |
70 |
+ |
71 |
+ if (replacement < XML_PARSER_NON_LINEAR * consumed) |
72 |
+ return(0); |
73 |
+ } else if (size != 0) { |
74 |
/* |
75 |
* Do the check based on the replacement size of the entity |
76 |
*/ |
77 |
@@ -170,7 +187,6 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, |
78 |
*/ |
79 |
return (0); |
80 |
} |
81 |
- |
82 |
xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); |
83 |
return (1); |
84 |
} |
85 |
@@ -2586,7 +2602,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, |
86 |
while (*current != 0) { /* non input consuming loop */ |
87 |
buffer[nbchars++] = *current++; |
88 |
if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { |
89 |
- if (xmlParserEntityCheck(ctxt, nbchars, ent)) |
90 |
+ if (xmlParserEntityCheck(ctxt, nbchars, ent, 0)) |
91 |
goto int_error; |
92 |
growBuffer(buffer, XML_PARSER_BUFFER_SIZE); |
93 |
} |
94 |
@@ -2628,7 +2644,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, |
95 |
while (*current != 0) { /* non input consuming loop */ |
96 |
buffer[nbchars++] = *current++; |
97 |
if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { |
98 |
- if (xmlParserEntityCheck(ctxt, nbchars, ent)) |
99 |
+ if (xmlParserEntityCheck(ctxt, nbchars, ent, 0)) |
100 |
goto int_error; |
101 |
growBuffer(buffer, XML_PARSER_BUFFER_SIZE); |
102 |
} |
103 |
@@ -7024,7 +7040,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { |
104 |
xmlFreeNodeList(list); |
105 |
return; |
106 |
} |
107 |
- if (xmlParserEntityCheck(ctxt, 0, ent)) { |
108 |
+ if (xmlParserEntityCheck(ctxt, 0, ent, 0)) { |
109 |
xmlFreeNodeList(list); |
110 |
return; |
111 |
} |
112 |
@@ -7181,6 +7197,13 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { |
113 |
xmlNodePtr nw = NULL, cur, firstChild = NULL; |
114 |
|
115 |
/* |
116 |
+ * We are copying here, make sure there is no abuse |
117 |
+ */ |
118 |
+ ctxt->sizeentcopy += ent->length; |
119 |
+ if (xmlParserEntityCheck(ctxt, 0, ent, ctxt->sizeentcopy)) |
120 |
+ return; |
121 |
+ |
122 |
+ /* |
123 |
* when operating on a reader, the entities definitions |
124 |
* are always owning the entities subtree. |
125 |
if (ctxt->parseMode == XML_PARSE_READER) |
126 |
@@ -7220,6 +7243,14 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { |
127 |
} else if (list == NULL) { |
128 |
xmlNodePtr nw = NULL, cur, next, last, |
129 |
firstChild = NULL; |
130 |
+ |
131 |
+ /* |
132 |
+ * We are copying here, make sure there is no abuse |
133 |
+ */ |
134 |
+ ctxt->sizeentcopy += ent->length; |
135 |
+ if (xmlParserEntityCheck(ctxt, 0, ent, ctxt->sizeentcopy)) |
136 |
+ return; |
137 |
+ |
138 |
/* |
139 |
* Copy the entity child list and make it the new |
140 |
* entity child list. The goal is to make sure any |
141 |
@@ -14526,6 +14557,7 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt) |
142 |
ctxt->catalogs = NULL; |
143 |
ctxt->nbentities = 0; |
144 |
ctxt->sizeentities = 0; |
145 |
+ ctxt->sizeentcopy = 0; |
146 |
xmlInitNodeInfoSeq(&ctxt->node_seq); |
147 |
|
148 |
if (ctxt->attsDefault != NULL) { |
149 |
diff --git a/parserInternals.c b/parserInternals.c |
150 |
index e53f525..b1ff158 100644 |
151 |
--- a/parserInternals.c |
152 |
+++ b/parserInternals.c |
153 |
@@ -1759,6 +1759,8 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) |
154 |
ctxt->charset = XML_CHAR_ENCODING_UTF8; |
155 |
ctxt->catalogs = NULL; |
156 |
ctxt->nbentities = 0; |
157 |
+ ctxt->sizeentities = 0; |
158 |
+ ctxt->sizeentcopy = 0; |
159 |
xmlInitNodeInfoSeq(&ctxt->node_seq); |
160 |
return(0); |
161 |
} |
162 |
-- |
163 |
1.7.11.7 |
164 |
|