Compare commits
10 Commits
d120f4736b
...
49c0d577ac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49c0d577ac | ||
|
|
7e7d820f4e | ||
|
|
61225c7922 | ||
|
|
2fc4b29f0d | ||
|
|
b908834a6e | ||
|
|
ca53218800 | ||
|
|
1ab989a431 | ||
|
|
b14adfa69c | ||
|
|
323f716435 | ||
|
|
4722b2b42f |
202
backport-001-CVE-2024-8176.patch
Normal file
202
backport-001-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
31
backport-002-CVE-2024-8176.patch
Normal file
31
backport-002-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
163
backport-003-CVE-2024-8176.patch
Normal file
163
backport-003-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
89
backport-004-CVE-2024-8176.patch
Normal file
89
backport-004-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
247
backport-005-CVE-2024-8176.patch
Normal file
247
backport-005-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
105
backport-006-CVE-2024-8176.patch
Normal file
105
backport-006-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
249
backport-007-CVE-2024-8176.patch
Normal file
249
backport-007-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
229
backport-008-CVE-2024-8176.patch
Normal file
229
backport-008-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
199
backport-009-CVE-2024-8176.patch
Normal file
199
backport-009-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
133
backport-010-CVE-2024-8176.patch
Normal file
133
backport-010-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
53
backport-011-CVE-2024-8176.patch
Normal file
53
backport-011-CVE-2024-8176.patch
Normal 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
|
||||
|
||||
31
backport-CVE-2024-45491.patch
Normal file
31
backport-CVE-2024-45491.patch
Normal 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) {
|
||||
30
backport-CVE-2024-45492.patch
Normal file
30
backport-CVE-2024-45492.patch
Normal 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;
|
||||
89
backport-CVE-2024-50602-testcase.patch
Normal file
89
backport-CVE-2024-50602-testcase.patch
Normal 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
|
||||
|
||||
70
backport-CVE-2024-50602.patch
Normal file
70
backport-CVE-2024-50602.patch
Normal 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
|
||||
65
backport-Make-parser-m_eventPtr-handling-clearer.patch
Normal file
65
backport-Make-parser-m_eventPtr-handling-clearer.patch
Normal 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
|
||||
|
||||
52
backport-Stop-updating-m_eventPtr-on-exit-for-reentry.patch
Normal file
52
backport-Stop-updating-m_eventPtr-on-exit-for-reentry.patch
Normal 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
|
||||
|
||||
45
expat.spec
45
expat.spec
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user