expat/backport-010-CVE-2024-8176.patch
2025-03-29 17:10:03 +08:00

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