134 lines
6.1 KiB
Diff
134 lines
6.1 KiB
Diff
From 4d0be4b56cf61428ccb17fbf9953a39defb77282 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
|
|
Date: Sat, 23 Nov 2024 21:37:15 +0100
|
|
Subject: [PATCH] Fix infinite loop with indirectly recursive entities
|
|
|
|
Detection of recursive entity references are currently failing because
|
|
we process and close entities before their inner references are
|
|
processed. Since the detection works by checking wheter the referenced
|
|
entity is already open, this early close leads to wrong results. This
|
|
commit delays closing entities until their inner entities are processed
|
|
and closed. This is achieved by postponing the unsetting of the open
|
|
flag and using a new hasMore flag to check if the entity has more
|
|
elements to process.
|
|
|
|
Reference: https://github.com/libexpat/libexpat/pull/973/commits/495fb53b16d510dd0d0307fef2145437a7ad6ab1
|
|
Conflict: adapt internalEntityProcessor
|
|
---
|
|
lib/xmlparse.c | 29 +++++++++++++++++++++++------
|
|
1 file changed, 23 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
|
index 325d5e7..bad6aae 100644
|
|
--- a/lib/xmlparse.c
|
|
+++ b/lib/xmlparse.c
|
|
@@ -303,6 +303,10 @@ typedef struct {
|
|
const XML_Char *publicId;
|
|
const XML_Char *notation;
|
|
XML_Bool open;
|
|
+ XML_Bool hasMore; /* true if entity has not been completely processed */
|
|
+ /* An entity can be open while being already completely processed (hasMore ==
|
|
+ XML_FALSE). The reason is the delayed closing of entities until their inner
|
|
+ entities are processed and closed */
|
|
XML_Bool is_param;
|
|
XML_Bool is_internal; /* true if declared in internal subset outside PE */
|
|
} ENTITY;
|
|
@@ -5970,6 +5974,7 @@ processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl,
|
|
return XML_ERROR_NO_MEMORY;
|
|
}
|
|
entity->open = XML_TRUE;
|
|
+ entity->hasMore = XML_TRUE;
|
|
#if XML_GE == 1
|
|
entityTrackingOnOpen(parser, entity, __LINE__);
|
|
#endif
|
|
@@ -6004,7 +6009,7 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
|
return XML_ERROR_UNEXPECTED_STATE;
|
|
|
|
entity = openEntity->entity;
|
|
- if (entity->open) {
|
|
+ if (entity->hasMore) {
|
|
textStart = ((const char *)entity->textPtr) + entity->processed;
|
|
textEnd = (const char *)(entity->textPtr + entity->textLen);
|
|
/* Set a safe default value in case 'next' does not get set */
|
|
@@ -6036,7 +6041,10 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
|
return result;
|
|
}
|
|
|
|
- entity->open = XML_FALSE;
|
|
+ // Entity is complete. We cannot close it here since we need to first
|
|
+ // process its possible inner entities (which are added to the
|
|
+ // m_openInternalEntities during doProlog or doContent calls above)
|
|
+ entity->hasMore = XML_FALSE;
|
|
triggerReenter(parser);
|
|
return result;
|
|
}
|
|
@@ -6044,6 +6052,7 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
|
#if defined(XML_DTD) || XML_GE == 1
|
|
entityTrackingOnClose(parser, entity, __LINE__);
|
|
#endif
|
|
+ entity->open = XML_FALSE;
|
|
// 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
|
|
@@ -6108,7 +6117,7 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
|
= (const char *)(entity->textPtr + entity->textLen);
|
|
/* Set a safe default value in case 'next' does not get set */
|
|
const char *nextInEntity = textStart;
|
|
- if (entity->open) {
|
|
+ if (entity->hasMore) {
|
|
result = appendAttributeValue(
|
|
parser, parser->m_internalEncoding, isCdata, textStart, textEnd,
|
|
pool, XML_ACCOUNT_ENTITY_EXPANSION, &nextInEntity);
|
|
@@ -6123,7 +6132,10 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
|
continue;
|
|
}
|
|
|
|
- entity->open = XML_FALSE;
|
|
+ // Entity is complete. We cannot close it here since we need to first
|
|
+ // process its possible inner entities (which are added to the
|
|
+ // m_openAttributeEntities during appendAttributeValue)
|
|
+ entity->hasMore = XML_FALSE;
|
|
triggerReenter(parser);
|
|
continue;
|
|
}
|
|
@@ -6131,6 +6143,7 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
|
#if XML_GE == 1
|
|
entityTrackingOnClose(parser, entity, __LINE__);
|
|
#endif
|
|
+ entity->open = XML_FALSE;
|
|
// Remove fully processed openEntity from open entity list.
|
|
// appendAttributeValue call can add maximum one new entity to
|
|
// m_openAttributeEntities since when a new entity is detected, parser
|
|
@@ -6567,7 +6580,7 @@ callStoreEntityValue(XML_Parser parser, const ENCODING *enc,
|
|
= (const char *)(entity->textPtr + entity->textLen);
|
|
/* Set a safe default value in case 'next' does not get set */
|
|
const char *nextInEntity = textStart;
|
|
- if (entity->open) {
|
|
+ if (entity->hasMore) {
|
|
result = storeEntityValue(parser, parser->m_internalEncoding, textStart,
|
|
textEnd, XML_ACCOUNT_ENTITY_EXPANSION,
|
|
&nextInEntity);
|
|
@@ -6582,7 +6595,10 @@ callStoreEntityValue(XML_Parser parser, const ENCODING *enc,
|
|
continue;
|
|
}
|
|
|
|
- entity->open = XML_FALSE;
|
|
+ // Entity is complete. We cannot close it here since we need to first
|
|
+ // process its possible inner entities (which are added to the
|
|
+ // m_openValueEntities during storeEntityValue)
|
|
+ entity->hasMore = XML_FALSE;
|
|
triggerReenter(parser);
|
|
continue;
|
|
}
|
|
@@ -6590,6 +6606,7 @@ callStoreEntityValue(XML_Parser parser, const ENCODING *enc,
|
|
# if XML_GE == 1
|
|
entityTrackingOnClose(parser, entity, __LINE__);
|
|
# endif
|
|
+ entity->open = XML_FALSE;
|
|
// Remove fully processed openEntity from open entity list.
|
|
// appendAttributeValue call can add maximum one new entity to
|
|
// m_openValueEntities since when a new entity is detected, parser
|
|
--
|
|
2.33.0
|
|
|