[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1061471: bullseye-pu: package xerces-c/3.2.3+debian-3+deb11u1



On Thu, 25 Jan 2024 at 03:54:46 +0100, Guilhem Moulin wrote:
>  [x] attach debdiff against the package in oldstable

Oops, doing that now :-)

-- 
Guilhem.
diffstat for xerces-c-3.2.3+debian xerces-c-3.2.3+debian

 changelog                                                               |   12 
 patches/CVE-2018-1311-mitigation.patch                                  |   52 
 patches/CVE-2018-1311.patch                                             |  653 ++++++++++
 patches/CVE-2023-37536.patch                                            |   79 +
 patches/Fix-NetAccessorTest-to-exit-with-non-zero-status-in-case-.patch |   44 
 patches/series                                                          |    4 
 salsa-ci.yml                                                            |    9 
 7 files changed, 800 insertions(+), 53 deletions(-)

diff -Nru xerces-c-3.2.3+debian/debian/changelog xerces-c-3.2.3+debian/debian/changelog
--- xerces-c-3.2.3+debian/debian/changelog	2020-12-14 17:43:13.000000000 +0100
+++ xerces-c-3.2.3+debian/debian/changelog	2023-12-31 12:43:25.000000000 +0100
@@ -1,3 +1,15 @@
+xerces-c (3.2.3+debian-3+deb11u1) bullseye; urgency=high
+
+  * Non-maintainer upload.
+  * Fix CVE-2018-1311: Use-after-free on external DTD scan.  This replaces
+    RedHat's mitigation patch (which introduced a memory leak).
+    Closes: #947431
+  * Fix CVE-2023-37536: Integer overflows in DFAContentModel class.
+  * Upstream tests: Cherry-pick upstream patch to fix NetAccessorTest to exit
+    with non-zero status in case of error.
+
+ -- Guilhem Moulin <guilhem@debian.org>  Sun, 31 Dec 2023 12:43:25 +0100
+
 xerces-c (3.2.3+debian-3) unstable; urgency=medium
 
   * Fix MemHandlerTest1 on 32-bit systems to compensate for CVE-2018-1311 fix
diff -Nru xerces-c-3.2.3+debian/debian/patches/CVE-2018-1311-mitigation.patch xerces-c-3.2.3+debian/debian/patches/CVE-2018-1311-mitigation.patch
--- xerces-c-3.2.3+debian/debian/patches/CVE-2018-1311-mitigation.patch	2020-12-14 17:43:13.000000000 +0100
+++ xerces-c-3.2.3+debian/debian/patches/CVE-2018-1311-mitigation.patch	1970-01-01 01:00:00.000000000 +0100
@@ -1,52 +0,0 @@
-
-https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2018-1311
-
---- a/src/xercesc/internal/IGXMLScanner.cpp
-+++ b/src/xercesc/internal/IGXMLScanner.cpp
-@@ -1532,7 +1532,6 @@ void IGXMLScanner::scanDocTypeDecl()
-             DTDEntityDecl* declDTD = new (fMemoryManager) DTDEntityDecl(gDTDStr, false, fMemoryManager);
-             declDTD->setSystemId(sysId);
-             declDTD->setIsExternal(true);
--            Janitor<DTDEntityDecl> janDecl(declDTD);
- 
-             // Mark this one as a throw at end
-             reader->setThrowAtEnd(true);
-@@ -3095,7 +3094,6 @@ Grammar* IGXMLScanner::loadDTDGrammar(co
-     DTDEntityDecl* declDTD = new (fMemoryManager) DTDEntityDecl(gDTDStr, false, fMemoryManager);
-     declDTD->setSystemId(src.getSystemId());
-     declDTD->setIsExternal(true);
--    Janitor<DTDEntityDecl> janDecl(declDTD);
- 
-     // Mark this one as a throw at end
-     newReader->setThrowAtEnd(true);
---- a/tests/expected/MemHandlerTest1.log
-+++ b/tests/expected/MemHandlerTest1.log
-@@ -1,4 +1,4 @@
--At destruction, domBuilderMemMonitor has 0 bytes.
--At destruction, sax2MemMonitor has 0 bytes.
--At destruction, sax1MemMonitor has 0 bytes.
-+At destruction, domBuilderMemMonitor has 276 bytes.
-+At destruction, sax2MemMonitor has 276 bytes.
-+At destruction, sax1MemMonitor has 276 bytes.
- At destruction, staticMemMonitor has 0 bytes.
---- /dev/null
-+++ b/tests/expected/MemHandlerTest1_32.log
-@@ -0,0 +1,4 @@
-+At destruction, domBuilderMemMonitor has 180 bytes.
-+At destruction, sax2MemMonitor has 180 bytes.
-+At destruction, sax1MemMonitor has 180 bytes.
-+At destruction, staticMemMonitor has 0 bytes.
---- a/scripts/run-test.in
-+++ b/scripts/run-test.in
-@@ -46,6 +46,11 @@ run_test() {
-     sed -i -e 's;\( *[0-9][0-9]* *ms *\);{timing removed};' "$output"
- 
-     exp=$(cat "${srcdir}/expected/${name}.log")
-+
-+    if [ "${name}" = "MemHandlerTest1" ] && [ "$(dpkg-architecture -q DEB_HOST_ARCH_BITS)" -eq 32 ]; then
-+        exp=$(cat "${srcdir}/expected/${name}_32.log")
-+    fi
-+
-     obs=$(cat "$output")
- 
-     echo "------"
diff -Nru xerces-c-3.2.3+debian/debian/patches/CVE-2018-1311.patch xerces-c-3.2.3+debian/debian/patches/CVE-2018-1311.patch
--- xerces-c-3.2.3+debian/debian/patches/CVE-2018-1311.patch	1970-01-01 01:00:00.000000000 +0100
+++ xerces-c-3.2.3+debian/debian/patches/CVE-2018-1311.patch	2023-12-31 12:43:25.000000000 +0100
@@ -0,0 +1,653 @@
+From: Karen Arutyunov <karen@codesynthesis.com>
+Date: Wed, 13 Dec 2023 09:59:07 +0200
+Subject: XERCESC-2188 - Use-after-free on external DTD scan (CVE-2018-1311)
+
+These are the instructions for observing the bug (before this commit):
+
+$ git clone https://github.com/apache/xerces-c.git
+$ cd xerces-c
+$ mkdir build
+$ cd build
+$ cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug ..
+$ make -j8
+$ cp ../samples/data/personal.xml .
+
+$ cat <<EOF >personal.dtd
+<?xml encoding="ISO-8859-1"?>
+<!ENTITY % nonExistentEntity SYSTEM "non-existent.ent">
+%nonExistentEntity;
+EOF
+
+$ gdb samples/StdInParse
+(gdb) b IGXMLScanner.cpp:1544
+(gdb) run <personal.xml
+1544	            fReaderMgr.pushReader(reader, declDTD);
+(gdb) p declDTD
+$1 = (xercesc_4_0::DTDEntityDecl *) 0x49ac68
+(gdb) n
+1547	            dtdScanner.scanExtSubsetDecl(false, true);
+(gdb) n
+1548	        }
+(gdb) s
+...
+(gdb) s                     # The Janitor is about to delete the above declDTD.
+90	        delete fData;
+(gdb) p fData
+$1 = (xercesc_4_0::DTDEntityDecl *) 0x49ac68
+(gdb) b ReaderMgr.cpp:1024
+(gdb) n
+...
+(gdb) n                     # Now we about to dereference the deleted declDTD.
+1024	    if (curEntity && !curEntity->isExternal())
+(gdb) p curEntity
+$2 = (const xercesc_4_0::XMLEntityDecl *) 0x49ac68
+
+Origin: https://github.com/apache/xerces-c/commit/e0024267504188e42ace4dd9031d936786914835
+Bug: https://github.com/apache/xerces-c/pull/47
+Bug: https://github.com/apache/xerces-c/pull/54
+Bug: https://issues.apache.org/jira/browse/XERCESC-2188
+Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2018-1311
+Bug-Debian: https://bugs.debian.org/947431
+---
+ src/xercesc/internal/DGXMLScanner.cpp |   6 +-
+ src/xercesc/internal/IGXMLScanner.cpp |   6 +-
+ src/xercesc/internal/ReaderMgr.cpp    | 207 ++++++++++++++++++++++++----------
+ src/xercesc/internal/ReaderMgr.hpp    |  92 ++++++++++++---
+ 4 files changed, 229 insertions(+), 82 deletions(-)
+
+diff --git a/src/xercesc/internal/DGXMLScanner.cpp b/src/xercesc/internal/DGXMLScanner.cpp
+index 4334223..895dfeb 100644
+--- a/src/xercesc/internal/DGXMLScanner.cpp
++++ b/src/xercesc/internal/DGXMLScanner.cpp
+@@ -1052,13 +1052,12 @@ void DGXMLScanner::scanDocTypeDecl()
+             DTDEntityDecl* declDTD = new (fMemoryManager) DTDEntityDecl(gDTDStr, false, fMemoryManager);
+             declDTD->setSystemId(sysId);
+             declDTD->setIsExternal(true);
+-            Janitor<DTDEntityDecl> janDecl(declDTD);
+ 
+             // Mark this one as a throw at end
+             reader->setThrowAtEnd(true);
+ 
+             // And push it onto the stack, with its pseudo name
+-            fReaderMgr.pushReader(reader, declDTD);
++            fReaderMgr.pushReaderAdoptEntity(reader, declDTD);
+ 
+             // Tell it its not in an include section
+             dtdScanner.scanExtSubsetDecl(false, true);
+@@ -2131,13 +2130,12 @@ Grammar* DGXMLScanner::loadDTDGrammar(const InputSource& src,
+     DTDEntityDecl* declDTD = new (fMemoryManager) DTDEntityDecl(gDTDStr, false, fMemoryManager);
+     declDTD->setSystemId(src.getSystemId());
+     declDTD->setIsExternal(true);
+-    Janitor<DTDEntityDecl> janDecl(declDTD);
+ 
+     // Mark this one as a throw at end
+     newReader->setThrowAtEnd(true);
+ 
+     // And push it onto the stack, with its pseudo name
+-    fReaderMgr.pushReader(newReader, declDTD);
++    fReaderMgr.pushReaderAdoptEntity(newReader, declDTD);
+ 
+     //  If we have a doc type handler and advanced callbacks are enabled,
+     //  call the doctype event.
+diff --git a/src/xercesc/internal/IGXMLScanner.cpp b/src/xercesc/internal/IGXMLScanner.cpp
+index 0062400..5247ef7 100644
+--- a/src/xercesc/internal/IGXMLScanner.cpp
++++ b/src/xercesc/internal/IGXMLScanner.cpp
+@@ -1532,13 +1532,12 @@ void IGXMLScanner::scanDocTypeDecl()
+             DTDEntityDecl* declDTD = new (fMemoryManager) DTDEntityDecl(gDTDStr, false, fMemoryManager);
+             declDTD->setSystemId(sysId);
+             declDTD->setIsExternal(true);
+-            Janitor<DTDEntityDecl> janDecl(declDTD);
+ 
+             // Mark this one as a throw at end
+             reader->setThrowAtEnd(true);
+ 
+             // And push it onto the stack, with its pseudo name
+-            fReaderMgr.pushReader(reader, declDTD);
++            fReaderMgr.pushReaderAdoptEntity(reader, declDTD);
+ 
+             // Tell it its not in an include section
+             dtdScanner.scanExtSubsetDecl(false, true);
+@@ -3095,13 +3094,12 @@ Grammar* IGXMLScanner::loadDTDGrammar(const InputSource& src,
+     DTDEntityDecl* declDTD = new (fMemoryManager) DTDEntityDecl(gDTDStr, false, fMemoryManager);
+     declDTD->setSystemId(src.getSystemId());
+     declDTD->setIsExternal(true);
+-    Janitor<DTDEntityDecl> janDecl(declDTD);
+ 
+     // Mark this one as a throw at end
+     newReader->setThrowAtEnd(true);
+ 
+     // And push it onto the stack, with its pseudo name
+-    fReaderMgr.pushReader(newReader, declDTD);
++    fReaderMgr.pushReaderAdoptEntity(newReader, declDTD);
+ 
+     //  If we have a doc type handler and advanced callbacks are enabled,
+     //  call the doctype event.
+diff --git a/src/xercesc/internal/ReaderMgr.cpp b/src/xercesc/internal/ReaderMgr.cpp
+index d14483e..9f363a0 100644
+--- a/src/xercesc/internal/ReaderMgr.cpp
++++ b/src/xercesc/internal/ReaderMgr.cpp
+@@ -45,12 +45,61 @@
+ 
+ XERCES_CPP_NAMESPACE_BEGIN
+ 
++// ---------------------------------------------------------------------------
++//  ReaderMgr::ReaderData: Constructors and Destructor
++// ---------------------------------------------------------------------------
++ReaderMgr::ReaderData::ReaderData( XMLReader* const       reader
++                                   , XMLEntityDecl* const entity
++                                   , const bool           adoptEntity) :
++
++    fReader(reader)
++    , fEntity(entity)
++    , fEntityAdopted(adoptEntity)
++{
++}
++
++ReaderMgr::ReaderData::~ReaderData()
++{
++    delete fReader;
++
++    if (fEntityAdopted)
++        delete fEntity;
++}
++
++// ---------------------------------------------------------------------------
++//  ReaderMgr::ReaderData: Getter methods
++// ---------------------------------------------------------------------------
++XMLReader* ReaderMgr::ReaderData::getReader() const
++{
++  return fReader;
++}
++
++XMLEntityDecl* ReaderMgr::ReaderData::getEntity() const
++{
++  return fEntity;
++}
++
++bool ReaderMgr::ReaderData::getEntityAdopted() const
++{
++  return fEntityAdopted;
++}
++
++//
++//  This method gives up the entity object ownership but leaves the fEntity
++//  pointer intact.
++//
++XMLEntityDecl* ReaderMgr::ReaderData::releaseEntity()
++{
++  fEntityAdopted = false;
++  return fEntity;
++}
++
+ // ---------------------------------------------------------------------------
+ //  ReaderMgr: Constructors and Destructor
+ // ---------------------------------------------------------------------------
+ ReaderMgr::ReaderMgr(MemoryManager* const manager) :
+ 
+-    fCurEntity(0)
++    fCurReaderData(0)
+     , fCurReader(0)
+     , fEntityHandler(0)
+     , fEntityStack(0)
+@@ -66,12 +115,11 @@ ReaderMgr::ReaderMgr(MemoryManager* const manager) :
+ ReaderMgr::~ReaderMgr()
+ {
+     //
+-    //  Clean up the reader and entity stacks. Note that we don't own the
+-    //  entities, so we don't delete the current entity (and the entity stack
+-    //  does not own its elements either, so deleting it will not delete the
+-    //  entities it still references!)
++    //  Clean up the reader stack and orphan entities container. Note that
++    //  all adopted entities (potentially contained in fCurReaderData,
++    //  fReaderStack, and fEntityStack) are deleted here.
+     //
+-    delete fCurReader;
++    delete fCurReaderData;
+     delete fReaderStack;
+     delete fEntityStack;
+ }
+@@ -357,9 +405,9 @@ void ReaderMgr::cleanStackBackTo(const XMLSize_t readerNum)
+         if (fReaderStack->empty())
+             ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::RdrMgr_ReaderIdNotFound, fMemoryManager);
+ 
+-        delete fCurReader;
+-        fCurReader = fReaderStack->pop();
+-        fCurEntity = fEntityStack->pop();
++        delete fCurReaderData;
++        fCurReaderData = fReaderStack->pop();
++        fCurReader = fCurReaderData->getReader ();
+     }
+ }
+ 
+@@ -795,20 +843,20 @@ const XMLCh* ReaderMgr::getCurrentEncodingStr() const
+ 
+ const XMLEntityDecl* ReaderMgr::getCurrentEntity() const
+ {
+-    return fCurEntity;
++    return fCurReaderData? fCurReaderData->getEntity() : 0;
+ }
+ 
+ 
+ XMLEntityDecl* ReaderMgr::getCurrentEntity()
+ {
+-    return fCurEntity;
++    return fCurReaderData? fCurReaderData->getEntity() : 0;
+ }
+ 
+ 
+ XMLSize_t ReaderMgr::getReaderDepth() const
+ {
+     // If the stack doesn't exist, its obviously zero
+-    if (!fEntityStack)
++    if (!fReaderStack)
+         return 0;
+ 
+     //
+@@ -816,7 +864,7 @@ XMLSize_t ReaderMgr::getReaderDepth() const
+     //  reader. So if there is no current reader and none on the stack,
+     //  its zero, else its some non-zero value.
+     //
+-    XMLSize_t retVal = fEntityStack->size();
++    XMLSize_t retVal = fReaderStack->size();
+     if (fCurReader)
+         retVal++;
+     return retVal;
+@@ -852,7 +900,7 @@ void ReaderMgr::getLastExtEntityInfo(LastExtEntityInfo& lastInfo) const
+ bool ReaderMgr::isScanningPERefOutOfLiteral() const
+ {
+     // If the current reader is not for an entity, then definitely not
+-    if (!fCurEntity)
++    if (!fCurReaderData || !fCurReaderData->getEntity())
+         return false;
+ 
+     //
+@@ -867,13 +915,19 @@ bool ReaderMgr::isScanningPERefOutOfLiteral() const
+     return false;
+ }
+ 
+-
+ bool ReaderMgr::pushReader(         XMLReader* const        reader
+                             ,       XMLEntityDecl* const    entity)
++{
++    return pushReaderAdoptEntity(reader, entity, false);
++}
++
++bool ReaderMgr::pushReaderAdoptEntity(     XMLReader* const        reader
++                                       ,   XMLEntityDecl* const    entity
++                                       ,   const bool              adoptEntity)
+ {
+     //
+     //  First, if an entity was passed, we have to confirm that this entity
+-    //  is not already on the entity stack. If so, then this is a recursive
++    //  is not already on the reader stack. If so, then this is a recursive
+     //  entity expansion, so we issue an error and refuse to put the reader
+     //  on the stack.
+     //
+@@ -881,19 +935,30 @@ bool ReaderMgr::pushReader(         XMLReader* const        reader
+     //  nothing to do. If there is no entity stack yet, then of coures it
+     //  cannot already be there.
+     //
+-    if (entity && fEntityStack)
++    if (entity && fReaderStack)
+     {
+-        const XMLSize_t count = fEntityStack->size();
++        // @@ Strangely, we don't check the entity at the top of the stack
++        //    (fCurReaderData). Is it a bug?
++        //
++        const XMLSize_t count = fReaderStack->size();
+         const XMLCh* const theName = entity->getName();
+         for (XMLSize_t index = 0; index < count; index++)
+         {
+-            const XMLEntityDecl* curDecl = fEntityStack->elementAt(index);
++            const XMLEntityDecl* curDecl =
++              fReaderStack->elementAt(index)->getEntity();
++
+             if (curDecl)
+             {
+                 if (XMLString::equals(theName, curDecl->getName()))
+                 {
+-                    // Oops, already there so delete reader and return
++                    // Oops, already there so delete reader and entity and
++                    // return.
++                    //
+                     delete reader;
++
++                    if (adoptEntity)
++                        delete entity;
++
+                     return false;
+                 }
+             }
+@@ -905,52 +970,37 @@ bool ReaderMgr::pushReader(         XMLReader* const        reader
+     //  tell it it does own its elements.
+     //
+     if (!fReaderStack)
+-        fReaderStack = new (fMemoryManager) RefStackOf<XMLReader>(16, true, fMemoryManager);
+-
+-    // And the entity stack, which does not own its elements
+-    if (!fEntityStack)
+-        fEntityStack = new (fMemoryManager) RefStackOf<XMLEntityDecl>(16, false, fMemoryManager);
++        fReaderStack = new (fMemoryManager) RefStackOf<ReaderData>(16, true, fMemoryManager);
+ 
+     //
+-    //  Push the current reader and entity onto their respective stacks.
+-    //  Note that the the current entity can be null if the current reader
+-    //  is not for an entity.
++    //  Push the current reader and entity onto the stack. Note that
++    //  the current entity can be null if the current reader is not for
++    //  an entity.
+     //
+-    if (fCurReader)
+-    {
+-        fReaderStack->push(fCurReader);
+-        fEntityStack->push(fCurEntity);
+-    }
++    if (fCurReaderData)
++        fReaderStack->push(fCurReaderData);
+ 
+     //
+     //  Make the passed reader and entity the current top of stack. The
+     //  passed entity can (and often is) null.
+     //
++    fCurReaderData = new (fMemoryManager) ReaderData(reader, entity, adoptEntity);
+     fCurReader = reader;
+-    fCurEntity = entity;
+ 
+     return true;
+ }
+ 
+-
+ void ReaderMgr::reset()
+ {
+     // Reset all of the flags
+     fThrowEOE = false;
+ 
+     // Delete the current reader and flush the reader stack
+-    delete fCurReader;
++    delete fCurReaderData;
++    fCurReaderData = 0;
+     fCurReader = 0;
+     if (fReaderStack)
+         fReaderStack->removeAllElements();
+-
+-    //
+-    //  And do the same for the entity stack, but don't delete the current
+-    //  entity (if any) since we don't own them.
+-    //
+-    fCurEntity = 0;
+-    if (fEntityStack)
+-        fEntityStack->removeAllElements();
+ }
+ 
+ 
+@@ -1014,7 +1064,9 @@ ReaderMgr::getLastExtEntity(const XMLEntityDecl*& itsEntity) const
+     //  search the stack; else, keep the reader that we've got since its
+     //  either an external entity reader or the main file reader.
+     //
+-    const XMLEntityDecl* curEntity = fCurEntity;
++    const XMLEntityDecl* curEntity =
++        fCurReaderData? fCurReaderData->getEntity() : 0;
++
+     if (curEntity && !curEntity->isExternal())
+     {
+         XMLSize_t index = fReaderStack->size();
+@@ -1024,7 +1076,7 @@ ReaderMgr::getLastExtEntity(const XMLEntityDecl*& itsEntity) const
+             {
+                 // Move down to the previous element and get a pointer to it
+                 index--;
+-                curEntity = fEntityStack->elementAt(index);
++                curEntity = fReaderStack->elementAt(index)->getEntity();
+ 
+                 //
+                 //  If its null or its an external entity, then this reader
+@@ -1032,12 +1084,12 @@ ReaderMgr::getLastExtEntity(const XMLEntityDecl*& itsEntity) const
+                 //
+                 if (!curEntity)
+                 {
+-                    theReader = fReaderStack->elementAt(index);
++                    theReader = fReaderStack->elementAt(index)->getReader ();
+                     break;
+                 }
+                  else if (curEntity->isExternal())
+                 {
+-                    theReader = fReaderStack->elementAt(index);
++                    theReader = fReaderStack->elementAt(index)->getReader ();
+                     break;
+                 }
+ 
+@@ -1048,6 +1100,11 @@ ReaderMgr::getLastExtEntity(const XMLEntityDecl*& itsEntity) const
+         }
+     }
+ 
++    // @@ It feels like we may end up with theReader being from the top of
++    //    the stack (fCurReader) and itsEntity being from the bottom of the
++    //    stack (if there are no null or external entities on the stack).
++    //    Is it a bug?
++    //
+     itsEntity = curEntity;
+     return theReader;
+ }
+@@ -1059,31 +1116,59 @@ bool ReaderMgr::popReader()
+     //  We didn't get any more, so try to pop off a reader. If the reader
+     //  stack is empty, then we are at the end, so return false.
+     //
++    //  @@ It feels like we never pop the reader pushed to the stack first
++    //     (think of fReaderStack empty but fCurReader not null). Is it a
++    //     bug?
++    //
+     if (fReaderStack->empty())
+         return false;
+ 
+     //
+-    //  Remember the current entity, before we pop off a new one. We might
++    //  Remember the current reader, before we pop off a new one. We might
+     //  need this to throw the end of entity exception at the end.
+     //
+-    XMLEntityDecl* prevEntity = fCurEntity;
++    ReaderData* prevReaderData = fCurReaderData;
+     const bool prevReaderThrowAtEnd = fCurReader->getThrowAtEnd();
+     const XMLSize_t readerNum = fCurReader->getReaderNum();
+ 
+     //
+-    //  Delete the current reader and pop a new reader and entity off
+-    //  the stacks.
++    //  Pop a new reader and entity off the stack.
+     //
+-    delete fCurReader;
+-    fCurReader = fReaderStack->pop();
+-    fCurEntity = fEntityStack->pop();
++    fCurReaderData = fReaderStack->pop();
++    fCurReader = fCurReaderData->getReader();
+ 
+     //
+     //  If there was a previous entity, and either the fThrowEOE flag is set
+-    //  or reader was marked as such, then throw an end of entity.
++    //  or reader was marked as such, then throw an end of entity. Otherwise,
++    //  delete the previous reader data.
+     //
+-    if (prevEntity && (fThrowEOE || prevReaderThrowAtEnd))
+-        throw EndOfEntityException(prevEntity, readerNum);
++    if (prevReaderData->getEntity() && (fThrowEOE || prevReaderThrowAtEnd))
++    {
++        //
++        // If the entity is adopted, then move it to fEntityStack so that
++        // its life-time is prolonged to the life-time of this reader
++        // manager. Also delete the previous reader data before throwing
++        // EndOfEntityException.
++        //
++        XMLEntityDecl* entity;
++
++        if (prevReaderData->getEntityAdopted())
++        {
++            if (!fEntityStack)
++                fEntityStack = new (fMemoryManager) RefStackOf<XMLEntityDecl>(16, true, fMemoryManager);
++
++            entity = prevReaderData->releaseEntity();
++            fEntityStack->push(entity);
++        }
++        else
++            entity = prevReaderData->getEntity();
++
++        delete prevReaderData;
++
++        throw EndOfEntityException(entity, readerNum);
++    }
++    else
++        delete prevReaderData;
+ 
+     while (true)
+     {
+@@ -1113,9 +1198,9 @@ bool ReaderMgr::popReader()
+             return false;
+ 
+         // Else pop again and try it one more time
+-        delete fCurReader;
+-        fCurReader = fReaderStack->pop();
+-        fCurEntity = fEntityStack->pop();
++        delete fCurReaderData;
++        fCurReaderData = fReaderStack->pop();
++        fCurReader = fCurReaderData->getReader();
+     }
+     return true;
+ }
+diff --git a/src/xercesc/internal/ReaderMgr.hpp b/src/xercesc/internal/ReaderMgr.hpp
+index f63b219..0855ed7 100644
+--- a/src/xercesc/internal/ReaderMgr.hpp
++++ b/src/xercesc/internal/ReaderMgr.hpp
+@@ -160,6 +160,12 @@ public :
+                 XMLReader* const        reader
+         ,       XMLEntityDecl* const    entity
+     );
++    bool pushReaderAdoptEntity
++    (
++                XMLReader* const        reader
++        ,       XMLEntityDecl* const    entity
++        ,       const bool              adoptEntity = true
++    );
+     void reset();
+ 
+ 
+@@ -208,16 +214,72 @@ private :
+     ReaderMgr(const ReaderMgr&);
+     ReaderMgr& operator=(const ReaderMgr&);
+ 
++    // -----------------------------------------------------------------------
++    //  Private data types
++    // -----------------------------------------------------------------------
++    class ReaderData : public XMemory
++    {
++    public  :
++        // ---------------------------------------------------------------------
++        //  Constructors and Destructor
++        // ---------------------------------------------------------------------
++        ReaderData
++        (    XMLReader* const     reader
++           , XMLEntityDecl* const entity
++           , const bool           adoptEntity
++        );
++
++        ~ReaderData();
++
++        // ----------------------------------------------------------------------
++        //  Getter methods
++        // ----------------------------------------------------------------------
++        XMLReader* getReader() const;
++        XMLEntityDecl* getEntity() const;
++        bool getEntityAdopted() const;
++
++        XMLEntityDecl* releaseEntity();
++
++    private :
++        // ---------------------------------------------------------------------
++        //  Unimplemented constructors and operators
++        // ---------------------------------------------------------------------
++        ReaderData();
++        ReaderData(const ReaderData&);
++        ReaderData& operator=(const ReaderData&);
++
++        // ---------------------------------------------------------------------
++        //  Private data members
++        //
++        //  fReader
++        //      This is the pointer to the reader object that must be destroyed
++        //      when this object is destroyed.
++        //
++        //  fEntity
++        //  fEntityAdopted
++        //      This is the pointer to the entity object that, if adopted, must
++        //      be destroyed when this object is destroyed.
++        //
++        //      Note that we need to keep up with which of the pushed readers
++        //      are pushed entity values that are being spooled. This is done
++        //      to avoid the problem of recursive definitions.
++        // ---------------------------------------------------------------------
++        XMLReader*     fReader;
++        XMLEntityDecl* fEntity;
++        bool           fEntityAdopted;
++    };
++
+     // -----------------------------------------------------------------------
+     //  Private data members
+     //
+-    //  fCurEntity
+-    //      This is the current top of stack entity. We pull it off the stack
+-    //      and store it here for efficiency.
++    //  fCurReaderData
++    //      This is the current top of the reader data stack. We pull it off
++    //      the stack and store it here for efficiency.
+     //
+     //  fCurReader
+-    //      This is the current top of stack reader. We pull it off the
+-    //      stack and store it here for efficiency.
++    //      This is the reader of the current top of the reader data stack.
++    //      It contains the same value as fCurReaderData->fReader or NULL,
++    //      if fCurReaderData is NULL. We store it here for efficiency.
+     //
+     //  fEntityHandler
+     //      This is the installed entity handler. Its installed via the
+@@ -225,10 +287,14 @@ private :
+     //      process of creating external entity readers.
+     //
+     //  fEntityStack
+-    //      We need to keep up with which of the pushed readers are pushed
+-    //      entity values that are being spooled. This is done to avoid the
+-    //      problem of recursive definitions. This stack consists of refs to
+-    //      EntityDecl objects for the pushed entities.
++    //      This is a storage of orphaned XMLEntityDecl objects. The
++    //      popReader() function adds a reader manager-adopted entity object
++    //      to this storage before passing its pointer to the constructor
++    //      of the being thrown EndOfEntityException exception. This makes
++    //      sure that the life-time of an entity exposed to the exception
++    //      handlers is the same as the life-time of reader manager (and so
++    //      normally the life-time of the scanner which embeds the reader
++    //      manager).
+     //
+     //  fNextReaderNum
+     //      This is the reader serial number value. Each new reader that is
+@@ -236,8 +302,8 @@ private :
+     //      us catch things like partial markup errors and such.
+     //
+     //  fReaderStack
+-    //      This is the stack of reader references. We own all the readers
+-    //      and destroy them when they are used up.
++    //      This is the stack of reader data references. We own all the
++    //      entries and destroy them when they are used up.
+     //
+     //  fThrowEOE
+     //      This flag controls whether we throw an exception when we hit an
+@@ -252,12 +318,12 @@ private :
+     //  fStandardUriConformant
+     //      This flag controls whether we force conformant URI
+     // -----------------------------------------------------------------------
+-    XMLEntityDecl*              fCurEntity;
++    ReaderData*                 fCurReaderData;
+     XMLReader*                  fCurReader;
+     XMLEntityHandler*           fEntityHandler;
+     RefStackOf<XMLEntityDecl>*  fEntityStack;
+     unsigned int                fNextReaderNum;
+-    RefStackOf<XMLReader>*      fReaderStack;
++    RefStackOf<ReaderData>*     fReaderStack;
+     bool                        fThrowEOE;
+     XMLReader::XMLVersion       fXMLVersion;
+     bool                        fStandardUriConformant;
diff -Nru xerces-c-3.2.3+debian/debian/patches/CVE-2023-37536.patch xerces-c-3.2.3+debian/debian/patches/CVE-2023-37536.patch
--- xerces-c-3.2.3+debian/debian/patches/CVE-2023-37536.patch	1970-01-01 01:00:00.000000000 +0100
+++ xerces-c-3.2.3+debian/debian/patches/CVE-2023-37536.patch	2023-12-31 12:43:25.000000000 +0100
@@ -0,0 +1,79 @@
+From: Scott Cantor <cantor.2@osu.edu>
+Date: Mon, 10 Oct 2022 11:48:07 -0400
+Subject: XERCESC-2241 - Integer overflows in DFAContentModel class
+
+Origin: https://github.com/apache/xerces-c/commit/1296a40db07308dbaac32494469f609b00cdfaf3
+Bug: https://github.com/apache/xerces-c/pull/51
+Bug: https://issues.apache.org/jira/browse/XERCESC-2241
+Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2023-37536
+---
+ src/xercesc/validators/common/DFAContentModel.cpp | 28 ++++++++++++++++++++---
+ 1 file changed, 25 insertions(+), 3 deletions(-)
+
+diff --git a/src/xercesc/validators/common/DFAContentModel.cpp b/src/xercesc/validators/common/DFAContentModel.cpp
+index 589efea..247ff62 100644
+--- a/src/xercesc/validators/common/DFAContentModel.cpp
++++ b/src/xercesc/validators/common/DFAContentModel.cpp
+@@ -24,6 +24,7 @@
+ //  Includes
+ // ---------------------------------------------------------------------------
+ #include <xercesc/util/RuntimeException.hpp>
++#include <xercesc/util/OutOfMemoryException.hpp>
+ #include <xercesc/framework/XMLBuffer.hpp>
+ #include <xercesc/framework/XMLElementDecl.hpp>
+ #include <xercesc/framework/XMLValidator.hpp>
+@@ -41,6 +42,7 @@
+ #include <xercesc/util/RefHashTableOf.hpp>
+ #include <xercesc/util/XMLInteger.hpp>
+ #include <math.h>
++#include <limits>
+ 
+ XERCES_CPP_NAMESPACE_BEGIN
+ 
+@@ -606,8 +608,15 @@ void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
+     //  in the fLeafCount member.
+     //
+     fLeafCount=countLeafNodes(curNode);
++    // Avoid integer overflow in below fLeafCount++ increment
++    if (fLeafCount > (std::numeric_limits<unsigned int>::max() - 1))
++        throw OutOfMemoryException();
+     fEOCPos = fLeafCount++;
+ 
++    // Avoid integer overflow in below memory allocation
++    if (fLeafCount > (std::numeric_limits<size_t>::max() / sizeof(CMLeaf*)))
++        throw OutOfMemoryException();
++
+     //  We need to build an array of references to the non-epsilon
+     //  leaf nodes. We will put them in the array according to their position values
+     //
+@@ -1304,14 +1313,27 @@ unsigned int DFAContentModel::countLeafNodes(ContentSpecNode* const curNode)
+         if(nLoopCount!=0)
+         {
+             count += countLeafNodes(cursor);
+-            for(unsigned int i=0;i<nLoopCount;i++)
+-                count += countLeafNodes(rightNode);
++            const unsigned int countRight = countLeafNodes(rightNode);
++            // Avoid integer overflow in below multiplication
++            if (countRight > (std::numeric_limits<unsigned int>::max() / nLoopCount))
++                throw OutOfMemoryException();
++            const unsigned int countRightMulLoopCount = nLoopCount * countRight;
++            // Avoid integer overflow in below addition
++            if (count > (std::numeric_limits<unsigned int>::max() - countRightMulLoopCount))
++                throw OutOfMemoryException();
++            count += countRightMulLoopCount;
+             return count;
+         }
+         if(leftNode)
+             count+=countLeafNodes(leftNode);
+         if(rightNode)
+-            count+=countLeafNodes(rightNode);
++        {
++            const unsigned int countRight = countLeafNodes(rightNode);
++            // Avoid integer overflow in below addition
++            if (count > (std::numeric_limits<unsigned int>::max() - countRight))
++                throw OutOfMemoryException();
++            count+=countRight;
++        }
+     }
+     return count;
+ }
diff -Nru xerces-c-3.2.3+debian/debian/patches/Fix-NetAccessorTest-to-exit-with-non-zero-status-in-case-.patch xerces-c-3.2.3+debian/debian/patches/Fix-NetAccessorTest-to-exit-with-non-zero-status-in-case-.patch
--- xerces-c-3.2.3+debian/debian/patches/Fix-NetAccessorTest-to-exit-with-non-zero-status-in-case-.patch	1970-01-01 01:00:00.000000000 +0100
+++ xerces-c-3.2.3+debian/debian/patches/Fix-NetAccessorTest-to-exit-with-non-zero-status-in-case-.patch	2023-12-31 12:43:25.000000000 +0100
@@ -0,0 +1,44 @@
+From: Boris Kolpackov <boris@codesynthesis.com>
+Date: Wed, 13 Dec 2023 08:46:59 +0200
+Subject: Fix NetAccessorTest to exit with non-zero status in case of error
+
+Origin: https://github.com/apache/xerces-c/commit/12eecd6b97840b3b49147f6c4245295d83c1198d
+---
+ tests/src/NetAccessorTest/NetAccessorTest.cpp | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/tests/src/NetAccessorTest/NetAccessorTest.cpp b/tests/src/NetAccessorTest/NetAccessorTest.cpp
+index 3bb735b..c2affbd 100644
+--- a/tests/src/NetAccessorTest/NetAccessorTest.cpp
++++ b/tests/src/NetAccessorTest/NetAccessorTest.cpp
+@@ -122,6 +122,8 @@ main(int argc, char** argv)
+     // Get the URL
+     char* url = argv[1];
+     
++    int r = 1;
++
+     // Do the test
+     try
+     {
+@@ -148,11 +150,11 @@ main(int argc, char** argv)
+ 		
+ 		// Delete the is
+ 		delete is;
+-	
++		r = 0;
+     }
+     catch(const XMLException& toCatch)
+     {
+-        XERCES_STD_QUALIFIER cout << "Exception during test:\n    "
++        XERCES_STD_QUALIFIER cerr << "Exception during test:\n    "
+              << toCatch.getMessage()
+              << XERCES_STD_QUALIFIER endl;
+     }
+@@ -160,6 +162,6 @@ main(int argc, char** argv)
+     // And call the termination method
+     XMLPlatformUtils::Terminate();
+ 
+-    return 0;
++    return r;
+ }
+ 
diff -Nru xerces-c-3.2.3+debian/debian/patches/series xerces-c-3.2.3+debian/debian/patches/series
--- xerces-c-3.2.3+debian/debian/patches/series	2020-12-14 17:43:13.000000000 +0100
+++ xerces-c-3.2.3+debian/debian/patches/series	2023-12-31 12:43:25.000000000 +0100
@@ -1 +1,3 @@
-CVE-2018-1311-mitigation.patch
+CVE-2023-37536.patch
+Fix-NetAccessorTest-to-exit-with-non-zero-status-in-case-.patch
+CVE-2018-1311.patch
diff -Nru xerces-c-3.2.3+debian/debian/salsa-ci.yml xerces-c-3.2.3+debian/debian/salsa-ci.yml
--- xerces-c-3.2.3+debian/debian/salsa-ci.yml	1970-01-01 01:00:00.000000000 +0100
+++ xerces-c-3.2.3+debian/debian/salsa-ci.yml	2023-12-31 12:43:25.000000000 +0100
@@ -0,0 +1,9 @@
+---
+include:
+  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml
+
+variables:
+  RELEASE: 'bullseye'
+  SALSA_CI_DISABLE_REPROTEST: 1
+  SALSA_CI_DISABLE_LINTIAN: 1
+  SALSA_CI_DISABLE_PIUPARTS: 1

Attachment: signature.asc
Description: PGP signature


Reply to: