164 lines
6.8 KiB
Diff
164 lines
6.8 KiB
Diff
From 95aa319b65b97d8a0abb5a2eda6295c3047f2bf9 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
|
|
Date: Sun, 11 Aug 2024 21:00:00 +0200
|
|
Subject: [PATCH] Fix internal entity processing
|
|
|
|
Co-authored-by: Jann Horn <jannh@google.com>
|
|
|
|
This avoids unbounded recursion in internal entity processing
|
|
|
|
Reference: https://github.com/libexpat/libexpat/pull/973/commits/a910fbc0e1c3828702c75001647ea98b06f8acd9
|
|
Conflict: adapt processInternalEntity, internalEntityProcessor
|
|
---
|
|
lib/xmlparse.c | 91 +++++++++++++++++---------------------------------
|
|
1 file changed, 31 insertions(+), 60 deletions(-)
|
|
|
|
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
|
index 9de7676..a6f1ce2 100644
|
|
--- a/lib/xmlparse.c
|
|
+++ b/lib/xmlparse.c
|
|
@@ -2704,8 +2704,9 @@ static enum XML_Error PTRCALL
|
|
contentProcessor(XML_Parser parser, const char *start, const char *end,
|
|
const char **endPtr) {
|
|
enum XML_Error result = doContent(
|
|
- parser, 0, parser->m_encoding, start, end, endPtr,
|
|
- (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
|
|
+ parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, start, end,
|
|
+ endPtr, (XML_Bool)! parser->m_parsingStatus.finalBuffer,
|
|
+ XML_ACCOUNT_DIRECT);
|
|
if (result == XML_ERROR_NONE) {
|
|
if (! storeRawNames(parser))
|
|
return XML_ERROR_NO_MEMORY;
|
|
@@ -5866,9 +5867,6 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
|
|
|
|
static enum XML_Error
|
|
processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
|
|
- const char *textStart, *textEnd;
|
|
- const char *next;
|
|
- enum XML_Error result;
|
|
OPEN_INTERNAL_ENTITY *openEntity;
|
|
|
|
if (parser->m_freeInternalEntities) {
|
|
@@ -5885,6 +5883,7 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
|
|
entityTrackingOnOpen(parser, entity, __LINE__);
|
|
#endif
|
|
entity->processed = 0;
|
|
+ parser->m_processor = internalEntityProcessor;
|
|
openEntity->next = parser->m_openInternalEntities;
|
|
parser->m_openInternalEntities = openEntity;
|
|
openEntity->entity = entity;
|
|
@@ -5892,45 +5891,15 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
|
|
openEntity->betweenDecl = betweenDecl;
|
|
openEntity->internalEventPtr = NULL;
|
|
openEntity->internalEventEndPtr = NULL;
|
|
- textStart = (const char *)entity->textPtr;
|
|
- textEnd = (const char *)(entity->textPtr + entity->textLen);
|
|
- /* Set a safe default value in case 'next' does not get set */
|
|
- next = textStart;
|
|
-
|
|
-#ifdef XML_DTD
|
|
- if (entity->is_param) {
|
|
- int tok
|
|
- = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
|
|
- result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
|
|
- tok, next, &next, XML_FALSE, XML_FALSE,
|
|
- XML_ACCOUNT_ENTITY_EXPANSION);
|
|
- } else
|
|
-#endif /* XML_DTD */
|
|
- result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
|
|
- textStart, textEnd, &next, XML_FALSE,
|
|
- XML_ACCOUNT_ENTITY_EXPANSION);
|
|
|
|
- if (result == XML_ERROR_NONE) {
|
|
- if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
|
|
- entity->processed = (int)(next - textStart);
|
|
- parser->m_processor = internalEntityProcessor;
|
|
- } else {
|
|
-#if defined(XML_DTD) || XML_GE == 1
|
|
- entityTrackingOnClose(parser, entity, __LINE__);
|
|
-#endif /* defined(XML_DTD) || XML_GE == 1 */
|
|
- entity->open = XML_FALSE;
|
|
- parser->m_openInternalEntities = openEntity->next;
|
|
- /* put openEntity back in list of free instances */
|
|
- openEntity->next = parser->m_freeInternalEntities;
|
|
- parser->m_freeInternalEntities = openEntity;
|
|
- }
|
|
- }
|
|
- return result;
|
|
+ triggerReenter(parser);
|
|
+ return XML_ERROR_NONE;
|
|
}
|
|
|
|
static enum XML_Error PTRCALL
|
|
internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
|
const char **nextPtr) {
|
|
+ UNUSED_P(s);
|
|
ENTITY *entity;
|
|
const char *textStart, *textEnd;
|
|
const char *next;
|
|
@@ -5972,7 +5941,19 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
|
entityTrackingOnClose(parser, entity, __LINE__);
|
|
#endif
|
|
entity->open = XML_FALSE;
|
|
- parser->m_openInternalEntities = openEntity->next;
|
|
+ // Remove fully processed openEntity from open entity list. doContent call can
|
|
+ // add maximum one new entity to m_openInternalEntities since when a new
|
|
+ // entity is detected, parser will go into REENTER state and return. Therefore
|
|
+ // openEntity is either the head or next to the new head.
|
|
+ if (parser->m_openInternalEntities == openEntity) {
|
|
+ // No new entity detected during entity processing,
|
|
+ // openEntity is still the head.
|
|
+ parser->m_openInternalEntities = parser->m_openInternalEntities->next;
|
|
+ } else {
|
|
+ // New entity detected since list has a new head. openEntity is the second
|
|
+ // element.
|
|
+ parser->m_openInternalEntities->next = openEntity->next;
|
|
+ }
|
|
/* put openEntity back in list of free instances */
|
|
openEntity->next = parser->m_freeInternalEntities;
|
|
parser->m_freeInternalEntities = openEntity;
|
|
@@ -5990,29 +5971,19 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
|
return XML_ERROR_NONE;
|
|
}
|
|
|
|
-#ifdef XML_DTD
|
|
- if (entity->is_param) {
|
|
- int tok;
|
|
- parser->m_processor = prologProcessor;
|
|
- tok = XmlPrologTok(parser->m_encoding, s, end, &next);
|
|
- return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
|
|
- (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
|
|
- XML_ACCOUNT_DIRECT);
|
|
- } else
|
|
-#endif /* XML_DTD */
|
|
- {
|
|
- parser->m_processor = contentProcessor;
|
|
- /* see externalEntityContentProcessor vs contentProcessor */
|
|
- result = doContent(parser, parser->m_parentParser ? 1 : 0,
|
|
- parser->m_encoding, s, end, nextPtr,
|
|
- (XML_Bool)! parser->m_parsingStatus.finalBuffer,
|
|
- XML_ACCOUNT_DIRECT);
|
|
- if (result == XML_ERROR_NONE) {
|
|
- if (! storeRawNames(parser))
|
|
- return XML_ERROR_NO_MEMORY;
|
|
+ if (parser->m_openInternalEntities == NULL) {
|
|
+ parser->m_processor = entity->is_param ? prologProcessor : contentProcessor;
|
|
+ // internalEntityProcessor is called from callProcessor's while(1) loop,
|
|
+ // therefore "end" denotes callProcessor's "end", which denotes the end
|
|
+ // of the current buffer being parsed. Consequently, if we do not have
|
|
+ // any open entities left and have reached to the end, we must not
|
|
+ // trigger a reentry.
|
|
+ if (end == *nextPtr) {
|
|
+ return XML_ERROR_NONE;
|
|
}
|
|
- return result;
|
|
}
|
|
+ triggerReenter(parser);
|
|
+ return XML_ERROR_NONE;
|
|
}
|
|
|
|
static enum XML_Error PTRCALL
|
|
--
|
|
2.33.0
|
|
|