Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
49c0d577ac
!135 CVE-2024-8176的后置补丁
From: @zhuofeng6 
Reviewed-by: @hubin95 
Signed-off-by: @hubin95
2025-04-16 06:11:34 +00:00
zhuofeng
7e7d820f4e
backport upstream patches
Signed-off-by: zhuofeng <1107893276@qq.com>
2025-04-08 02:25:29 +00:00
openeuler-ci-bot
61225c7922
!130 fix CVE-2024-8176
From: @zhuofeng6 
Reviewed-by: @dillon_chen 
Signed-off-by: @dillon_chen
2025-04-02 08:05:09 +00:00
zhuofeng
2fc4b29f0d fix CVE-2024-8176 2025-03-29 17:10:03 +08:00
openeuler-ci-bot
b908834a6e
!123 [sync] PR-116: add testcase for CVE-2024-50602
From: @openeuler-sync-bot 
Reviewed-by: @dillon_chen 
Signed-off-by: @dillon_chen
2024-10-30 08:11:34 +00:00
liningjie
ca53218800 add testcase for CVE-2024-50602
(cherry picked from commit 18500b9c8879a75ab6029cd51e930a5c513c3fc0)
2024-10-30 15:49:09 +08:00
openeuler-ci-bot
1ab989a431
!115 [sync] PR-113: fix CVE-2024-20602
From: @openeuler-sync-bot 
Reviewed-by: @dillon_chen 
Signed-off-by: @dillon_chen
2024-10-30 07:28:35 +00:00
liningjie
b14adfa69c fix CVE-2024-50602
(cherry picked from commit d033ab7be9cb380f7eada98d47759bec203376b8)
2024-10-29 16:42:18 +08:00
openeuler-ci-bot
323f716435
!108 [sync] PR-104: fix CVE-2024-45491, CVE-2024-45492
From: @openeuler-sync-bot 
Reviewed-by: @dillon_chen 
Signed-off-by: @dillon_chen
2024-09-05 10:13:01 +00:00
Funda Wang
4722b2b42f fix CVE-2024-45491, CVE-2024-45492
(cherry picked from commit cc5691c3d0f87811f91dbbe60b11805273ca0229)
2024-09-05 17:53:13 +08:00
18 changed files with 2073 additions and 9 deletions

View File

@ -0,0 +1,202 @@
From cf6dc8e885feef5d5ce2225bd1d2c535162b7e39 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Sat, 10 Aug 2024 21:00:00 +0200
Subject: [PATCH] Introduce reenter flag
Co-authored-by: Jann Horn <jannh@google.com>
Add a new reenter flag. This flag acts like XML_SUSPENDED,
except that instead of returning out of the library, we
only return back to the main parse function, then re-enter
the processor function.
---
lib/xmlparse.c | 88 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 79 insertions(+), 9 deletions(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index e13b2bf..a94aa38 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -716,6 +716,7 @@ struct XML_ParserStruct {
ACCOUNTING m_accounting;
ENTITY_STATS m_entity_stats;
#endif
+ XML_Bool m_reenter;
};
#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
@@ -974,7 +975,28 @@ callProcessor(XML_Parser parser, const char *start, const char *end,
return XML_ERROR_NONE;
}
}
- const enum XML_Error ret = parser->m_processor(parser, start, end, endPtr);
+ // Run in a loop to eliminate dangerous recursion depths
+ enum XML_Error ret;
+ *endPtr = start;
+ while (1) {
+ // Use endPtr as the new start in each iteration, since it will
+ // be set to the next start point by m_processor.
+ ret = parser->m_processor(parser, *endPtr, end, endPtr);
+
+ // Make parsing status (and in particular XML_SUSPENDED) take
+ // precedence over re-enter flag when they disagree
+ if (parser->m_parsingStatus.parsing != XML_PARSING) {
+ parser->m_reenter = XML_FALSE;
+ }
+
+ if (! parser->m_reenter) {
+ break;
+ }
+
+ parser->m_reenter = XML_FALSE;
+ if (ret != XML_ERROR_NONE)
+ return ret;
+ }
if (ret == XML_ERROR_NONE) {
// if we consumed nothing, remember what we had on this parse attempt.
if (*endPtr == start) {
@@ -1196,6 +1218,8 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
parser->m_unknownEncodingData = NULL;
parser->m_parentParser = NULL;
parser->m_parsingStatus.parsing = XML_INITIALIZED;
+ // Reentry can only be triggered inside m_processor calls
+ parser->m_reenter = XML_FALSE;
#ifdef XML_DTD
parser->m_isParamEntity = XML_FALSE;
parser->m_useForeignDTD = XML_FALSE;
@@ -2203,6 +2227,11 @@ XML_GetBuffer(XML_Parser parser, int len) {
return parser->m_bufferEnd;
}
+static void
+triggerReenter(XML_Parser parser) {
+ parser->m_reenter = XML_TRUE;
+}
+
enum XML_Status XMLCALL
XML_StopParser(XML_Parser parser, XML_Bool resumable) {
if (parser == NULL)
@@ -2764,6 +2793,12 @@ externalEntityInitProcessor3(XML_Parser parser, const char *start,
return XML_ERROR_NONE;
case XML_FINISHED:
return XML_ERROR_ABORTED;
+ case XML_PARSING:
+ if (parser->m_reenter) {
+ *endPtr = next;
+ return XML_ERROR_NONE;
+ }
+ /* Fall through */
default:
start = next;
}
@@ -3063,7 +3098,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
}
if ((parser->m_tagLevel == 0)
&& (parser->m_parsingStatus.parsing != XML_FINISHED)) {
- if (parser->m_parsingStatus.parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_SUSPENDED
+ || (parser->m_parsingStatus.parsing == XML_PARSING
+ && parser->m_reenter))
parser->m_processor = epilogProcessor;
else
return epilogProcessor(parser, next, end, nextPtr);
@@ -3124,7 +3161,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
}
if ((parser->m_tagLevel == 0)
&& (parser->m_parsingStatus.parsing != XML_FINISHED)) {
- if (parser->m_parsingStatus.parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_SUSPENDED
+ || (parser->m_parsingStatus.parsing == XML_PARSING
+ && parser->m_reenter))
parser->m_processor = epilogProcessor;
else
return epilogProcessor(parser, next, end, nextPtr);
@@ -3264,6 +3303,12 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
return XML_ERROR_NONE;
case XML_FINISHED:
return XML_ERROR_ABORTED;
+ case XML_PARSING:
+ if (parser->m_reenter) {
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ }
+ /* Fall through */
default:;
}
}
@@ -4188,6 +4233,12 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
return XML_ERROR_NONE;
case XML_FINISHED:
return XML_ERROR_ABORTED;
+ case XML_PARSING:
+ if (parser->m_reenter) {
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ }
+ /* Fall through */
default:;
}
}
@@ -5722,6 +5773,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
return XML_ERROR_NONE;
case XML_FINISHED:
return XML_ERROR_ABORTED;
+ case XML_PARSING:
+ if (parser->m_reenter) {
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ }
+ /* Fall through */
default:
s = next;
tok = XmlPrologTok(enc, s, end, &next);
@@ -5796,6 +5853,12 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
return XML_ERROR_NONE;
case XML_FINISHED:
return XML_ERROR_ABORTED;
+ case XML_PARSING:
+ if (parser->m_reenter) {
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ }
+ /* Fall through */
default:;
}
}
@@ -5897,8 +5960,10 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
if (result != XML_ERROR_NONE)
return result;
-
- if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
+ if (textEnd != next
+ && (parser->m_parsingStatus.parsing == XML_SUSPENDED
+ || (parser->m_parsingStatus.parsing == XML_PARSING
+ && parser->m_reenter))) {
entity->processed = (int)(next - (const char *)entity->textPtr);
return result;
}
@@ -5912,11 +5977,16 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
openEntity->next = parser->m_freeInternalEntities;
parser->m_freeInternalEntities = openEntity;
- // If there are more open entities we want to stop right here and have the
- // upcoming call to XML_ResumeParser continue with entity content, or it would
- // be ignored altogether.
+ // If the state is XML_SUSPENDED and there are more open entities we want to
+ // stop right here and have the upcoming call to XML_ResumeParser continue
+ // with entity content, or it would be ignored altogether.
+ // If the state is XML_PARSING, m_reenter is set, and there are more open
+ // entities, we want to return and reenter to internalEntityProcessor to
+ // process the next entity in the list
if (parser->m_openInternalEntities != NULL
- && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
+ && (parser->m_parsingStatus.parsing == XML_SUSPENDED
+ || (parser->m_parsingStatus.parsing == XML_PARSING
+ && parser->m_reenter))) {
return XML_ERROR_NONE;
}
--
2.33.0

View File

@ -0,0 +1,31 @@
From 6edca2c37e280b3ce15e776ffabf70f11abf2966 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Thu, 12 Dec 2024 14:06:44 +0100
Subject: [PATCH 2/7] Switch allowClosingDoctype
This change of allowClosingDoctype has no effect and only serves as a
preparation for the upcoming changes.
Reference: https://github.com/libexpat/libexpat/pull/973/commits/6edca2c37e280b3ce15e776ffabf70f11abf2966
Conflict: adapt internalEntityProcessor
---
lib/xmlparse.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index 29843b0..10225e3 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -5944,7 +5944,7 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
int tok
= XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
- tok, next, &next, XML_FALSE, XML_TRUE,
+ tok, next, &next, XML_FALSE, XML_FALSE,
XML_ACCOUNT_ENTITY_EXPANSION);
} else
#endif /* XML_DTD */
--
2.33.0

View File

@ -0,0 +1,163 @@
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

View File

@ -0,0 +1,89 @@
From 74308916d90218707bd7e8f61fbf52032e0e633d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Wed, 25 Sep 2024 09:34:48 +0200
Subject: [PATCH 4/7] Add next pointer to appendAttributeValue
This commits extends appendAttributeValue by introducing a new parameter
that will be set to the next token to process.
Having such a parameter allows us to reenter the function after an exit
and continue from the last token pointed by the pointer.
Reference: https://github.com/libexpat/libexpat/pull/973/commits/74308916d90218707bd7e8f61fbf52032e0e633d
Conflict: adapt appendAttributeValue
---
lib/xmlparse.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index cc5a609..781fc71 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -486,10 +486,10 @@ static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *,
XML_Bool isCdata, const char *,
const char *, STRING_POOL *,
enum XML_Account account);
-static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
- XML_Bool isCdata, const char *,
- const char *, STRING_POOL *,
- enum XML_Account account);
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+ const char *ptr, const char *end, STRING_POOL *pool,
+ enum XML_Account account, const char **nextPtr);
static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end);
static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
@@ -5994,8 +5994,8 @@ static enum XML_Error
storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
const char *ptr, const char *end, STRING_POOL *pool,
enum XML_Account account) {
- enum XML_Error result
- = appendAttributeValue(parser, enc, isCdata, ptr, end, pool, account);
+ enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, end,
+ pool, account, NULL);
if (result)
return result;
if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
@@ -6008,7 +6008,7 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
static enum XML_Error
appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
const char *ptr, const char *end, STRING_POOL *pool,
- enum XML_Account account) {
+ enum XML_Account account, const char **nextPtr) {
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
#ifndef XML_DTD
UNUSED_P(account);
@@ -6026,6 +6026,9 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
#endif
switch (tok) {
case XML_TOK_NONE:
+ if (nextPtr) {
+ *nextPtr = next;
+ }
return XML_ERROR_NONE;
case XML_TOK_INVALID:
if (enc == parser->m_encoding)
@@ -6174,7 +6177,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
result = appendAttributeValue(parser, parser->m_internalEncoding,
isCdata, (const char *)entity->textPtr,
(const char *)textEnd, pool,
- XML_ACCOUNT_ENTITY_EXPANSION);
+ XML_ACCOUNT_ENTITY_EXPANSION, NULL);
#if defined(XML_DTD) || XML_GE == 1
entityTrackingOnClose(parser, entity, __LINE__);
#endif
@@ -6201,6 +6204,9 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
/* LCOV_EXCL_STOP */
}
ptr = next;
+ if (nextPtr) {
+ *nextPtr = next;
+ }
}
/* not reached */
}
--
2.33.0

View File

@ -0,0 +1,247 @@
From da10ca23282cf336553307dcc47dafb5b7378ad0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Tue, 27 Aug 2024 17:14:50 +0200
Subject: [PATCH 5/7] Break cyclic appendAttributeValue recursion
During processing attributes with entity references,
appendAttributeValue can reach high recursion depths that can lead to
a crash.
This commit switches the processing to an iterative approach similar to
the fix for internal entity processing. A new m_openAttributeEntities
list is introduced to keep track of entity references that need
processing. When a new entity reference is detected, instead of calling
appendAttributeValue recursively, the entity will be added to open
entities list and the execution will return to storeAttributeValue,
where newly added entity will be handled. After the entity processing
is done, appendAttributeValue will be called by using the next token.
Reference: https://github.com/libexpat/libexpat/pull/973/commits/da10ca23282cf336553307dcc47dafb5b7378ad0
Conflict: adapt appendAttributeValue
---
lib/xmlparse.c | 145 +++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 127 insertions(+), 18 deletions(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index 781fc71..c86da91 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -457,6 +457,8 @@ static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
enum XML_Account account);
static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
XML_Bool betweenDecl);
+static enum XML_Error processAttributeEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl);
static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc, const char *start,
const char *end, const char **endPtr,
@@ -665,6 +667,8 @@ struct XML_ParserStruct {
const char *m_positionPtr;
OPEN_INTERNAL_ENTITY *m_openInternalEntities;
OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
+ OPEN_INTERNAL_ENTITY *m_openAttributeEntities;
+ OPEN_INTERNAL_ENTITY *m_freeAttributeEntities;
XML_Bool m_defaultExpandInternalEntities;
int m_tagLevel;
ENTITY *m_declEntity;
@@ -1103,6 +1107,7 @@ parserCreate(const XML_Char *encodingName,
parser->m_freeBindingList = NULL;
parser->m_freeTagList = NULL;
parser->m_freeInternalEntities = NULL;
+ parser->m_freeAttributeEntities = NULL;
parser->m_groupSize = 0;
parser->m_groupConnector = NULL;
@@ -1204,6 +1209,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
parser->m_eventEndPtr = NULL;
parser->m_positionPtr = NULL;
parser->m_openInternalEntities = NULL;
+ parser->m_openAttributeEntities = NULL;
parser->m_defaultExpandInternalEntities = XML_TRUE;
parser->m_tagLevel = 0;
parser->m_tagStack = NULL;
@@ -1275,6 +1281,15 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
openEntity->next = parser->m_freeInternalEntities;
parser->m_freeInternalEntities = openEntity;
}
+ /* move m_openAttributeEntities to m_freeAttributeEntities (i.e. same task but
+ * for attributes) */
+ openEntityList = parser->m_openAttributeEntities;
+ while (openEntityList) {
+ OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
+ openEntityList = openEntity->next;
+ openEntity->next = parser->m_freeAttributeEntities;
+ parser->m_freeAttributeEntities = openEntity;
+ }
moveToFreeBindingList(parser, parser->m_inheritedBindings);
FREE(parser, parser->m_unknownEncodingMem);
if (parser->m_unknownEncodingRelease)
@@ -1531,7 +1546,20 @@ XML_ParserFree(XML_Parser parser) {
entityList = entityList->next;
FREE(parser, openEntity);
}
-
+ /* free m_openAttributeEntities and m_freeAttributeEntities */
+ entityList = parser->m_openAttributeEntities;
+ for (;;) {
+ OPEN_INTERNAL_ENTITY *openEntity;
+ if (entityList == NULL) {
+ if (parser->m_freeAttributeEntities == NULL)
+ break;
+ entityList = parser->m_freeAttributeEntities;
+ parser->m_freeAttributeEntities = NULL;
+ }
+ openEntity = entityList;
+ entityList = entityList->next;
+ FREE(parser, openEntity);
+ }
destroyBindings(parser->m_freeBindingList, parser);
destroyBindings(parser->m_inheritedBindings, parser);
poolDestroy(&parser->m_tempPool);
@@ -5859,6 +5887,7 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
}
}
+/* KEEP IN SYNC with processAttributeEntity */
static enum XML_Error
processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
OPEN_INTERNAL_ENTITY *openEntity;
@@ -5890,6 +5919,37 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
return XML_ERROR_NONE;
}
+/* KEEP IN SYNC with processInternalEntity */
+static enum XML_Error
+processAttributeEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl) {
+ OPEN_INTERNAL_ENTITY *openEntity;
+
+ if (parser->m_freeAttributeEntities) {
+ openEntity = parser->m_freeAttributeEntities;
+ parser->m_freeAttributeEntities = openEntity->next;
+ } else {
+ openEntity
+ = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
+ if (! openEntity)
+ return XML_ERROR_NO_MEMORY;
+ }
+ entity->open = XML_TRUE;
+#if XML_GE == 1
+ entityTrackingOnOpen(parser, entity, __LINE__);
+#endif
+ entity->processed = 0;
+ openEntity->next = parser->m_openAttributeEntities;
+ parser->m_openAttributeEntities = openEntity;
+ openEntity->entity = entity;
+ openEntity->startTagLevel = parser->m_tagLevel;
+ openEntity->betweenDecl = betweenDecl;
+ openEntity->internalEventPtr = NULL;
+ openEntity->internalEventEndPtr = NULL;
+
+ return XML_ERROR_NONE;
+}
+
static enum XML_Error PTRCALL
internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
@@ -5994,8 +6054,67 @@ static enum XML_Error
storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
const char *ptr, const char *end, STRING_POOL *pool,
enum XML_Account account) {
- enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, end,
- pool, account, NULL);
+ const char *next = ptr;
+ enum XML_Error result = XML_ERROR_NONE;
+
+ while (1) {
+ if (! parser->m_openAttributeEntities) {
+ result = appendAttributeValue(parser, enc, isCdata, next, end, pool,
+ account, &next);
+ } else {
+ OPEN_INTERNAL_ENTITY *const openEntity = parser->m_openAttributeEntities;
+ if (! openEntity)
+ return XML_ERROR_UNEXPECTED_STATE;
+
+ ENTITY *const entity = openEntity->entity;
+ const char *const textStart
+ = ((const char *)entity->textPtr) + entity->processed;
+ const char *const textEnd
+ = (const char *)(entity->textPtr + entity->textLen);
+ /* Set a safe default value in case 'next' does not get set */
+ const char *nextInEntity = textStart;
+ result = appendAttributeValue(
+ parser, parser->m_internalEncoding, isCdata, textStart, textEnd, pool,
+ XML_ACCOUNT_ENTITY_EXPANSION, &nextInEntity);
+ if (result != XML_ERROR_NONE)
+ break;
+ // Check if entity is complete, if not, mark down how much of it is
+ // processed. A XML_SUSPENDED check here is not required as
+ // appendAttributeValue will never suspend the parser.
+ if (textEnd != nextInEntity) {
+ entity->processed = (int)(nextInEntity - (const char *)entity->textPtr);
+ continue;
+ }
+
+#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
+ // will set the 'reenter' flag and return. Therefore openEntity is either
+ // the head or next to the new head.
+ if (parser->m_openAttributeEntities == openEntity) {
+ // No new entity detected during entity processing,
+ // openEntity is still the head.
+ parser->m_openAttributeEntities = parser->m_openAttributeEntities->next;
+ } else {
+ // New entity detected since list has a new head. openEntity is the
+ // second element.
+ parser->m_openAttributeEntities->next = openEntity->next;
+ }
+ /* put openEntity back in list of free instances */
+ openEntity->next = parser->m_freeAttributeEntities;
+ parser->m_freeAttributeEntities = openEntity;
+ }
+
+ // Break if an error occurred or there is nothing left to process
+ if (result || (parser->m_openAttributeEntities == NULL && end == next)) {
+ break;
+ }
+ }
+
if (result)
return result;
if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
@@ -6169,21 +6288,11 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
} else {
enum XML_Error result;
- const XML_Char *textEnd = entity->textPtr + entity->textLen;
- entity->open = XML_TRUE;
-#if defined(XML_DTD) || XML_GE == 1
- entityTrackingOnOpen(parser, entity, __LINE__);
-#endif
- result = appendAttributeValue(parser, parser->m_internalEncoding,
- isCdata, (const char *)entity->textPtr,
- (const char *)textEnd, pool,
- XML_ACCOUNT_ENTITY_EXPANSION, NULL);
-#if defined(XML_DTD) || XML_GE == 1
- entityTrackingOnClose(parser, entity, __LINE__);
-#endif
- entity->open = XML_FALSE;
- if (result)
- return result;
+ result = processAttributeEntity(parser, entity, XML_FALSE);
+ if (nextPtr) {
+ *nextPtr = next;
+ }
+ return result;
}
} break;
default:
--
2.33.0

View File

@ -0,0 +1,105 @@
From bf97ac508110dc390bd5471ed4904d5a4044332b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Mon, 7 Oct 2024 15:38:53 +0200
Subject: [PATCH 6/7] Add next pointer to storeEntityValue
This commit introduces a new nextPtr parameter to storeEntityValue.
After finishing its execution, storeEntityValue function sets this
parameter in way that it points to the next token to process.
This is useful when we want to leave and reenter storeEntityValue during
its execution since nextPtr will point where we left.
This commit is base to the following commit.
Reference: https://github.com/libexpat/libexpat/pull/973/commits/bf97ac508110dc390bd5471ed4904d5a4044332b
Conflict: NA
---
lib/xmlparse.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index c86da91..8f556d9 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -498,7 +498,8 @@ static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
#if XML_GE == 1
static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end,
- enum XML_Account account);
+ enum XML_Account account,
+ const char **nextPtr);
#else
static enum XML_Error storeSelfEntityValue(XML_Parser parser, ENTITY *entity);
#endif
@@ -4594,7 +4595,7 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
}
/* found end of entity value - can store it now */
return storeEntityValue(parser, parser->m_encoding, s, end,
- XML_ACCOUNT_DIRECT);
+ XML_ACCOUNT_DIRECT, NULL);
} else if (tok == XML_TOK_XML_DECL) {
enum XML_Error result;
result = processXmlDecl(parser, 0, start, next);
@@ -4721,7 +4722,7 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
break;
}
/* found end of entity value - can store it now */
- return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT);
+ return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT, NULL);
}
start = next;
}
@@ -5166,7 +5167,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
// parser->m_declEntity->textPtr.
enum XML_Error result
= storeEntityValue(parser, enc, s + enc->minBytesPerChar,
- next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
+ next - enc->minBytesPerChar, XML_ACCOUNT_NONE, NULL);
if (parser->m_declEntity) {
parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
parser->m_declEntity->textLen
@@ -6324,7 +6325,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
static enum XML_Error
storeEntityValue(XML_Parser parser, const ENCODING *enc,
const char *entityTextPtr, const char *entityTextEnd,
- enum XML_Account account) {
+ enum XML_Account account, const char **nextPtr) {
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
STRING_POOL *pool = &(dtd->entityValuePool);
enum XML_Error result = XML_ERROR_NONE;
@@ -6342,8 +6343,9 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
return XML_ERROR_NO_MEMORY;
}
+ const char *next;
for (;;) {
- const char *next
+ next
= entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
@@ -6412,7 +6414,7 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
result = storeEntityValue(
parser, parser->m_internalEncoding, (const char *)entity->textPtr,
(const char *)(entity->textPtr + entity->textLen),
- XML_ACCOUNT_ENTITY_EXPANSION);
+ XML_ACCOUNT_ENTITY_EXPANSION, NULL);
entityTrackingOnClose(parser, entity, __LINE__);
entity->open = XML_FALSE;
if (result)
@@ -6504,6 +6506,10 @@ endEntityValue:
# ifdef XML_DTD
parser->m_prologState.inEntityValue = oldInEntityValue;
# endif /* XML_DTD */
+ // If 'nextPtr' is given, it should be updated during the processing
+ if (nextPtr != NULL) {
+ *nextPtr = next;
+ }
return result;
}
--
2.33.0

View File

@ -0,0 +1,249 @@
From fabae41d28399e1d1623bde9ebd300c962e62ebe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Wed, 18 Sep 2024 13:52:06 +0200
Subject: [PATCH 7/7] Fix storeEntityValue recursion
Reference: https://github.com/libexpat/libexpat/pull/973/commits/fabae41d28399e1d1623bde9ebd300c962e62ebe
Conflict: adapt doProlog
---
lib/xmlparse.c | 153 ++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 140 insertions(+), 13 deletions(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index 8f556d9..6c81713 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -459,6 +459,10 @@ static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
XML_Bool betweenDecl);
static enum XML_Error processAttributeEntity(XML_Parser parser, ENTITY *entity,
XML_Bool betweenDecl);
+#ifdef XML_DTD
+static enum XML_Error processValueEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl);
+#endif /* XML_DTD */
static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc, const char *start,
const char *end, const char **endPtr,
@@ -500,6 +504,10 @@ static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end,
enum XML_Account account,
const char **nextPtr);
+static enum XML_Error callStoreEntityValue(XML_Parser parser,
+ const ENCODING *enc,
+ const char *start, const char *end,
+ enum XML_Account account);
#else
static enum XML_Error storeSelfEntityValue(XML_Parser parser, ENTITY *entity);
#endif
@@ -670,6 +678,8 @@ struct XML_ParserStruct {
OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
OPEN_INTERNAL_ENTITY *m_openAttributeEntities;
OPEN_INTERNAL_ENTITY *m_freeAttributeEntities;
+ OPEN_INTERNAL_ENTITY *m_openValueEntities;
+ OPEN_INTERNAL_ENTITY *m_freeValueEntities;
XML_Bool m_defaultExpandInternalEntities;
int m_tagLevel;
ENTITY *m_declEntity;
@@ -1109,6 +1119,7 @@ parserCreate(const XML_Char *encodingName,
parser->m_freeTagList = NULL;
parser->m_freeInternalEntities = NULL;
parser->m_freeAttributeEntities = NULL;
+ parser->m_freeValueEntities = NULL;
parser->m_groupSize = 0;
parser->m_groupConnector = NULL;
@@ -1211,6 +1222,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
parser->m_positionPtr = NULL;
parser->m_openInternalEntities = NULL;
parser->m_openAttributeEntities = NULL;
+ parser->m_openValueEntities = NULL;
parser->m_defaultExpandInternalEntities = XML_TRUE;
parser->m_tagLevel = 0;
parser->m_tagStack = NULL;
@@ -1291,6 +1303,15 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
openEntity->next = parser->m_freeAttributeEntities;
parser->m_freeAttributeEntities = openEntity;
}
+ /* move m_openValueEntities to m_freeValueEntities (i.e. same task but
+ * for value entities) */
+ openEntityList = parser->m_openValueEntities;
+ while (openEntityList) {
+ OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
+ openEntityList = openEntity->next;
+ openEntity->next = parser->m_freeValueEntities;
+ parser->m_freeValueEntities = openEntity;
+ }
moveToFreeBindingList(parser, parser->m_inheritedBindings);
FREE(parser, parser->m_unknownEncodingMem);
if (parser->m_unknownEncodingRelease)
@@ -1561,6 +1582,20 @@ XML_ParserFree(XML_Parser parser) {
entityList = entityList->next;
FREE(parser, openEntity);
}
+ /* free m_openValueEntities and m_freeValueEntities */
+ entityList = parser->m_openValueEntities;
+ for (;;) {
+ OPEN_INTERNAL_ENTITY *openEntity;
+ if (entityList == NULL) {
+ if (parser->m_freeValueEntities == NULL)
+ break;
+ entityList = parser->m_freeValueEntities;
+ parser->m_freeValueEntities = NULL;
+ }
+ openEntity = entityList;
+ entityList = entityList->next;
+ FREE(parser, openEntity);
+ }
destroyBindings(parser->m_freeBindingList, parser);
destroyBindings(parser->m_inheritedBindings, parser);
poolDestroy(&parser->m_tempPool);
@@ -5165,9 +5200,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
#if defined(XML_DTD) || XML_GE == 1
// This will store the given replacement text in
// parser->m_declEntity->textPtr.
- enum XML_Error result
- = storeEntityValue(parser, enc, s + enc->minBytesPerChar,
- next - enc->minBytesPerChar, XML_ACCOUNT_NONE, NULL);
+ enum XML_Error result = callStoreEntityValue(
+ parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar,
+ XML_ACCOUNT_NONE);
if (parser->m_declEntity) {
parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
parser->m_declEntity->textLen
@@ -5951,6 +5986,38 @@ processAttributeEntity(XML_Parser parser, ENTITY *entity,
return XML_ERROR_NONE;
}
+/* KEEP IN SYNC with processInternalEntity */
+#ifdef XML_DTD
+static enum XML_Error
+processValueEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
+ OPEN_INTERNAL_ENTITY *openEntity;
+
+ if (parser->m_freeValueEntities) {
+ openEntity = parser->m_freeValueEntities;
+ parser->m_freeValueEntities = openEntity->next;
+ } else {
+ openEntity
+ = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
+ if (! openEntity)
+ return XML_ERROR_NO_MEMORY;
+ }
+ entity->open = XML_TRUE;
+# if XML_GE == 1
+ entityTrackingOnOpen(parser, entity, __LINE__);
+# endif
+ entity->processed = 0;
+ openEntity->next = parser->m_openValueEntities;
+ parser->m_openValueEntities = openEntity;
+ openEntity->entity = entity;
+ openEntity->startTagLevel = parser->m_tagLevel;
+ openEntity->betweenDecl = betweenDecl;
+ openEntity->internalEventPtr = NULL;
+ openEntity->internalEventEndPtr = NULL;
+
+ return XML_ERROR_NONE;
+}
+#endif /* XML_DTD */
+
static enum XML_Error PTRCALL
internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
@@ -6409,16 +6476,8 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
} else
dtd->keepProcessing = dtd->standalone;
} else {
- entity->open = XML_TRUE;
- entityTrackingOnOpen(parser, entity, __LINE__);
- result = storeEntityValue(
- parser, parser->m_internalEncoding, (const char *)entity->textPtr,
- (const char *)(entity->textPtr + entity->textLen),
- XML_ACCOUNT_ENTITY_EXPANSION, NULL);
- entityTrackingOnClose(parser, entity, __LINE__);
- entity->open = XML_FALSE;
- if (result)
- goto endEntityValue;
+ result = processValueEntity(parser, entity, XML_FALSE);
+ goto endEntityValue;
}
break;
}
@@ -6513,6 +6572,74 @@ endEntityValue:
return result;
}
+static enum XML_Error
+callStoreEntityValue(XML_Parser parser, const ENCODING *enc,
+ const char *entityTextPtr, const char *entityTextEnd,
+ enum XML_Account account) {
+ const char *next = entityTextPtr;
+ enum XML_Error result = XML_ERROR_NONE;
+ while (1) {
+ if (! parser->m_openValueEntities) {
+ result
+ = storeEntityValue(parser, enc, next, entityTextEnd, account, &next);
+ } else {
+ OPEN_INTERNAL_ENTITY *const openEntity = parser->m_openValueEntities;
+ if (! openEntity)
+ return XML_ERROR_UNEXPECTED_STATE;
+
+ ENTITY *const entity = openEntity->entity;
+ const char *const textStart
+ = ((const char *)entity->textPtr) + entity->processed;
+ const char *const textEnd
+ = (const char *)(entity->textPtr + entity->textLen);
+ /* Set a safe default value in case 'next' does not get set */
+ const char *nextInEntity = textStart;
+ result = storeEntityValue(parser, parser->m_internalEncoding, textStart,
+ textEnd, XML_ACCOUNT_ENTITY_EXPANSION,
+ &nextInEntity);
+ if (result != XML_ERROR_NONE)
+ break;
+ // Check if entity is complete, if not, mark down how much of it is
+ // processed. A XML_SUSPENDED check here is not required as
+ // appendAttributeValue will never suspend the parser.
+ if (textEnd != nextInEntity) {
+ entity->processed = (int)(nextInEntity - (const char *)entity->textPtr);
+ continue;
+ }
+
+# 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
+ // will set the 'reenter' flag and return. Therefore openEntity is either
+ // the head or next to the new head.
+ if (parser->m_openValueEntities == openEntity) {
+ // No new entity detected during entity processing,
+ // openEntity is still the head.
+ parser->m_openValueEntities = parser->m_openValueEntities->next;
+ } else {
+ // New entity detected since list has a new head. openEntity is the
+ // second element.
+ parser->m_openValueEntities->next = openEntity->next;
+ }
+ /* put openEntity back in list of free instances */
+ openEntity->next = parser->m_freeValueEntities;
+ parser->m_freeValueEntities = openEntity;
+ }
+
+ // Break if an error occurred or there is nothing left to process
+ if (result
+ || (parser->m_openValueEntities == NULL && entityTextEnd == next)) {
+ break;
+ }
+ }
+
+ return result;
+}
+
#else /* XML_GE == 0 */
static enum XML_Error
--
2.33.0

View File

@ -0,0 +1,229 @@
From 16a3b9d3566a95c4e502bfd008d05a0d015013ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Wed, 9 Oct 2024 15:51:05 +0200
Subject: [PATCH 1/3] Merge entity processors
Reference: https://github.com/libexpat/libexpat/pull/973/commits/16a3b9d3566a95c4e502bfd008d05a0d015013ac
Conflict: adapt epilogProcessor
---
lib/xmlparse.c | 135 +++++++++++++++++++------------------------------
1 file changed, 51 insertions(+), 84 deletions(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index 6c81713..9d8099e 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -389,6 +389,12 @@ typedef struct {
int *scaffIndex;
} DTD;
+enum EntityType {
+ ENTITY_INTERNAL,
+ ENTITY_ATTRIBUTE,
+ ENTITY_VALUE,
+};
+
typedef struct open_internal_entity {
const char *internalEventPtr;
const char *internalEventEndPtr;
@@ -396,6 +402,7 @@ typedef struct open_internal_entity {
ENTITY *entity;
int startTagLevel;
XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+ enum EntityType type;
} OPEN_INTERNAL_ENTITY;
enum XML_Account {
@@ -455,14 +462,8 @@ static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
const char *next, const char **nextPtr,
XML_Bool haveMore, XML_Bool allowClosingDoctype,
enum XML_Account account);
-static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
- XML_Bool betweenDecl);
-static enum XML_Error processAttributeEntity(XML_Parser parser, ENTITY *entity,
- XML_Bool betweenDecl);
-#ifdef XML_DTD
-static enum XML_Error processValueEntity(XML_Parser parser, ENTITY *entity,
- XML_Bool betweenDecl);
-#endif /* XML_DTD */
+static enum XML_Error processEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl, enum EntityType type);
static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc, const char *start,
const char *end, const char **endPtr,
@@ -3033,7 +3034,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
reportDefault(parser, enc, s, next);
break;
}
- result = processInternalEntity(parser, entity, XML_FALSE);
+ result = processEntity(parser, entity, XML_FALSE, ENTITY_INTERNAL);
if (result != XML_ERROR_NONE)
return result;
} else if (parser->m_externalEntityRefHandler) {
@@ -5627,7 +5628,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
enum XML_Error result;
XML_Bool betweenDecl
= (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
- result = processInternalEntity(parser, entity, betweenDecl);
+ result = processEntity(parser, entity, betweenDecl, ENTITY_INTERNAL);
if (result != XML_ERROR_NONE)
return result;
handleDefault = XML_FALSE;
@@ -5923,48 +5924,40 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
}
}
-/* KEEP IN SYNC with processAttributeEntity */
static enum XML_Error
-processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
- OPEN_INTERNAL_ENTITY *openEntity;
-
- if (parser->m_freeInternalEntities) {
- openEntity = parser->m_freeInternalEntities;
- parser->m_freeInternalEntities = openEntity->next;
- } else {
- openEntity
- = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
- if (! openEntity)
- return XML_ERROR_NO_MEMORY;
+processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl,
+ enum EntityType type) {
+ OPEN_INTERNAL_ENTITY *openEntity, **openEntityList, **freeEntityList;
+ switch (type) {
+ case ENTITY_INTERNAL:
+ parser->m_processor = internalEntityProcessor;
+ openEntityList = &parser->m_openInternalEntities;
+ freeEntityList = &parser->m_freeInternalEntities;
+ break;
+ case ENTITY_ATTRIBUTE:
+ openEntityList = &parser->m_openAttributeEntities;
+ freeEntityList = &parser->m_freeAttributeEntities;
+ break;
+ case ENTITY_VALUE:
+ openEntityList = &parser->m_openValueEntities;
+ freeEntityList = &parser->m_freeValueEntities;
+ break;
+ /* default case serves merely as a safety net in case of a
+ * wrong entityType. Therefore we exclude the following lines
+ * from the test coverage.
+ *
+ * LCOV_EXCL_START
+ */
+ default:
+ // Should not reach here
+ assert(0);
+ /* LCOV_EXCL_STOP */
}
- entity->open = XML_TRUE;
-#if defined(XML_DTD) || XML_GE == 1
- entityTrackingOnOpen(parser, entity, __LINE__);
-#endif
- entity->processed = 0;
- parser->m_processor = internalEntityProcessor;
- openEntity->next = parser->m_openInternalEntities;
- parser->m_openInternalEntities = openEntity;
- openEntity->entity = entity;
- openEntity->startTagLevel = parser->m_tagLevel;
- openEntity->betweenDecl = betweenDecl;
- openEntity->internalEventPtr = NULL;
- openEntity->internalEventEndPtr = NULL;
-
- triggerReenter(parser);
- return XML_ERROR_NONE;
-}
-
-/* KEEP IN SYNC with processInternalEntity */
-static enum XML_Error
-processAttributeEntity(XML_Parser parser, ENTITY *entity,
- XML_Bool betweenDecl) {
- OPEN_INTERNAL_ENTITY *openEntity;
- if (parser->m_freeAttributeEntities) {
- openEntity = parser->m_freeAttributeEntities;
- parser->m_freeAttributeEntities = openEntity->next;
- } else {
+ if (*freeEntityList) {
+ openEntity = *freeEntityList;
+ *freeEntityList = openEntity->next;
+ } else {
openEntity
= (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
if (! openEntity)
@@ -5975,48 +5968,22 @@ processAttributeEntity(XML_Parser parser, ENTITY *entity,
entityTrackingOnOpen(parser, entity, __LINE__);
#endif
entity->processed = 0;
- openEntity->next = parser->m_openAttributeEntities;
- parser->m_openAttributeEntities = openEntity;
+ openEntity->next = *openEntityList;
+ *openEntityList = openEntity;
openEntity->entity = entity;
+ openEntity->type = type;
openEntity->startTagLevel = parser->m_tagLevel;
openEntity->betweenDecl = betweenDecl;
openEntity->internalEventPtr = NULL;
openEntity->internalEventEndPtr = NULL;
- return XML_ERROR_NONE;
-}
-
-/* KEEP IN SYNC with processInternalEntity */
-#ifdef XML_DTD
-static enum XML_Error
-processValueEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
- OPEN_INTERNAL_ENTITY *openEntity;
-
- if (parser->m_freeValueEntities) {
- openEntity = parser->m_freeValueEntities;
- parser->m_freeValueEntities = openEntity->next;
- } else {
- openEntity
- = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
- if (! openEntity)
- return XML_ERROR_NO_MEMORY;
+ // Only internal entities make use of the reenter flag
+ // therefore no need to set it for other entity types
+ if (type == ENTITY_INTERNAL) {
+ triggerReenter(parser);
}
- entity->open = XML_TRUE;
-# if XML_GE == 1
- entityTrackingOnOpen(parser, entity, __LINE__);
-# endif
- entity->processed = 0;
- openEntity->next = parser->m_openValueEntities;
- parser->m_openValueEntities = openEntity;
- openEntity->entity = entity;
- openEntity->startTagLevel = parser->m_tagLevel;
- openEntity->betweenDecl = betweenDecl;
- openEntity->internalEventPtr = NULL;
- openEntity->internalEventEndPtr = NULL;
-
return XML_ERROR_NONE;
}
-#endif /* XML_DTD */
static enum XML_Error PTRCALL
internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
@@ -6356,7 +6323,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
} else {
enum XML_Error result;
- result = processAttributeEntity(parser, entity, XML_FALSE);
+ result = processEntity(parser, entity, XML_FALSE, ENTITY_ATTRIBUTE);
if (nextPtr) {
*nextPtr = next;
}
@@ -6476,7 +6443,7 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
} else
dtd->keepProcessing = dtd->standalone;
} else {
- result = processValueEntity(parser, entity, XML_FALSE);
+ result = processEntity(parser, entity, XML_FALSE, ENTITY_VALUE);
goto endEntityValue;
}
break;
--
2.33.0

View File

@ -0,0 +1,199 @@
From 08ff7591ffe9519f627e246f841427c6f10edc2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Tue, 15 Oct 2024 11:37:09 +0200
Subject: [PATCH] Fix entity debug order
The fix for entity processing changes the order of opening and closing
of entities. The reason is the new iterative approach that closes
and removes entities as soon as they are fully processed, unlike
the recursive approach that, as a side effect of the recursion, waits
the inner entities before closing and removal.
This commit delays the removal and the call to entityTrackingOnClose
until the current entities inner entities are processed, which in turn
allows us to have the correct debug order again.
Reference: https://github.com/libexpat/libexpat/pull/973/commits/c20ce3aaa3a114e7d671d11625a63d75de904e31
Conflict: adapt internalEntityProcessor
---
lib/xmlparse.c | 121 ++++++++++++++++++++++++++-----------------------
1 file changed, 64 insertions(+), 57 deletions(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index 9dda309..325d5e7 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -6004,38 +6004,46 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
return XML_ERROR_UNEXPECTED_STATE;
entity = openEntity->entity;
- 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 */
- next = textStart;
+ if (entity->open) {
+ 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 */
+ 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
+ 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, openEntity->startTagLevel,
- parser->m_internalEncoding, textStart, textEnd, &next,
- XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
+ result = doContent(parser, openEntity->startTagLevel,
+ parser->m_internalEncoding, textStart, textEnd, &next,
+ XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
+ }
- if (result != XML_ERROR_NONE)
- return result;
- if (textEnd != next
- && (parser->m_parsingStatus.parsing == XML_SUSPENDED
- || (parser->m_parsingStatus.parsing == XML_PARSING
- && parser->m_reenter))) {
- entity->processed = (int)(next - (const char *)entity->textPtr);
+ if (result != XML_ERROR_NONE)
+ return result;
+ // Check if entity is complete, if not, mark down how much of it is
+ // processed
+ if (textEnd != next
+ && (parser->m_parsingStatus.parsing == XML_SUSPENDED
+ || (parser->m_parsingStatus.parsing == XML_PARSING
+ && parser->m_reenter))) {
+ entity->processed = (int)(next - (const char *)entity->textPtr);
+ return result;
+ }
+
+ entity->open = XML_FALSE;
+ triggerReenter(parser);
return result;
}
#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
@@ -6053,19 +6061,6 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
openEntity->next = parser->m_freeInternalEntities;
parser->m_freeInternalEntities = openEntity;
- // If the state is XML_SUSPENDED and there are more open entities we want to
- // stop right here and have the upcoming call to XML_ResumeParser continue
- // with entity content, or it would be ignored altogether.
- // If the state is XML_PARSING, m_reenter is set, and there are more open
- // entities, we want to return and reenter to internalEntityProcessor to
- // process the next entity in the list
- if (parser->m_openInternalEntities != NULL
- && (parser->m_parsingStatus.parsing == XML_SUSPENDED
- || (parser->m_parsingStatus.parsing == XML_PARSING
- && parser->m_reenter))) {
- return XML_ERROR_NONE;
- }
-
if (parser->m_openInternalEntities == NULL) {
parser->m_processor = entity->is_param ? prologProcessor : contentProcessor;
// internalEntityProcessor is called from callProcessor's while(1) loop,
@@ -6113,23 +6108,29 @@ 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;
- result = appendAttributeValue(
- parser, parser->m_internalEncoding, isCdata, textStart, textEnd, pool,
- XML_ACCOUNT_ENTITY_EXPANSION, &nextInEntity);
- if (result != XML_ERROR_NONE)
- break;
- // Check if entity is complete, if not, mark down how much of it is
- // processed. A XML_SUSPENDED check here is not required as
- // appendAttributeValue will never suspend the parser.
- if (textEnd != nextInEntity) {
- entity->processed = (int)(nextInEntity - (const char *)entity->textPtr);
+ if (entity->open) {
+ result = appendAttributeValue(
+ parser, parser->m_internalEncoding, isCdata, textStart, textEnd,
+ pool, XML_ACCOUNT_ENTITY_EXPANSION, &nextInEntity);
+ if (result != XML_ERROR_NONE)
+ break;
+ // Check if entity is complete, if not, mark down how much of it is
+ // processed. A XML_SUSPENDED check here is not required as
+ // appendAttributeValue will never suspend the parser.
+ if (textEnd != nextInEntity) {
+ entity->processed
+ = (int)(nextInEntity - (const char *)entity->textPtr);
+ continue;
+ }
+
+ entity->open = XML_FALSE;
+ triggerReenter(parser);
continue;
}
#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
@@ -6566,23 +6567,29 @@ 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;
- result = storeEntityValue(parser, parser->m_internalEncoding, textStart,
- textEnd, XML_ACCOUNT_ENTITY_EXPANSION,
- &nextInEntity);
- if (result != XML_ERROR_NONE)
- break;
- // Check if entity is complete, if not, mark down how much of it is
- // processed. A XML_SUSPENDED check here is not required as
- // appendAttributeValue will never suspend the parser.
- if (textEnd != nextInEntity) {
- entity->processed = (int)(nextInEntity - (const char *)entity->textPtr);
+ if (entity->open) {
+ result = storeEntityValue(parser, parser->m_internalEncoding, textStart,
+ textEnd, XML_ACCOUNT_ENTITY_EXPANSION,
+ &nextInEntity);
+ if (result != XML_ERROR_NONE)
+ break;
+ // Check if entity is complete, if not, mark down how much of it is
+ // processed. A XML_SUSPENDED check here is not required as
+ // appendAttributeValue will never suspend the parser.
+ if (textEnd != nextInEntity) {
+ entity->processed
+ = (int)(nextInEntity - (const char *)entity->textPtr);
+ continue;
+ }
+
+ entity->open = XML_FALSE;
+ triggerReenter(parser);
continue;
}
# 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

View File

@ -0,0 +1,133 @@
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

View File

@ -0,0 +1,53 @@
From f2edeaaecebfad1edef3e6504ffb772e5e4dd089 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Wed, 5 Mar 2025 12:33:47 +0100
Subject: [PATCH] Delete the check that prevents reentry
The early return in case of zero open internal entities and matching
end/nextPtr pointers cause the parser to miss XML_ERROR_NO_ELEMENTS
error.
The reason is that the internalEntityProcessor does not set the
m_reenter flag in such a case, which results in skipping the
prologProcessor or contentProcessor depending on wheter is_param is set
or not. However, this last skipped call to mentioned processors can
detect the non-existence of elements when some are expected.
Reference: https://github.com/libexpat/libexpat/pull/973/commits/f2edeaaecebfad1edef3e6504ffb772e5e4dd089
Conflict: NA
---
lib/xmlparse.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index d5161e93..de459192 100644
--- a/lib/xmlparse.c
+++ b/ib/xmlparse.c
@@ -6034,6 +6034,8 @@ static enum XML_Error PTRCALL
internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
UNUSED_P(s);
+ UNUSED_P(end);
+ UNUSED_P(nextPtr);
ENTITY *entity;
const char *textStart, *textEnd;
const char *next;
@@ -6101,14 +6103,6 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
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;
- }
}
triggerReenter(parser);
return XML_ERROR_NONE;
--
2.33.0

View File

@ -0,0 +1,31 @@
From 8e439a9947e9dc80a395c0c7456545d8d9d9e421 Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Mon, 19 Aug 2024 22:34:13 +0200
Subject: [PATCH] lib: Detect integer overflow in dtdCopy
Reported by TaiYou
---
expat/lib/xmlparse.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/lib/xmlparse.c b/expat/lib/xmlparse.c
index 91682c188..e2327bdcf 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -7016,6 +7016,16 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
if (! newE)
return 0;
if (oldE->nDefaultAtts) {
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((size_t)oldE->nDefaultAtts
+ > ((size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE))) {
+ return 0;
+ }
+#endif
newE->defaultAtts
= ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
if (! newE->defaultAtts) {

View File

@ -0,0 +1,30 @@
From 9bf0f2c16ee86f644dd1432507edff94c08dc232 Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Mon, 19 Aug 2024 22:37:16 +0200
Subject: [PATCH] lib: Detect integer overflow in function nextScaffoldPart
Reported by TaiYou
---
expat/lib/xmlparse.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index 91682c188..f737575ea 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -7558,6 +7558,15 @@ nextScaffoldPart(XML_Parser parser) {
int next;
if (! dtd->scaffIndex) {
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if (parser->m_groupSize > ((size_t)(-1) / sizeof(int))) {
+ return -1;
+ }
+#endif
dtd->scaffIndex = (int *)MALLOC(parser, parser->m_groupSize * sizeof(int));
if (! dtd->scaffIndex)
return -1;

View File

@ -0,0 +1,89 @@
From b3836ff534c7cc78128fe7b935aad3d4353814ed Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Sun, 20 Oct 2024 23:24:27 +0200
Subject: [PATCH 3/3] tests: Cover XML_StopParser's new handling of status
XML_INITIALIZED
Prior to the fix to XML_StopParser, test test_misc_resumeparser_not_crashing
would crash with a NULL pointer dereference in function normal_updatePosition.
This was the AddressSanitizer output:
> AddressSanitizer:DEADLYSIGNAL
> =================================================================
> ==19700==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5623e07ad85f bp 0x7ffcf40da650 sp 0x7ffcf40da590 T0)
> ==19700==The signal is caused by a READ memory access.
> ==19700==Hint: address points to the zero page.
> #0 0x5623e07ad85f in normal_updatePosition [..]/lib/xmltok_impl.c:1781:13
> #1 0x5623e07a52ff in initUpdatePosition [..]/lib/xmltok.c:1031:3
> #2 0x5623e0762760 in XML_ResumeParser [..]/lib/xmlparse.c:2297:3
> #3 0x5623e074f7c1 in test_misc_resumeparser_not_crashing() misc_tests_cxx.cpp
> #4 0x5623e074e228 in srunner_run_all ([..]/build_asan_fuzzers/tests/runtests_cxx+0x136228)
> #5 0x5623e0753d2d in main ([..]/build_asan_fuzzers/tests/runtests_cxx+0x13bd2d)
> #6 0x7f802a39af79 (/lib64/libc.so.6+0x25f79)
> #7 0x7f802a39b034 in __libc_start_main (/lib64/libc.so.6+0x26034)
> #8 0x5623e064f340 in _start ([..]/build_asan_fuzzers/tests/runtests_cxx+0x37340)
>
> AddressSanitizer can not provide additional info.
> SUMMARY: AddressSanitizer: SEGV [..]/lib/xmltok_impl.c:1781:13 in normal_updatePosition
> ==19700==ABORTING
And this the UndefinedBehaviorSanitizer output:
> [..]/lib/xmltok_impl.c:1781:13: runtime error: load of null pointer of type 'const char'
> SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior [..]/lib/xmltok_impl.c:1781:13 in
---
tests/runtests.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/tests/runtests.c b/tests/runtests.c
index 4649359..2c88c7f 100644
--- a/tests/runtests.c
+++ b/tests/runtests.c
@@ -8207,6 +8207,35 @@ START_TEST(test_misc_tag_mismatch_reset_leak) {
}
END_TEST
+START_TEST(test_misc_resumeparser_not_crashing) {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ XML_GetBuffer(parser, 1);
+ XML_StopParser(parser, /*resumable=*/XML_TRUE);
+ XML_ResumeParser(parser); // could crash here, previously
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_misc_stopparser_rejects_unstarted_parser) {
+ const XML_Bool cases[] = {XML_TRUE, XML_FALSE};
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ const XML_Bool resumable = cases[i];
+ XML_Parser parser = XML_ParserCreate(NULL);
+
+ if (XML_GetErrorCode(parser) != XML_ERROR_NONE)
+ fail("There was not supposed to be any initial parse error.");
+
+ if (XML_StopParser(parser, resumable) != XML_STATUS_ERROR)
+ fail("Attempting to suspend a subordinate parser not faulted.");
+
+ if (XML_GetErrorCode(parser) != XML_ERROR_NOT_STARTED)
+ fail("parser not started.");
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+
static void
alloc_setup(void) {
XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
@@ -12707,6 +12736,8 @@ make_suite(void) {
tcase_add_test__ifdef_xml_dtd(
tc_misc, test_misc_deny_internal_entity_closing_doctype_issue_317);
tcase_add_test(tc_misc, test_misc_tag_mismatch_reset_leak);
+ tcase_add_test(tc_misc, test_misc_resumeparser_not_crashing);
+ tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser);
suite_add_tcase(s, tc_alloc);
tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown);
--
2.27.0

View File

@ -0,0 +1,70 @@
From 51c7019069b862e88d94ed228659e70bddd5de09 Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Mon, 21 Oct 2024 01:42:54 +0200
Subject: [PATCH 1/3] lib: Make XML_StopParser refuse to stop/suspend an
unstarted parser
---
lib/expat.h | 4 +++-
lib/xmlparse.c | 11 ++++++++++-
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/lib/expat.h b/lib/expat.h
index 504727a..3a9ac2c 100644
--- a/lib/expat.h
+++ b/lib/expat.h
@@ -127,7 +127,9 @@ enum XML_Error {
/* Added in 2.3.0. */
XML_ERROR_NO_BUFFER,
/* Added in 2.4.0. */
- XML_ERROR_AMPLIFICATION_LIMIT_BREACH
+ XML_ERROR_AMPLIFICATION_LIMIT_BREACH,
+ /* Added in 2.6.4. */
+ XML_ERROR_NOT_STARTED,
};
enum XML_Content_Type {
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index 75cb51d..e13b2bf 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -2208,6 +2208,9 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) {
if (parser == NULL)
return XML_STATUS_ERROR;
switch (parser->m_parsingStatus.parsing) {
+ case XML_INITIALIZED:
+ parser->m_errorCode = XML_ERROR_NOT_STARTED;
+ return XML_STATUS_ERROR;
case XML_SUSPENDED:
if (resumable) {
parser->m_errorCode = XML_ERROR_SUSPENDED;
@@ -2218,7 +2221,7 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) {
case XML_FINISHED:
parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
- default:
+ case XML_PARSING:
if (resumable) {
#ifdef XML_DTD
if (parser->m_isParamEntity) {
@@ -2229,6 +2232,9 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) {
parser->m_parsingStatus.parsing = XML_SUSPENDED;
} else
parser->m_parsingStatus.parsing = XML_FINISHED;
+ break;
+ default:
+ assert(0);
}
return XML_STATUS_OK;
}
@@ -2493,6 +2499,9 @@ XML_ErrorString(enum XML_Error code) {
case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
return XML_L(
"limit on input amplification factor (from DTD and entities) breached");
+ /* Added in 2.6.4. */
+ case XML_ERROR_NOT_STARTED:
+ return XML_L("parser not started");
}
return NULL;
}
--
2.27.0

View File

@ -0,0 +1,65 @@
From bcf353990c651d589c74aa0f283f9b392bbb68bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Wed, 19 Mar 2025 15:37:21 +0100
Subject: [PATCH] Make parser->m_eventPtr handling clearer
Reference: https://github.com/libexpat/libexpat/pull/989/commits/bcf353990c651d589c74aa0f283f9b392bbb68bf
Conflict: NA
---
lib/xmlparse.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index 67bd3a54..f8ae864a 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -4334,12 +4334,13 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
/* LCOV_EXCL_STOP */
}
- *eventPP = s = next;
switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
+ *eventPP = next;
*nextPtr = next;
return XML_ERROR_NONE;
case XML_FINISHED:
+ *eventPP = next;
return XML_ERROR_ABORTED;
case XML_PARSING:
if (parser->m_reenter) {
@@ -4347,6 +4348,7 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
}
/* Fall through */
default:;
+ *eventPP = s = next;
}
}
/* not reached */
@@ -5953,12 +5955,13 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
default:
return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
}
- parser->m_eventPtr = s = next;
switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
+ parser->m_eventPtr = next;
*nextPtr = next;
return XML_ERROR_NONE;
case XML_FINISHED:
+ parser->m_eventPtr = next;
return XML_ERROR_ABORTED;
case XML_PARSING:
if (parser->m_reenter) {
@@ -5966,6 +5969,7 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
}
/* Fall through */
default:;
+ parser->m_eventPtr = s = next;
}
}
}
--
2.37.3

View File

@ -0,0 +1,52 @@
From 89a9c6807c982b4fa8aa806dd72771d6642dd8a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Wed, 19 Mar 2025 02:20:49 +0100
Subject: [PATCH] Stop updating m_eventPtr on exit for reentry
The fix for recursive entity processing introduced a reenter flag that
returns the execution from the current function and switches to entity
processing.
The same fix also updates the m_eventPtr during this switch. However
this update changes the behaviour in certain cases as the older version
does not update the m_eventPtr while recursing into entity processing.
This commit removes the pointer update and restores the old behaviour.
Reference: https://github.com/libexpat/libexpat/pull/989/commits/89a9c6807c982b4fa8aa806dd72771d6642dd8a1
Conflict: NA
---
lib/xmlparse.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
index 626f56af..67bd3a54 100644
--- a/lib/xmlparse.c
+++ b/lib/xmlparse.c
@@ -3402,12 +3402,13 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
break;
/* LCOV_EXCL_STOP */
}
- *eventPP = s = next;
switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
+ *eventPP = next;
*nextPtr = next;
return XML_ERROR_NONE;
case XML_FINISHED:
+ *eventPP = next;
return XML_ERROR_ABORTED;
case XML_PARSING:
if (parser->m_reenter) {
@@ -3416,6 +3417,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
}
/* Fall through */
default:;
+ *eventPP = s = next;
}
}
/* not reached */
--
2.37.3

View File

@ -1,7 +1,7 @@
%define Rversion %(echo %{version} | sed -e 's/\\./_/g' -e 's/^/R_/')
Name: expat
Version: 2.5.0
Release: 4
Release: 9
Summary: An XML parser library
License: MIT
URL: https://libexpat.github.io/
@ -27,6 +27,23 @@ Patch17: backport-009-CVE-2023-52425.patch
Patch18: backport-001-CVE-2024-45490.patch
Patch19: backport-002-CVE-2024-45490.patch
Patch20: backport-003-CVE-2024-45490.patch
Patch21: backport-CVE-2024-45491.patch
Patch22: backport-CVE-2024-45492.patch
Patch23: backport-CVE-2024-50602.patch
Patch24: backport-CVE-2024-50602-testcase.patch
Patch25: backport-001-CVE-2024-8176.patch
Patch26: backport-002-CVE-2024-8176.patch
Patch27: backport-003-CVE-2024-8176.patch
Patch28: backport-004-CVE-2024-8176.patch
Patch29: backport-005-CVE-2024-8176.patch
Patch30: backport-006-CVE-2024-8176.patch
Patch31: backport-007-CVE-2024-8176.patch
Patch32: backport-008-CVE-2024-8176.patch
Patch33: backport-009-CVE-2024-8176.patch
Patch34: backport-010-CVE-2024-8176.patch
Patch35: backport-011-CVE-2024-8176.patch
Patch36: backport-Stop-updating-m_eventPtr-on-exit-for-reentry.patch
Patch37: backport-Make-parser-m_eventPtr-handling-clearer.patch
BuildRequires: sed,autoconf,automake,gcc-c++,libtool,xmlto
@ -52,36 +69,46 @@ autoreconf -fiv
%make_build
%install
%makeinstall
%make_install
find %{buildroot} -type f -name changelog -delete
%check
make check
%ldconfig_scriptlets
%make_build check
%files
%defattr(-,root,root)
%license COPYING AUTHORS
%{_bindir}/*
%{_libdir}/libexpat.so.1*
%exclude %{_docdir}/%{name}/AUTHORS
%files devel
%defattr(-,root,root)
%{_includedir}/*
%{_libdir}/{libexpat.*a,libexpat.so}
%{_libdir}/cmake/expat-%{version}
%{_libdir}/pkgconfig/expat.pc
%files help
%defattr(-,root,root)
%doc README.md
%{_mandir}/man1/*
%changelog
* Tue Apr 08 2025 zhuofeng <1107893276@qq.com> - 2.5.0-9
- backport upstream patches
* Fri Mar 28 2025 zhuofeng <1107893276@qq.com> - 2.5.0-8
- fix CVE-2024-8176
* Tue Oct 29 2024 liningjie <liningjie@xfusion.com> - 2.5.0-7
- add testcase for CVE-2024-50602
* Tue Oct 29 2024 liningjie <liningjie@xfusion.com> - 2.5.0-6
- fix CVE-2024-50602
* Wed Sep 04 2024 Funda Wang <fundawang@yeah.net> - 2.5.0-5
- fix CVE-2024-45491, CVE-2024-45492
* Mon Sep 2 2024 caixiaomeng <caixiaomeng2@huawei.com> - 2.5.0-4
- fix CVE-2024-45491
- fix CVE-2024-45490
* Wed Jun 12 2024 wangjiang <wangjiang37@h-partners.com> - 2.5.0-3
- fix CVE-2023-52425