comphelper/source/misc/storagehelper.cxx    |   13 
 package/inc/ByteGrabber.hxx                 |    1 
 package/inc/ZipFile.hxx                     |   27 -
 package/inc/ZipPackage.hxx                  |    1 
 package/qa/cppunit/data/fail/ofz56826-1.zip |binary
 package/source/zipapi/ByteGrabber.cxx       |   18 
 package/source/zipapi/MemoryByteGrabber.hxx |   34 +
 package/source/zipapi/ZipFile.cxx           |  555 +++++++++++++++++++++++++---
 package/source/zippackage/ZipPackage.cxx    |   44 ++
 package/source/zippackage/zipfileaccess.cxx |    2 
 sc/qa/unit/filters-test.cxx                 |   25 +
 sfx2/source/doc/objmisc.cxx                 |    6 
 sfx2/source/doc/objserv.cxx                 |   10 
 sfx2/source/doc/objstor.cxx                 |    2 
 vcl/qa/cppunit/pdfexport/pdfexport.cxx      |    5 
 15 files changed, 666 insertions(+), 77 deletions(-)

New commits:
commit 72a0f94d49764bc1298d721019b7313ec7a0e1ab
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Aug 13 17:59:18 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:34 2024 +0200

    package: ZipPackage: add additional check for entries STORED with
    
    ... data descriptor; only allow it for encrypted ODF entries, which
    requires reading the manifest first.
    
    Change-Id: If36d31a4cb93e7af78f48be3ed899ad9d9bb28f0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171911
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 32cad89592ec04ab552399095c91dd76afb3002c)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171779
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>
    (cherry picked from commit 525fe1a2e58a4d6164aa104e893d4f07a5709b27)

diff --git a/package/inc/ZipPackage.hxx b/package/inc/ZipPackage.hxx
index e6cf614ad503..5784bed6e5bf 100644
--- a/package/inc/ZipPackage.hxx
+++ b/package/inc/ZipPackage.hxx
@@ -103,6 +103,7 @@ class ZipPackage final : public cppu::WeakImplHelper
 
     bool isLocalFile() const;
 
+    void checkZipEntriesWithDD();
     void parseManifest();
     void parseContentType();
     void getZipFileContents();
diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index d7a6633a4266..16ae81e2e40e 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -882,7 +882,11 @@ sal_uInt64 ZipFile::readLOC(ZipEntry &rEntry)
         if ((rEntry.nFlag & 0x08) != 0)
         {
 #if 0
-            if (nLocMethod == STORED) // example: fdo68983.odt has this :(
+            // Unfortunately every encrypted ODF package entry hits this,
+            // because ODF requires deflated entry with value STORED and OOo/LO
+            // has always written compressed streams with data descriptor.
+            // So it is checked later in ZipPackage::checkZipEntriesWithDD()
+            if (nLocMethod == STORED)
             {
                 SAL_INFO("package", "LOC STORED with data descriptor: \"" << 
rEntry.sPath << "\"");
                 bBroken = true;
@@ -1270,6 +1274,11 @@ sal_Int32 ZipFile::readCEN()
                 }
             }
 
+            if (aEntry.nMethod == STORED && aEntry.nCompressedSize != 
aEntry.nSize)
+            {
+                throw ZipException("entry STORED with inconsistent size");
+            }
+
             aMemGrabber.skipBytes(nCommentLen);
 
             // unfortunately readLOC is required now to check the consistency
diff --git a/package/source/zippackage/ZipPackage.cxx 
b/package/source/zippackage/ZipPackage.cxx
index 48ecb3aa4209..b353a0caf9d0 100644
--- a/package/source/zippackage/ZipPackage.cxx
+++ b/package/source/zippackage/ZipPackage.cxx
@@ -158,6 +158,31 @@ bool ZipPackage::isLocalFile() const
     return comphelper::isFileUrl(m_aURL);
 }
 
+// note: don't check for StorageFormats::ZIP, it breaks signing!
+void ZipPackage::checkZipEntriesWithDD()
+{
+    if (!m_bForceRecovery)
+    {
+        ZipEnumeration entries{m_pZipFile->entries()};
+        while (entries.hasMoreElements())
+        {
+            ZipEntry const& rEntry{*entries.nextElement()};
+            if ((rEntry.nFlag & 0x08) != 0 && rEntry.nMethod == STORED)
+            {
+                uno::Reference<XPropertySet> xStream;
+                getByHierarchicalName(rEntry.sPath) >>= xStream;
+                if (!xStream->getPropertyValue("WasEncrypted").get<bool>())
+                {
+                    SAL_INFO("package", "entry STORED with data descriptor but 
not encrypted: \"" << rEntry.sPath << "\"");
+                    throw ZipIOException(
+                        THROW_WHERE
+                        "entry STORED with data descriptor but not encrypted");
+                }
+            }
+        }
+    }
+}
+
 void ZipPackage::parseManifest()
 {
     if ( m_nFormat != embed::StorageFormats::PACKAGE )
@@ -352,6 +377,8 @@ void ZipPackage::parseManifest()
                     bManifestParsed = true;
                 }
 
+                checkZipEntriesWithDD(); // check before removing entries!
+
                 // now hide the manifest.xml file from user
                 xMetaInfFolder->removeByName( sManifest );
             }
@@ -583,7 +610,10 @@ void ZipPackage::getZipFileContents()
     if ( m_nFormat == embed::StorageFormats::PACKAGE )
         parseManifest();
     else if ( m_nFormat == embed::StorageFormats::OFOPXML )
+    {
         parseContentType();
+        checkZipEntriesWithDD();
+    }
 }
 
 void SAL_CALL ZipPackage::initialize( const uno::Sequence< Any >& aArguments )
commit f52d1148d185b58005289a7d7ab29226d9989df2
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Jul 19 20:43:05 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:34 2024 +0200

    package: ZipFile: check Zip64 end of central directory for consistency
    
    Change-Id: Iae873ec8175922e210398ef8e0f83e148a795c2c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170783
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    Tested-by: Jenkins
    (cherry picked from commit ca21cc985d57fffe7c834159b17c095206304994)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171209
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>
    (cherry picked from commit 1d37c37ab6025bf5b107cc0c18eae5739ff02149)

diff --git a/package/inc/ZipFile.hxx b/package/inc/ZipFile.hxx
index c431aa23043d..f633846a3b30 100644
--- a/package/inc/ZipFile.hxx
+++ b/package/inc/ZipFile.hxx
@@ -90,7 +90,7 @@ private:
 
     sal_uInt64 readLOC(ZipEntry &rEntry);
     sal_Int32 readCEN();
-    sal_Int32 findEND();
+    std::tuple<sal_Int64, sal_Int64, sal_Int64> findCentralDirectory();
     void recover();
     static bool readExtraFields(MemoryByteGrabber& aMemGrabber, sal_Int16 
nExtraLen,
                                 sal_uInt64/*&*/ nSize, sal_uInt64/*&*/ 
nCompressedSize,
diff --git a/package/source/zipapi/MemoryByteGrabber.hxx 
b/package/source/zipapi/MemoryByteGrabber.hxx
index 650b5c6a6d02..dd876d66ebfa 100644
--- a/package/source/zipapi/MemoryByteGrabber.hxx
+++ b/package/source/zipapi/MemoryByteGrabber.hxx
@@ -99,6 +99,22 @@ public:
         nInt32 |= ( mpBuffer [mnCurrent++] & 0xFF ) << 24;
         return nInt32;
     }
+
+    sal_uInt64 ReadUInt64()
+    {
+        if (mnCurrent + 8 > mnEnd)
+            return 0;
+
+        sal_uInt64 nInt64 = mpBuffer[mnCurrent++] & 0xFF;
+        nInt64 |= static_cast<sal_Int64>(mpBuffer[mnCurrent++] & 0xFF) << 8;
+        nInt64 |= static_cast<sal_Int64>(mpBuffer[mnCurrent++] & 0xFF) << 16;
+        nInt64 |= static_cast<sal_Int64>(mpBuffer[mnCurrent++] & 0xFF) << 24;
+        nInt64 |= static_cast<sal_Int64>(mpBuffer[mnCurrent++] & 0xFF) << 32;
+        nInt64 |= static_cast<sal_Int64>(mpBuffer[mnCurrent++] & 0xFF) << 40;
+        nInt64 |= static_cast<sal_Int64>(mpBuffer[mnCurrent++] & 0xFF) << 48;
+        nInt64 |= static_cast<sal_Int64>(mpBuffer[mnCurrent++] & 0xFF) << 56;
+        return nInt64;
+    }
 };
 
 #endif
diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index 7bbdfbe593f5..d7a6633a4266 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -978,18 +978,19 @@ sal_uInt64 ZipFile::readLOC(ZipEntry &rEntry)
     return nEnd;
 }
 
-sal_Int32 ZipFile::findEND()
+std::tuple<sal_Int64, sal_Int64, sal_Int64> ZipFile::findCentralDirectory()
 {
     // this method is called in constructor only, no need for mutex
-    sal_Int32 nPos, nEnd;
     Sequence < sal_Int8 > aBuffer;
     try
     {
-        sal_Int32 nLength = static_cast <sal_Int32 > (aGrabber.getLength());
+        sal_Int64 const nLength = aGrabber.getLength();
         if (nLength < ENDHDR)
-            return -1;
-        nPos = nLength - ENDHDR - ZIP_MAXNAMELEN;
-        nEnd = nPos >= 0 ? nPos : 0 ;
+        {
+            throw ZipException("Zip too small!");
+        }
+        sal_Int64 nPos = nLength - ENDHDR - ZIP_MAXNAMELEN;
+        sal_Int64 nEnd = nPos >= 0 ? nPos : 0;
 
         aGrabber.seek( nEnd );
 
@@ -999,13 +1000,145 @@ sal_Int32 ZipFile::findEND()
 
         const sal_Int8 *pBuffer = aBuffer.getConstArray();
 
+        sal_Int64 nEndPos = {};
         nPos = nSize - ENDHDR;
         while ( nPos >= 0 )
         {
             if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && 
pBuffer[nPos+2] == 5 && pBuffer[nPos+3] == 6 )
-                return nPos + nEnd;
+            {
+                nEndPos = nPos + nEnd;
+                break;
+            }
             nPos--;
+            if (nPos == 0)
+            {
+                throw ZipException("Zip END signature not found!");
+            }
+        }
+
+        aGrabber.seek(nEndPos + 4);
+        sal_uInt16 const nEndDisk = aGrabber.ReadUInt16();
+        if (nEndDisk != 0)
+        {   // only single disk is supported!
+            throw ZipException("invalid end (disk)" );
+        }
+        sal_uInt16 const nEndDirDisk = aGrabber.ReadUInt16();
+        if (nEndDirDisk != 0)
+        {
+            throw ZipException("invalid end (directory disk)" );
         }
+        sal_uInt16 const nEndDiskEntries = aGrabber.ReadUInt16();
+        sal_uInt16 const nEndEntries = aGrabber.ReadUInt16();
+        if (nEndDiskEntries != nEndEntries)
+        {
+            throw ZipException("invalid end (entries)" );
+        }
+        sal_Int32 const nEndDirSize = aGrabber.ReadInt32();
+        sal_Int32 const nEndDirOffset = aGrabber.ReadInt32();
+
+        // Zip64 end of central directory locator must immediately precede
+        // end of central directory record
+        if (20 <= nEndPos)
+        {
+            aGrabber.seek(nEndPos - 20);
+            Sequence<sal_Int8> aZip64EndLocator;
+            aGrabber.readBytes(aZip64EndLocator, 20);
+            MemoryByteGrabber loc64Grabber(aZip64EndLocator);
+            if (loc64Grabber.ReadUInt8() == 'P'
+                && loc64Grabber.ReadUInt8() == 'K'
+                && loc64Grabber.ReadUInt8() == 6
+                && loc64Grabber.ReadUInt8() == 7)
+            {
+                sal_uInt32 const nLoc64Disk = loc64Grabber.ReadUInt32();
+                if (nLoc64Disk != 0)
+                {
+                    throw ZipException("invalid Zip64 end locator (disk)");
+                }
+                sal_Int64 const nLoc64End64Offset = loc64Grabber.ReadUInt64();
+                if (nEndPos < 20 + 56 || (nEndPos - 20 - 56) < 
nLoc64End64Offset
+                    || nLoc64End64Offset < 0)
+                {
+                    throw ZipException("invalid Zip64 end locator (offset)");
+                }
+                sal_uInt32 const nLoc64Disks = loc64Grabber.ReadUInt32();
+                if (nLoc64Disks != 1)
+                {
+                    throw ZipException("invalid Zip64 end locator (number of 
disks)");
+                }
+                aGrabber.seek(nLoc64End64Offset);
+                Sequence<sal_Int8> aZip64EndDirectory;
+                aGrabber.readBytes(aZip64EndDirectory, nEndPos - 20 - 
nLoc64End64Offset);
+                MemoryByteGrabber end64Grabber(aZip64EndDirectory);
+                if (end64Grabber.ReadUInt8() != 'P'
+                    || end64Grabber.ReadUInt8() != 'K'
+                    || end64Grabber.ReadUInt8() != 6
+                    || end64Grabber.ReadUInt8() != 6)
+                {
+                    throw ZipException("invalid Zip64 end (signature)");
+                }
+                sal_Int64 const nEnd64Size = end64Grabber.ReadUInt64();
+                if (nEnd64Size != nEndPos - 20 - nLoc64End64Offset - 12)
+                {
+                    throw ZipException("invalid Zip64 end (size)");
+                }
+                end64Grabber.ReadUInt16(); // ignore version made by
+                end64Grabber.ReadUInt16(); // ignore version needed to extract
+                sal_uInt32 const nEnd64Disk = end64Grabber.ReadUInt32();
+                if (nEnd64Disk != 0)
+                {
+                    throw ZipException("invalid Zip64 end (disk)");
+                }
+                sal_uInt32 const nEnd64EndDisk = end64Grabber.ReadUInt32();
+                if (nEnd64EndDisk != 0)
+                {
+                    throw ZipException("invalid Zip64 end (directory disk)");
+                }
+                sal_uInt64 const nEnd64DiskEntries = end64Grabber.ReadUInt64();
+                sal_uInt64 const nEnd64Entries = end64Grabber.ReadUInt64();
+                if (nEnd64DiskEntries != nEnd64Entries)
+                {
+                    throw ZipException("invalid Zip64 end (entries)");
+                }
+                sal_Int64 const nEnd64DirSize = end64Grabber.ReadUInt64();
+                sal_Int64 const nEnd64DirOffset = end64Grabber.ReadUInt64();
+                if (nEndEntries != sal_uInt16(-1) && nEnd64Entries != 
nEndEntries)
+                {
+                    throw ZipException("inconsistent Zip/Zip64 end (entries)");
+                }
+                if (o3tl::make_unsigned(nEndDirSize) != sal_uInt32(-1)
+                    && nEnd64DirSize != nEndDirSize)
+                {
+                    throw ZipException("inconsistent Zip/Zip64 end (size)");
+                }
+                if (o3tl::make_unsigned(nEndDirOffset) != sal_uInt32(-1)
+                    && nEnd64DirOffset != nEndDirOffset)
+                {
+                    throw ZipException("inconsistent Zip/Zip64 end (offset)");
+                }
+
+                sal_Int64 end;
+                if (o3tl::checked_add<sal_Int64>(nEnd64DirOffset, 
nEnd64DirSize, end)
+                    || nLoc64End64Offset < end
+                    || nEnd64DirOffset < 0
+                    || nLoc64End64Offset - nEnd64DirSize != nEnd64DirOffset)
+                {
+                    throw ZipException("Invalid Zip64 end (bad central 
directory size)");
+                }
+
+                return { nEnd64Entries, nEnd64DirSize, nEnd64DirOffset };
+            }
+        }
+
+        sal_Int32 end;
+        if (o3tl::checked_add<sal_Int32>(nEndDirOffset, nEndDirSize, end)
+            || nEndPos < end
+            || nEndDirOffset < 0
+            || nEndPos - nEndDirSize != nEndDirOffset)
+        {
+            throw ZipException("Invalid END header (bad central directory 
size)");
+        }
+
+        return { nEndEntries, nEndDirSize, nEndDirOffset };
     }
     catch ( IllegalArgumentException& )
     {
@@ -1019,41 +1152,30 @@ sal_Int32 ZipFile::findEND()
     {
         throw ZipException("Zip END signature not found!" );
     }
-    throw ZipException("Zip END signature not found!" );
 }
 
 sal_Int32 ZipFile::readCEN()
 {
     // this method is called in constructor only, no need for mutex
-    sal_Int32 nCenPos = -1, nLocPos;
-    sal_uInt16 nCount;
+    sal_Int32 nCenPos = -1;
 
     try
     {
-        sal_Int32 nEndPos = findEND();
-        if (nEndPos == -1)
-            return -1;
-        aGrabber.seek(nEndPos + ENDTOT);
-        sal_uInt16 nTotal = aGrabber.ReadUInt16();
-        sal_Int32 nCenLen = aGrabber.ReadInt32();
-        sal_Int32 nCenOff = aGrabber.ReadInt32();
-
-        if ( nTotal * CENHDR > nCenLen )
-            throw ZipException("invalid END header (bad entry count)" );
+        auto [nTotal, nCenLen, nCenOff] = findCentralDirectory();
+        nCenPos = nCenOff; // data before start of zip is not supported
 
         if ( nTotal > ZIP_MAXENTRIES )
             throw ZipException("too many entries in ZIP File" );
 
-        if ( nCenLen < 0 || nCenLen > nEndPos )
-            throw ZipException("Invalid END header (bad central directory 
size)" );
-
-        nCenPos = nEndPos - nCenLen;
+        if (nCenLen < nTotal * CENHDR) // prevent overflow with ZIP_MAXENTRIES
+            throw ZipException("invalid END header (bad entry count)" );
 
-        if ( nCenOff < 0 || nCenOff > nCenPos )
-            throw ZipException("Invalid END header (bad central directory 
size)" );
+        if (SAL_MAX_INT32 < nCenLen)
+        {
+            throw ZipException("central directory too big");
+        }
 
-        nLocPos = nCenPos - nCenOff;
-        aGrabber.seek( nCenPos );
+        aGrabber.seek(nCenPos);
         Sequence < sal_Int8 > aCENBuffer ( nCenLen );
         sal_Int64 nRead = aGrabber.readBytes ( aCENBuffer, nCenLen );
         if ( static_cast < sal_Int64 > ( nCenLen ) != nRead )
@@ -1066,6 +1188,7 @@ sal_Int32 ZipFile::readCEN()
         ::std::vector<std::pair<sal_uInt64, sal_uInt64>> unallocated = { { 0, 
nCenPos } };
 
         aEntries.reserve(nTotal);
+        sal_Int64 nCount;
         for (nCount = 0 ; nCount < nTotal; nCount++)
         {
             sal_Int32 nTestSig = aMemGrabber.ReadInt32();
@@ -1105,8 +1228,6 @@ sal_Int32 ZipFile::readCEN()
             aEntry.nSize = nSize;
             aEntry.nOffset = nOffset;
 
-            if (o3tl::checked_add<sal_Int64>(aEntry.nOffset, nLocPos, 
aEntry.nOffset))
-                throw ZipException("Integer-overflow");
             if (o3tl::checked_multiply<sal_Int64>(aEntry.nOffset, -1, 
aEntry.nOffset))
                 throw ZipException("Integer-overflow");
 
commit f3b68860aaddf77f454a70c1bcc5c494f37550e4
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Jul 16 12:12:09 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:34 2024 +0200

    package: add additional consistency checks for local file header
    
    Check it contains same as central directory header, also check data
    descriptor if available.  Also check there are no gaps or overlaps.
    
    This causes 3 fuzzer generated test documents to fail to load; adapt
    tests.
    
    Change-Id: If5813652f3bd03e90fdf95eb97e1e1523455b2b8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170571
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit efae4fc42d5fe3c0a69757226f38efc10d101194)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170588
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    (cherry picked from commit cffa22ee046fd62b38692ca25dea3a6827889d9a)
    
    Disallowing Zip64 caused tdf128550.pptx be reported as corrupted, which
    contains a pointless Zip64 will 0 size and compressed size, so try to
    ignore that. Pages_5.pages contains a pointless Zip64 with the same
    values that are also in the local header, ignore that too...

diff --git a/package/inc/ByteGrabber.hxx b/package/inc/ByteGrabber.hxx
index ba1512cf5162..4a93398a7704 100644
--- a/package/inc/ByteGrabber.hxx
+++ b/package/inc/ByteGrabber.hxx
@@ -61,6 +61,7 @@ public:
 
     sal_uInt16 ReadUInt16();
     sal_uInt32 ReadUInt32();
+    sal_uInt64 ReadUInt64();
     sal_Int16 ReadInt16()
     {
         return static_cast<sal_Int16>(ReadUInt16());
diff --git a/package/inc/ZipFile.hxx b/package/inc/ZipFile.hxx
index 0d96abe3d067..c431aa23043d 100644
--- a/package/inc/ZipFile.hxx
+++ b/package/inc/ZipFile.hxx
@@ -29,6 +29,7 @@
 #include "HashMaps.hxx"
 #include "EncryptionData.hxx"
 
+#include <optional>
 #include <unordered_set>
 
 class MemoryByteGrabber;
@@ -87,13 +88,13 @@ private:
 
     void getSizeAndCRC( sal_Int64 nOffset, sal_Int64 nCompressedSize, 
sal_Int64 *nSize, sal_Int32 *nCRC );
 
-    void readLOC( ZipEntry &rEntry );
+    sal_uInt64 readLOC(ZipEntry &rEntry);
     sal_Int32 readCEN();
     sal_Int32 findEND();
     void recover();
-    static void readExtraFields(MemoryByteGrabber& aMemGrabber, sal_Int16 
nExtraLen,
-                                /*sal_uInt64& nSize, sal_uInt64& 
nCompressedSize,
-                                sal_uInt64* nOffset,*/
+    static bool readExtraFields(MemoryByteGrabber& aMemGrabber, sal_Int16 
nExtraLen,
+                                sal_uInt64/*&*/ nSize, sal_uInt64/*&*/ 
nCompressedSize,
+                                /*::std::optional<sal_uInt64> & roOffset,*/
                                 OUString const* pCENFilenameToCheck);
 
 public:
diff --git a/package/source/zipapi/ByteGrabber.cxx 
b/package/source/zipapi/ByteGrabber.cxx
index b58a7087f468..19b5a4cc9755 100644
--- a/package/source/zipapi/ByteGrabber.cxx
+++ b/package/source/zipapi/ByteGrabber.cxx
@@ -122,4 +122,22 @@ sal_uInt32 ByteGrabber::ReadUInt32()
           | ( pSequence[3] & 0xFF ) << 24 );
 }
 
+sal_uInt64 ByteGrabber::ReadUInt64()
+{
+    std::scoped_lock aGuard(m_aMutex);
+
+    if (xStream->readBytes(aSequence, 8) != 8)
+        return 0;
+
+    pSequence = aSequence.getConstArray();
+    return  static_cast<sal_uInt64>(pSequence[0] & 0xFF)
+          | static_cast<sal_uInt64>(pSequence[1] & 0xFF) << 8
+          | static_cast<sal_uInt64>(pSequence[2] & 0xFF) << 16
+          | static_cast<sal_uInt64>(pSequence[3] & 0xFF) << 24
+          | static_cast<sal_uInt64>(pSequence[4] & 0xFF) << 32
+          | static_cast<sal_uInt64>(pSequence[5] & 0xFF) << 40
+          | static_cast<sal_uInt64>(pSequence[6] & 0xFF) << 48
+          | static_cast<sal_uInt64>(pSequence[7] & 0xFF) << 56;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index d79ce545aaf3..7bbdfbe593f5 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -772,7 +772,7 @@ uno::Reference< XInputStream > ZipFile::getWrappedRawStream(
     return createStreamForZipEntry ( aMutexHolder, rEntry, rData, 
UNBUFF_STREAM_WRAPPEDRAW, true, true, aMediaType );
 }
 
-void ZipFile::readLOC( ZipEntry &rEntry )
+sal_uInt64 ZipFile::readLOC(ZipEntry &rEntry)
 {
     ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
 
@@ -788,19 +788,23 @@ void ZipFile::readLOC( ZipEntry &rEntry )
     // Just verify the path and calculate the data offset and otherwise
     // rely on the central directory info.
 
-    aGrabber.ReadInt16(); //version
-    aGrabber.ReadInt16(); //flag
-    aGrabber.ReadInt16(); //how
+    aGrabber.ReadInt16(); // version - ignore any mismatch (Maven created JARs)
+    sal_uInt16 const nLocFlag = aGrabber.ReadUInt16(); // general purpose bit 
flag
+    sal_uInt16 const nLocMethod = aGrabber.ReadUInt16(); // compression method
+    // Do *not* compare timestamps, since MSO 2010 can produce documents
+    // with timestamp difference in the central directory entry and local
+    // file header.
     aGrabber.ReadInt32(); //time
-    aGrabber.ReadInt32(); //crc
-    aGrabber.ReadInt32(); //compressed size
-    aGrabber.ReadInt32(); //size
+    sal_uInt32 nLocCrc = aGrabber.ReadUInt32(); //crc
+    sal_uInt64 nLocCompressedSize = aGrabber.ReadUInt32(); //compressed size
+    sal_uInt64 nLocSize = aGrabber.ReadUInt32(); //size
     sal_Int16 nPathLen = aGrabber.ReadInt16();
     sal_Int16 nExtraLen = aGrabber.ReadInt16();
     rEntry.nOffset = aGrabber.getPosition() + nPathLen + nExtraLen;
 
     // FIXME64: need to read 64bit LOC
 
+    sal_Int64 nEnd = {}; // avoid -Werror=maybe-uninitialized
     bool bBroken = false;
 
     try
@@ -828,8 +832,140 @@ void ZipFile::readLOC( ZipEntry &rEntry )
             rEntry.sPath = sLOCPath;
         }
 
-        bBroken = rEntry.nPathLen != nPathLen
-                        || rEntry.sPath != sLOCPath;
+        if (rEntry.nPathLen != nPathLen || rEntry.sPath != sLOCPath)
+        {
+            SAL_INFO("package", "LOC inconsistent name: \"" << rEntry.sPath << 
"\"");
+            bBroken = true;
+        }
+
+        bool isZip64{false};
+        //::std::optional<sal_uInt64> oOffset64;
+        if (nExtraLen != 0)
+        {
+            Sequence<sal_Int8> aExtraBuffer;
+            aGrabber.readBytes(aExtraBuffer, nExtraLen);
+            MemoryByteGrabber extraMemGrabber(aExtraBuffer);
+
+            isZip64 = readExtraFields(extraMemGrabber, nExtraLen,
+                    nLocSize, nLocCompressedSize, /*oOffset64,*/ &sLOCPath);
+            if (isZip64)
+            {
+                SAL_INFO("package", "Zip64 not supported: \"" << rEntry.sPath 
<< "\"");
+                bBroken = true; // this version does NOT support Zip64 files
+            }
+        }
+
+        // Just plain ignore bits 1 & 2 of the flag field - they are either
+        // purely informative, or even fully undefined (depending on method).
+        // Also ignore bit 11 ("Language encoding flag"): tdf125300.docx is
+        // example with mismatch - and the actual file names are compared in
+        // any case and required to be UTF-8.
+        if ((rEntry.nFlag & ~0x806U) != (nLocFlag & ~0x806U))
+        {
+            SAL_INFO("package", "LOC inconsistent flag: \"" << rEntry.sPath << 
"\"");
+            bBroken = true;
+        }
+
+        // TODO: "older versions with encrypted streams write mismatching 
DEFLATE/STORE" ???
+        if (rEntry.nMethod != nLocMethod)
+        {
+            SAL_INFO("package", "LOC inconsistent method: \"" << rEntry.sPath 
<< "\"");
+            bBroken = true;
+        }
+
+        if (o3tl::checked_add<sal_Int64>(rEntry.nOffset, 
rEntry.nCompressedSize, nEnd))
+        {
+            throw ZipException("Integer-overflow");
+        }
+
+        // read "data descriptor" - this can be 12, 16, 20, or 24 bytes in size
+        if ((rEntry.nFlag & 0x08) != 0)
+        {
+#if 0
+            if (nLocMethod == STORED) // example: fdo68983.odt has this :(
+            {
+                SAL_INFO("package", "LOC STORED with data descriptor: \"" << 
rEntry.sPath << "\"");
+                bBroken = true;
+            }
+            else
+#endif
+            {
+                decltype(nLocCrc) nDDCrc;
+                decltype(nLocCompressedSize) nDDCompressedSize;
+                decltype(nLocSize) nDDSize;
+                aGrabber.seek(aGrabber.getPosition() + rEntry.nCompressedSize);
+                sal_uInt32 nTemp = aGrabber.ReadUInt32();
+                if (nTemp == 0x08074b50) // APPNOTE says PK78 is optional???
+                {
+                    nDDCrc = aGrabber.ReadUInt32();
+                }
+                else
+                {
+                    nDDCrc = nTemp;
+                }
+                if (isZip64)
+                {
+                    nDDCompressedSize = aGrabber.ReadUInt64();
+                    nDDSize = aGrabber.ReadUInt64();
+                }
+                else
+                {
+                    nDDCompressedSize = aGrabber.ReadUInt32();
+                    nDDSize = aGrabber.ReadUInt32();
+                }
+                if (nEnd < aGrabber.getPosition())
+                {
+                    nEnd = aGrabber.getPosition();
+                }
+                else
+                {
+                    SAL_INFO("package", "LOC invalid size: \"" << rEntry.sPath 
<< "\"");
+                    bBroken = true;
+                }
+                // tdf91429.docx has same values in LOC and in (superfluous) DD
+                if ((nLocCrc == 0 || nLocCrc == nDDCrc)
+                    && (nLocCompressedSize == 0 || nLocCompressedSize == 
sal_uInt64(-1) || nLocCompressedSize == nDDCompressedSize)
+                    && (nLocSize == 0 || nLocSize == sal_uInt64(-1) || 
nLocSize == nDDSize))
+
+                {
+                    nLocCrc = nDDCrc;
+                    nLocCompressedSize = nDDCompressedSize;
+                    nLocSize = nDDSize;
+                }
+                else
+                {
+                    SAL_INFO("package", "LOC non-0 with data descriptor: \"" 
<< rEntry.sPath << "\"");
+                    bBroken = true;
+                }
+            }
+        }
+
+        // unit test file export64.zip has nLocCrc/nLocCS/nLocSize = 0 on 
mimetype
+        if (nLocCrc != 0 && static_cast<sal_uInt32>(rEntry.nCrc) != nLocCrc)
+        {
+            SAL_INFO("package", "LOC inconsistent CRC: \"" << rEntry.sPath << 
"\"");
+            bBroken = true;
+        }
+
+        if (nLocCompressedSize != 0 && 
static_cast<sal_uInt64>(rEntry.nCompressedSize) != nLocCompressedSize)
+        {
+            SAL_INFO("package", "LOC inconsistent compressed size: \"" << 
rEntry.sPath << "\"");
+            bBroken = true;
+        }
+
+        if (nLocSize != 0 && static_cast<sal_uInt64>(rEntry.nSize) != nLocSize)
+        {
+            SAL_INFO("package", "LOC inconsistent size: \"" << rEntry.sPath << 
"\"");
+            bBroken = true;
+        }
+
+#if 0
+        if (oOffset64 && o3tl::make_unsigned(nPos) != *oOffset64)
+        {
+            SAL_INFO("package", "LOC inconsistent offset: \"" << rEntry.sPath 
<< "\"");
+            bBroken = true;
+        }
+#endif
     }
     catch(...)
     {
@@ -838,6 +974,8 @@ void ZipFile::readLOC( ZipEntry &rEntry )
 
     if ( bBroken && !bRecoveryMode )
         throw ZipIOException("The stream seems to be broken!" );
+
+    return nEnd;
 }
 
 sal_Int32 ZipFile::findEND()
@@ -925,7 +1063,7 @@ sal_Int32 ZipFile::readCEN()
 
         ZipEntry aEntry;
         sal_Int16 nCommentLen;
-        sal_Int64 nMinOffset{nEndPos};
+        ::std::vector<std::pair<sal_uInt64, sal_uInt64>> unallocated = { { 0, 
nCenPos } };
 
         aEntries.reserve(nTotal);
         for (nCount = 0 ; nCount < nTotal; nCount++)
@@ -969,7 +1107,6 @@ sal_Int32 ZipFile::readCEN()
 
             if (o3tl::checked_add<sal_Int64>(aEntry.nOffset, nLocPos, 
aEntry.nOffset))
                 throw ZipException("Integer-overflow");
-            nMinOffset = std::min(nMinOffset, aEntry.nOffset);
             if (o3tl::checked_multiply<sal_Int64>(aEntry.nOffset, -1, 
aEntry.nOffset))
                 throw ZipException("Integer-overflow");
 
@@ -997,11 +1134,76 @@ sal_Int32 ZipFile::readCEN()
 
             if (aEntry.nExtraLen>0)
             {
-                readExtraFields(aMemGrabber, aEntry.nExtraLen, /*nSize, 
nCompressedSize, &nOffset,*/ &aEntry.sPath);
+                //::std::optional<sal_uInt64> oOffset64;
+                bool const isZip64 = readExtraFields(aMemGrabber, 
aEntry.nExtraLen, nSize, nCompressedSize, /*oOffset64,*/ &aEntry.sPath);
+#if 0
+                if (oOffset64)
+                {
+                    nOffset = *oOffset64;
+                }
+#endif
+                if (isZip64)
+                {
+                    SAL_INFO("package", "Zip64 not supported: \"" << 
aEntry.sPath << "\"");
+                    throw ZipException("Zip64 not supported");
+                }
             }
 
             aMemGrabber.skipBytes(nCommentLen);
 
+            // unfortunately readLOC is required now to check the consistency
+            assert(aEntry.nOffset <= 0);
+            sal_uInt64 const nStart{ o3tl::make_unsigned(-aEntry.nOffset) };
+            sal_uInt64 const nEnd = readLOC(aEntry);
+            assert(nStart < nEnd);
+            for (auto it = unallocated.begin(); ; ++it)
+            {
+                if (it == unallocated.end())
+                {
+                    throw ZipException("overlapping entries");
+                }
+                if (nStart < it->first)
+                {
+                    throw ZipException("overlapping entries");
+                }
+                else if (it->first == nStart)
+                {
+                    if (it->second == nEnd)
+                    {
+                        unallocated.erase(it);
+                        break;
+                    }
+                    else if (nEnd < it->second)
+                    {
+                        it->first = nEnd;
+                        break;
+                    }
+                    else
+                    {
+                        throw ZipException("overlapping entries");
+                    }
+                }
+                else if (nStart < it->second)
+                {
+                    if (nEnd < it->second)
+                    {
+                        auto const temp{it->first};
+                        it->first = nEnd;
+                        unallocated.insert(it, { temp, nStart });
+                        break;
+                    }
+                    else if (nEnd == it->second)
+                    {
+                        it->second = nStart;
+                        break;
+                    }
+                    else
+                    {
+                        throw ZipException("overlapping entries");
+                    }
+                }
+            }
+
             if (aEntries.find(aEntry.sPath) != aEntries.end())
             {
                 SAL_INFO("package", "Duplicate CEN entry: \"" << aEntry.sPath 
<< "\"");
@@ -1019,9 +1221,9 @@ sal_Int32 ZipFile::readCEN()
 
         if (nCount != nTotal)
             throw ZipException("Count != Total" );
-        if (nMinOffset != 0)
+        if (!unallocated.empty())
         {
-            throw ZipException("Extra bytes at beginning of zip file");
+            throw ZipException("Zip file has holes! It will leak!");
         }
     }
     catch ( IllegalArgumentException & )
@@ -1032,37 +1234,48 @@ sal_Int32 ZipFile::readCEN()
     return nCenPos;
 }
 
-void ZipFile::readExtraFields(MemoryByteGrabber& aMemGrabber, sal_Int16 
nExtraLen,
-        /*sal_uInt64& nSize, sal_uInt64& nCompressedSize,
-        sal_uInt64* nOffset, */OUString const*const pCENFilenameToCheck)
+bool ZipFile::readExtraFields(MemoryByteGrabber& aMemGrabber, sal_Int16 
nExtraLen,
+        sal_uInt64/*&*/ nLocSize, sal_uInt64/*&*/ nLocCompressedSize,
+//        std::optional<sal_uInt64> & roOffset,
+        OUString const*const pCENFilenameToCheck)
 {
+    bool isZip64{false};
     while (nExtraLen > 0) // Extensible data fields
     {
         sal_Int16 nheaderID = aMemGrabber.ReadInt16();
         sal_uInt16 dataSize = aMemGrabber.ReadUInt16();
-#if 0
         if (nheaderID == 1) // Load Zip64 Extended Information Extra Field
         {
             // Datasize should be 28byte but some files have less (maybe non 
standard?)
-            nSize = aMemGrabber.ReadUInt64();
+            auto const nSize = aMemGrabber.ReadUInt64();
+            if (nSize != 0 && nSize != nLocSize)
+            {   // this may look weird but then there is tdf128550.pptx 
produced reportedly by an Apple product
+                isZip64 = true;
+            }
             sal_uInt16 nReadSize = 8;
             if (dataSize >= 16)
             {
-                nCompressedSize = aMemGrabber.ReadUInt64();
+                auto const nCompressedSize = aMemGrabber.ReadUInt64();
+                if (nCompressedSize != 0 && nCompressedSize != 
nLocCompressedSize)
+                {
+                    isZip64 = true;
+                }
                 nReadSize = 16;
-                if (dataSize >= 24 && nOffset)
+                if (dataSize >= 24 /*&& roOffset*/)
                 {
-                    *nOffset = aMemGrabber.ReadUInt64();
+                    isZip64 = true;
+#if 0
+                    roOffset.emplace(aMemGrabber.ReadUInt64());
                     nReadSize = 24;
                     // 4 byte should be "Disk Start Number" but we not need it
+#endif
                 }
             }
             if (dataSize > nReadSize)
                 aMemGrabber.skipBytes(dataSize - nReadSize);
         }
-#endif
         // Info-ZIP Unicode Path Extra Field - pointless as we expect UTF-8 in 
CEN already
-        if (nheaderID == 0x7075 && pCENFilenameToCheck) // ignore in recovery 
mode
+        else if (nheaderID == 0x7075 && pCENFilenameToCheck) // ignore in 
recovery mode
         {
             if (aMemGrabber.remainingSize() < dataSize)
             {
@@ -1096,6 +1309,7 @@ void ZipFile::readExtraFields(MemoryByteGrabber& 
aMemGrabber, sal_Int16 nExtraLe
         }
         nExtraLen -= dataSize + 4;
     }
+    return isZip64;
 }
 
 void ZipFile::recover()
diff --git a/sc/qa/unit/filters-test.cxx b/sc/qa/unit/filters-test.cxx
index 44dc5ace5ad7..c811d0261354 100644
--- a/sc/qa/unit/filters-test.cxx
+++ b/sc/qa/unit/filters-test.cxx
@@ -32,6 +32,12 @@
 #include <svx/svdocapt.hxx>
 #include <svx/svdpage.hxx>
 #include <tools/stream.hxx>
+#if 0
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#endif
 
 using namespace ::com::sun::star;
 using namespace ::com::sun::star::uno;
@@ -874,8 +880,23 @@ void ScFiltersTest::testSortWithFormattingXLS()
 // just needs to not crash on recalc
 void ScFiltersTest::testForcepoint107()
 {
-    ScDocShellRef xDocSh = loadDoc(u"forcepoint107.", FORMAT_XLSX, true);
-    xDocSh->DoHardRecalc();
+    // It expectedly fails to load normally
+    CPPUNIT_ASSERT_ASSERTION_FAIL(loadDoc(u"forcepoint107.", FORMAT_XLSX, 
true));
+
+    // type detection fails on this branch due to the broken zip, can't test
+#if 0
+    // importing it must succeed with RepairPackage set to true.
+    uno::Sequence<beans::PropertyValue> aParams
+        = { comphelper::makePropertyValue("RepairPackage", true) };
+    OUString url;
+    createFileURL(u"forcepoint107.", u"xlsx", url);
+
+    css::uno::Reference<css::frame::XDesktop2> 
xDesktop(css::frame::Desktop::create(comphelper::getProcessComponentContext()));
+    m_xCalcComponent = xDesktop->loadComponentFromURL(url, "_default", 0, 
aParams);
+
+    ScDocShell* pDocSh = getScDocShell();
+    pDocSh->DoHardRecalc();
+#endif
 }
 
 ScFiltersTest::ScFiltersTest()
diff --git a/sd/qa/unit/data/pptx/pass/ofz35597-1.pptx 
b/sd/qa/unit/data/pptx/fail/ofz35597-1.pptx
similarity index 100%
rename from sd/qa/unit/data/pptx/pass/ofz35597-1.pptx
rename to sd/qa/unit/data/pptx/fail/ofz35597-1.pptx
diff --git a/sd/qa/unit/data/pptx/pass/ofz46160-1.pptx 
b/sd/qa/unit/data/pptx/fail/ofz46160-1.pptx
similarity index 100%
rename from sd/qa/unit/data/pptx/pass/ofz46160-1.pptx
rename to sd/qa/unit/data/pptx/fail/ofz46160-1.pptx
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx 
b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 0d67999b25f7..69c02c7218a5 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -1783,8 +1783,9 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf113143)
 CPPUNIT_TEST_FIXTURE(PdfExportTest, testForcePoint71)
 {
     // I just care it doesn't crash
-    aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
-    saveAsPDF(u"forcepoint71.key");
+    // numerous Zip errors are detected now and libetonyek cannot RepairPackage
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
u"forcepoint71.key";
+    CPPUNIT_ASSERT_ASSERTION_FAIL(loadFromDesktop(aURL));
 }
 
 CPPUNIT_TEST_FIXTURE(PdfExportTest, testForcePoint80)
commit c0ac29e1b68a92f220e1c1d3d018bfe2c825ad27
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Jul 17 12:04:13 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:34 2024 +0200

    package: don't check case insensitive duplicates for ZIP package
    
    Turns out there's a TexMaths extension that contains files with names
    differing only in case.
    
    
https://ask.libreoffice.org/t/zipexception-when-installing-an-extension/108256
    
    There isn't a separate ZipPackage mode for OXT so just don't check in
    the ZIP mode.
    
    Change-Id: I7680c93f5f24ac566a59b131b36d855bd85100b9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170616
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 0fb25ce9ff9a3ede8d43ee1502c44b4c02135b3f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170623
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit bf9ece7cf6d184675fac1eba88ebcb04bf81442f)

diff --git a/package/inc/ZipFile.hxx b/package/inc/ZipFile.hxx
index 9490a6c592de..0d96abe3d067 100644
--- a/package/inc/ZipFile.hxx
+++ b/package/inc/ZipFile.hxx
@@ -52,9 +52,14 @@ class ZipEnumeration;
 
 class ZipFile
 {
+public:
+    enum class Checks { Default, CheckInsensitive };
+
+private:
     rtl::Reference<comphelper::RefCountedMutex> m_aMutexHolder;
 
     std::unordered_set<OUString> m_EntriesInsensitive;
+    Checks m_Checks;
 
     EntryHash       aEntries;
     ByteGrabber     aGrabber;
@@ -93,16 +98,12 @@ class ZipFile
 
 public:
 
-    ZipFile( const rtl::Reference<comphelper::RefCountedMutex>& aMutexHolder,
-             css::uno::Reference < css::io::XInputStream > const &xInput,
-             const css::uno::Reference < css::uno::XComponentContext > 
&rxContext,
-             bool bInitialise );
-
     ZipFile( const rtl::Reference<comphelper::RefCountedMutex>& aMutexHolder,
              css::uno::Reference < css::io::XInputStream > const &xInput,
              const css::uno::Reference < css::uno::XComponentContext > 
&rxContext,
              bool bInitialise,
-             bool bForceRecover );
+             bool bForceRecover,
+             Checks checks);
 
     ~ZipFile();
 
diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index d5d35087ed95..d79ce545aaf3 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -79,27 +79,10 @@ using ZipUtils::Inflater;
 ZipFile::ZipFile( const rtl::Reference<comphelper::RefCountedMutex>& 
aMutexHolder,
                   uno::Reference < XInputStream > const &xInput,
                   const uno::Reference < XComponentContext > & rxContext,
-                  bool bInitialise )
-: m_aMutexHolder( aMutexHolder )
-, aGrabber( xInput )
-, aInflater( true )
-, xStream(xInput)
-, m_xContext ( rxContext )
-, bRecoveryMode( false )
-{
-    if (bInitialise && readCEN() == -1 )
-    {
-        aEntries.clear();
-        m_EntriesInsensitive.clear();
-        throw ZipException( "stream data looks to be broken" );
-    }
-}
-
-ZipFile::ZipFile( const rtl::Reference< comphelper::RefCountedMutex >& 
aMutexHolder,
-                  uno::Reference < XInputStream > const &xInput,
-                  const uno::Reference < XComponentContext > & rxContext,
-                  bool bInitialise, bool bForceRecovery)
+                  bool bInitialise, bool bForceRecovery,
+                  Checks const checks)
 : m_aMutexHolder( aMutexHolder )
+, m_Checks(checks)
 , aGrabber( xInput )
 , aInflater( true )
 , xStream(xInput)
@@ -1026,7 +1009,7 @@ sal_Int32 ZipFile::readCEN()
             }
             // this is required for OOXML, but not for ODF
             auto const lowerPath(aEntry.sPath.toAsciiLowerCase());
-            if (!m_EntriesInsensitive.insert(lowerPath).second)
+            if (!m_EntriesInsensitive.insert(lowerPath).second && m_Checks == 
Checks::CheckInsensitive)
             {
                 SAL_INFO("package", "Duplicate CEN entry (case insensitive): 
\"" << aEntry.sPath << "\"");
                 throw ZipException("Duplicate CEN entry (case insensitive)");
diff --git a/package/source/zippackage/ZipPackage.cxx 
b/package/source/zippackage/ZipPackage.cxx
index 3d6a75ad55d5..48ecb3aa4209 100644
--- a/package/source/zippackage/ZipPackage.cxx
+++ b/package/source/zippackage/ZipPackage.cxx
@@ -762,7 +762,9 @@ void SAL_CALL ZipPackage::initialize( const uno::Sequence< 
Any >& aArguments )
     OUString message;
     try
     {
-        m_pZipFile.emplace(m_aMutexHolder, m_xContentStream, m_xContext, true, 
m_bForceRecovery);
+        m_pZipFile.emplace(m_aMutexHolder, m_xContentStream, m_xContext, true,
+            m_bForceRecovery,
+            m_nFormat == embed::StorageFormats::ZIP ? ZipFile::Checks::Default 
: ZipFile::Checks::CheckInsensitive);
         getZipFileContents();
     }
     catch ( IOException & e )
@@ -1135,7 +1137,9 @@ void ZipPackage::ConnectTo( const uno::Reference< 
io::XInputStream >& xInStream
     if ( m_pZipFile )
         m_pZipFile->setInputStream( m_xContentStream );
     else
-        m_pZipFile.emplace(m_aMutexHolder, m_xContentStream, m_xContext, 
false);
+        m_pZipFile.emplace(m_aMutexHolder, m_xContentStream, m_xContext, false,
+            false,
+            m_nFormat == embed::StorageFormats::ZIP ? ZipFile::Checks::Default 
: ZipFile::Checks::CheckInsensitive);
 }
 
 namespace
diff --git a/package/source/zippackage/zipfileaccess.cxx 
b/package/source/zippackage/zipfileaccess.cxx
index d9b17fd80b49..1e185a21b280 100644
--- a/package/source/zippackage/zipfileaccess.cxx
+++ b/package/source/zippackage/zipfileaccess.cxx
@@ -244,7 +244,7 @@ void SAL_CALL OZipFileAccess::initialize( const 
uno::Sequence< uno::Any >& aArgu
                 m_aMutexHolder,
                 m_xContentStream,
                 m_xContext,
-                true );
+                true, false, ZipFile::Checks::Default);
 }
 
 // XNameAccess
commit 8dc00d5db2389fc405f7ae6620b6209fe0c34207
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Jul 9 17:22:15 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:34 2024 +0200

    package: ZipFile: don't accept duplicate entries (case insensitive)
    
    This is required for OOXML, but not for ODF.
    
    Unclear if there are use cases for this with ODF, can add some
    conditions if it turns out to be a problem.
    
    Change-Id: I3810da5c2273574135d133b4a9bbad98dc97af44
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170223
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 4833f131243bdb409ddfaff8b4db87d4ed2af98f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170282
    Reviewed-by: Christian Lohmaier <lohmaier+libreoff...@googlemail.com>
    (cherry picked from commit 92564a17fe68066f6e9135c6f79fb6319b192f22)

diff --git a/package/inc/ZipFile.hxx b/package/inc/ZipFile.hxx
index d141df934d8c..9490a6c592de 100644
--- a/package/inc/ZipFile.hxx
+++ b/package/inc/ZipFile.hxx
@@ -29,6 +29,8 @@
 #include "HashMaps.hxx"
 #include "EncryptionData.hxx"
 
+#include <unordered_set>
+
 class MemoryByteGrabber;
 namespace com::sun::star {
     namespace uno { class XComponentContext; }
@@ -52,6 +54,8 @@ class ZipFile
 {
     rtl::Reference<comphelper::RefCountedMutex> m_aMutexHolder;
 
+    std::unordered_set<OUString> m_EntriesInsensitive;
+
     EntryHash       aEntries;
     ByteGrabber     aGrabber;
     ZipUtils::Inflater aInflater;
diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index 8ecd6d5109d5..d5d35087ed95 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -90,6 +90,7 @@ ZipFile::ZipFile( const 
rtl::Reference<comphelper::RefCountedMutex>& aMutexHolde
     if (bInitialise && readCEN() == -1 )
     {
         aEntries.clear();
+        m_EntriesInsensitive.clear();
         throw ZipException( "stream data looks to be broken" );
     }
 }
@@ -114,6 +115,7 @@ ZipFile::ZipFile( const rtl::Reference< 
comphelper::RefCountedMutex >& aMutexHol
         else if ( readCEN() == -1 )
         {
             aEntries.clear();
+            m_EntriesInsensitive.clear();
             throw ZipException("stream data looks to be broken" );
         }
     }
@@ -1017,15 +1019,19 @@ sal_Int32 ZipFile::readCEN()
 
             aMemGrabber.skipBytes(nCommentLen);
 
-            if (auto it = aEntries.find(aEntry.sPath); it == aEntries.end())
-            {
-                aEntries[aEntry.sPath] = aEntry;
-            }
-            else
+            if (aEntries.find(aEntry.sPath) != aEntries.end())
             {
                 SAL_INFO("package", "Duplicate CEN entry: \"" << aEntry.sPath 
<< "\"");
                 throw ZipException("Duplicate CEN entry");
             }
+            // this is required for OOXML, but not for ODF
+            auto const lowerPath(aEntry.sPath.toAsciiLowerCase());
+            if (!m_EntriesInsensitive.insert(lowerPath).second)
+            {
+                SAL_INFO("package", "Duplicate CEN entry (case insensitive): 
\"" << aEntry.sPath << "\"");
+                throw ZipException("Duplicate CEN entry (case insensitive)");
+            }
+            aEntries[aEntry.sPath] = aEntry;
         }
 
         if (nCount != nTotal)
@@ -1200,6 +1206,13 @@ void ZipFile::recover()
                                     aEntry.nSize = 0;
                                 }
 
+                                auto const 
lowerPath(aEntry.sPath.toAsciiLowerCase());
+                                if (m_EntriesInsensitive.find(lowerPath) != 
m_EntriesInsensitive.end())
+                                {   // this is required for OOXML, but not for 
ODF
+                                    nPos += 4;
+                                    continue;
+                                }
+                                m_EntriesInsensitive.insert(lowerPath);
                                 aEntries.emplace( aEntry.sPath, aEntry );
                             }
                         }
commit 09ad54e955dbb291d805fafbd8ef90b315a35861
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Jul 5 13:55:31 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:34 2024 +0200

    package: avoid throwing RuntimeException in getZipFileContents()
    
    Translate it to ZipIOException.
    
    Change-Id: I7a07a59c0ba301b92f31696355c73ccbdf119ff8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170013
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit c409c83d777fdb6291c7cd03186b69fe4e7fd902)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170030
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit bcb6130ef8ab66a99347945c1c30ec0112d6940e)

diff --git a/package/source/zippackage/ZipPackage.cxx 
b/package/source/zippackage/ZipPackage.cxx
index 9270bb70502e..3d6a75ad55d5 100644
--- a/package/source/zippackage/ZipPackage.cxx
+++ b/package/source/zippackage/ZipPackage.cxx
@@ -544,7 +544,11 @@ void ZipPackage::getZipFileContents()
                 if ( !pCurrent->hasByName( sTemp ) )
                 {
                     rtl::Reference<ZipPackageFolder> pPkgFolder = new 
ZipPackageFolder(m_xContext, m_nFormat, m_bAllowRemoveOnInsert);
-                    pPkgFolder->setName( sTemp );
+                    try {
+                        pPkgFolder->setName( sTemp );
+                    } catch (uno::RuntimeException const& e) {
+                        throw css::packages::zip::ZipIOException(e.Message);
+                    }
                     pPkgFolder->doSetParent( pCurrent );
                     pCurrent = pPkgFolder.get();
                 }
commit bf1df9bed791580b88cb828a1e0a7ead1c59e625
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Jul 4 17:52:49 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:34 2024 +0200

    package: ZipFile: treat junk at the start of zip as invalid
    
    Probably the only legitimate use of such is self-extracting archives,
    irrelevant for LO.
    
    ofz56826-1.zip is an example; given what Info-Zip unzip prints about
    this file we don't want to successfully open it.
    
    Change-Id: I9568710227e4a152f9dc7bc356184394d7da8eba
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170002
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 2afdc61dd3138b383fb73dae2242ba1a9c8de901)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170009
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit fca236e6fd7f1b42d8ed23907913036d8140d651)

diff --git a/package/qa/cppunit/data/pass/ofz56826-1.zip 
b/package/qa/cppunit/data/fail/ofz56826-1.zip
similarity index 100%
rename from package/qa/cppunit/data/pass/ofz56826-1.zip
rename to package/qa/cppunit/data/fail/ofz56826-1.zip
diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index d353ecebce29..8ecd6d5109d5 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -940,6 +940,7 @@ sal_Int32 ZipFile::readCEN()
 
         ZipEntry aEntry;
         sal_Int16 nCommentLen;
+        sal_Int64 nMinOffset{nEndPos};
 
         aEntries.reserve(nTotal);
         for (nCount = 0 ; nCount < nTotal; nCount++)
@@ -983,6 +984,7 @@ sal_Int32 ZipFile::readCEN()
 
             if (o3tl::checked_add<sal_Int64>(aEntry.nOffset, nLocPos, 
aEntry.nOffset))
                 throw ZipException("Integer-overflow");
+            nMinOffset = std::min(nMinOffset, aEntry.nOffset);
             if (o3tl::checked_multiply<sal_Int64>(aEntry.nOffset, -1, 
aEntry.nOffset))
                 throw ZipException("Integer-overflow");
 
@@ -1028,6 +1030,10 @@ sal_Int32 ZipFile::readCEN()
 
         if (nCount != nTotal)
             throw ZipException("Count != Total" );
+        if (nMinOffset != 0)
+        {
+            throw ZipException("Extra bytes at beginning of zip file");
+        }
     }
     catch ( IllegalArgumentException & )
     {
commit ab6b1f274fc93d83bed393983b8d5f08d7bd7d77
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Jul 4 14:07:25 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:34 2024 +0200

    comphelper: treat zip file path segments '.' and '..' as invalid
    
    This will prevent also opening with RepairPackage, would need to adapt
    ZipPackage::getZipFileContents() a bit, but let's hope nobody acutally
    has such files.
    
    Also treat path that starts with "/" as invalid, presumably it's not
    allowed by APPNOTE.TXT:
    "The name of the file, with optional relative path."
    
    Change-Id: Ic694ea2fb34f5de1d490a9a251cf56e4004e9673
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169994
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    Tested-by: Jenkins
    (cherry picked from commit 6005260078c126bf3f1cf4d6f1ebb631453f5ac7)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169964
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit fda9ae6f1cef7512f0560828f67553b91641bd26)

diff --git a/comphelper/source/misc/storagehelper.cxx 
b/comphelper/source/misc/storagehelper.cxx
index 5f8527bcf273..ef310d9837ee 100644
--- a/comphelper/source/misc/storagehelper.cxx
+++ b/comphelper/source/misc/storagehelper.cxx
@@ -565,10 +565,17 @@ bool OStorageHelper::IsValidZipEntryFileName( 
std::u16string_view aName, bool bS
 bool OStorageHelper::IsValidZipEntryFileName(
     const sal_Unicode *pChar, sal_Int32 nLength, bool bSlashAllowed )
 {
+    long nDots{0};
     for ( sal_Int32 i = 0; i < nLength; i++ )
     {
         switch ( pChar[i] )
         {
+            case '.':
+                if (nDots != -1)
+                {
+                    ++nDots;
+                }
+                break;
             case '\':
             case '?':
             case '<':
@@ -578,15 +585,17 @@ bool OStorageHelper::IsValidZipEntryFileName(
             case ':':
                 return false;
             case '/':
-                if ( !bSlashAllowed )
+                if (!bSlashAllowed || nDots == 1 || nDots == 2 || i == 0)
                     return false;
+                nDots = 0;
                 break;
             default:
+                nDots = -1;
                 if ( pChar[i] < 32  || (pChar[i] >= 0xD800 && pChar[i] <= 
0xDFFF) )
                     return false;
         }
     }
-    return true;
+    return nDots != 1 && nDots != 2;
 }
 
 
commit 3dcf350cb1c4bc78170c2412e46a4f5acb53087d
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Jul 2 11:50:09 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:34 2024 +0200

    package: ZipFile: check Info-ZIP Unicode Path Extra Field
    
    Change-Id: I829eb449e8a0947341f066399be549f56b0f02da
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169882
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 67dca5a47d1be1b38edee7d0d81fa9adfce5a22e)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169929
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    (cherry picked from commit 1150584be851b311067ee6482f51da1ad3b12636)
    
    ofz#56826 Heap-use-after-free
    
    since:
    commit abda72eeac19b18c22f57d5443c3955a463605d7
    Date:   Mon Feb 20 00:32:22 2023 +0100
        tdf#82984 tdf#94915 zip64 support (import + export)
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148526
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit 59b0f676758dd752457c84fb4159f6446d74e8a4)
    Change-Id: I11d2247004e3fb20fe2e443f0d4aa755290aa667

diff --git a/package/inc/ZipFile.hxx b/package/inc/ZipFile.hxx
index 15b800430555..d141df934d8c 100644
--- a/package/inc/ZipFile.hxx
+++ b/package/inc/ZipFile.hxx
@@ -29,6 +29,7 @@
 #include "HashMaps.hxx"
 #include "EncryptionData.hxx"
 
+class MemoryByteGrabber;
 namespace com::sun::star {
     namespace uno { class XComponentContext; }
     namespace ucb  { class XProgressHandler; }
@@ -81,6 +82,10 @@ class ZipFile
     sal_Int32 readCEN();
     sal_Int32 findEND();
     void recover();
+    static void readExtraFields(MemoryByteGrabber& aMemGrabber, sal_Int16 
nExtraLen,
+                                /*sal_uInt64& nSize, sal_uInt64& 
nCompressedSize,
+                                sal_uInt64* nOffset,*/
+                                OUString const* pCENFilenameToCheck);
 
 public:
 
diff --git a/package/qa/cppunit/data/pass/ofz56826-1.zip 
b/package/qa/cppunit/data/pass/ofz56826-1.zip
new file mode 100644
index 000000000000..b9acfe34da14
Binary files /dev/null and b/package/qa/cppunit/data/pass/ofz56826-1.zip differ
diff --git a/package/source/zipapi/MemoryByteGrabber.hxx 
b/package/source/zipapi/MemoryByteGrabber.hxx
index 8dcf7f067064..650b5c6a6d02 100644
--- a/package/source/zipapi/MemoryByteGrabber.hxx
+++ b/package/source/zipapi/MemoryByteGrabber.hxx
@@ -49,6 +49,14 @@ public:
         mnCurrent += nBytesToSkip;
     }
 
+    sal_Int8 ReadUInt8()
+    {
+        if (mnCurrent + 1 > mnEnd)
+            return 0;
+        sal_uInt8 nInt8 = mpBuffer[mnCurrent++];
+        return nInt8;
+    }
+
     // XSeekable chained...
     sal_Int16 ReadInt16()
     {
@@ -58,6 +66,16 @@ public:
         nInt16 |= ( mpBuffer[mnCurrent++] & 0xFF ) << 8;
         return nInt16;
     }
+
+    sal_Int16 ReadUInt16()
+    {
+        if (mnCurrent + 2 > mnEnd )
+            return 0;
+        sal_uInt16 nInt16  =  mpBuffer[mnCurrent++] & 0xFF;
+        nInt16 |= ( mpBuffer[mnCurrent++] & 0xFF ) << 8;
+        return nInt16;
+    }
+
     sal_Int32 ReadInt32()
     {
         if (mnCurrent + 4 > mnEnd )
diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index 931e9acc33c7..d353ecebce29 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -36,6 +36,7 @@
 #include <comphelper/storagehelper.hxx>
 #include <comphelper/processfactory.hxx>
 #include <rtl/digest.h>
+#include <rtl/crc.h>
 #include <sal/log.hxx>
 #include <o3tl/safeint.hxx>
 #include <osl/diagnose.h>
@@ -1005,7 +1006,14 @@ sal_Int32 ZipFile::readCEN()
             if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( 
aEntry.sPath, true ) )
                 throw ZipException("Zip entry has an invalid name." );
 
-            aMemGrabber.skipBytes( aEntry.nPathLen + aEntry.nExtraLen + 
nCommentLen );
+            aMemGrabber.skipBytes(aEntry.nPathLen);
+
+            if (aEntry.nExtraLen>0)
+            {
+                readExtraFields(aMemGrabber, aEntry.nExtraLen, /*nSize, 
nCompressedSize, &nOffset,*/ &aEntry.sPath);
+            }
+
+            aMemGrabber.skipBytes(nCommentLen);
 
             if (auto it = aEntries.find(aEntry.sPath); it == aEntries.end())
             {
@@ -1029,6 +1037,72 @@ sal_Int32 ZipFile::readCEN()
     return nCenPos;
 }
 
+void ZipFile::readExtraFields(MemoryByteGrabber& aMemGrabber, sal_Int16 
nExtraLen,
+        /*sal_uInt64& nSize, sal_uInt64& nCompressedSize,
+        sal_uInt64* nOffset, */OUString const*const pCENFilenameToCheck)
+{
+    while (nExtraLen > 0) // Extensible data fields
+    {
+        sal_Int16 nheaderID = aMemGrabber.ReadInt16();
+        sal_uInt16 dataSize = aMemGrabber.ReadUInt16();
+#if 0
+        if (nheaderID == 1) // Load Zip64 Extended Information Extra Field
+        {
+            // Datasize should be 28byte but some files have less (maybe non 
standard?)
+            nSize = aMemGrabber.ReadUInt64();
+            sal_uInt16 nReadSize = 8;
+            if (dataSize >= 16)
+            {
+                nCompressedSize = aMemGrabber.ReadUInt64();
+                nReadSize = 16;
+                if (dataSize >= 24 && nOffset)
+                {
+                    *nOffset = aMemGrabber.ReadUInt64();
+                    nReadSize = 24;
+                    // 4 byte should be "Disk Start Number" but we not need it
+                }
+            }
+            if (dataSize > nReadSize)
+                aMemGrabber.skipBytes(dataSize - nReadSize);
+        }
+#endif
+        // Info-ZIP Unicode Path Extra Field - pointless as we expect UTF-8 in 
CEN already
+        if (nheaderID == 0x7075 && pCENFilenameToCheck) // ignore in recovery 
mode
+        {
+            if (aMemGrabber.remainingSize() < dataSize)
+            {
+                SAL_INFO("package", "Invalid Info-ZIP Unicode Path Extra 
Field: invalid TSize");
+                throw ZipException("Invalid Info-ZIP Unicode Path Extra 
Field");
+            }
+            auto const nVersion = aMemGrabber.ReadUInt8();
+            if (nVersion != 1)
+            {
+                SAL_INFO("package", "Invalid Info-ZIP Unicode Path Extra 
Field: unexpected Version");
+                throw ZipException("Invalid Info-ZIP Unicode Path Extra 
Field");
+            }
+            // this CRC32 is actually of the pCENFilenameToCheck
+            // so it's pointless to check it if we require the UnicodeName
+            // to be equal to the CEN name anyway (and pCENFilenameToCheck
+            // is already converted to UTF-16 here)
+            (void) aMemGrabber.ReadUInt32();
+            // this is required to be UTF-8
+            OUString const unicodePath(reinterpret_cast<char const 
*>(aMemGrabber.getCurrentPos()),
+                    dataSize - 5, RTL_TEXTENCODING_UTF8);
+            aMemGrabber.skipBytes(dataSize - 5);
+            if (unicodePath != *pCENFilenameToCheck)
+            {
+                SAL_INFO("package", "Invalid Info-ZIP Unicode Path Extra 
Field: unexpected UnicodeName");
+                throw ZipException("Invalid Info-ZIP Unicode Path Extra 
Field");
+            }
+        }
+        else
+        {
+            aMemGrabber.skipBytes(dataSize);
+        }
+        nExtraLen -= dataSize + 4;
+    }
+}
+
 void ZipFile::recover()
 {
     ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
commit 2848cc5b7429e9a7536af4be33fef71e58a756b3
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Jul 2 11:47:17 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:33 2024 +0200

    package: ZipFile: don't accept duplicate CEN entries
    
    Change-Id: Ice341a11346b445c555cba276bf2284e4f9b6685
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169881
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 67cb6af482bc5b0f4d310f0a42a85057f3db0267)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169945
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    (cherry picked from commit a4f85170623b40d33b914d95be109f6e8fe3c8fa)

diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index 18bd6f34d888..931e9acc33c7 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -1006,7 +1006,16 @@ sal_Int32 ZipFile::readCEN()
                 throw ZipException("Zip entry has an invalid name." );
 
             aMemGrabber.skipBytes( aEntry.nPathLen + aEntry.nExtraLen + 
nCommentLen );
-            aEntries[aEntry.sPath] = aEntry;
+
+            if (auto it = aEntries.find(aEntry.sPath); it == aEntries.end())
+            {
+                aEntries[aEntry.sPath] = aEntry;
+            }
+            else
+            {
+                SAL_INFO("package", "Duplicate CEN entry: \"" << aEntry.sPath 
<< "\"");
+                throw ZipException("Duplicate CEN entry");
+            }
         }
 
         if (nCount != nTotal)
commit 12941b0338df32c739b9fdb55c71210f3d1a779a
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Tue Jan 2 12:31:01 2024 +0000
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:33 2024 +0200

    ofz#65480: Integer-overflow
    
    Change-Id: Ie771e6e37237907698e4c39eb50cd940500b86ca
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161540
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    (cherry picked from commit 69181dd430543db21fc0e61b70033ef484708c1c)

diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index 410d9b892ac4..18bd6f34d888 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -980,8 +980,10 @@ sal_Int32 ZipFile::readCEN()
             aEntry.nSize = nSize;
             aEntry.nOffset = nOffset;
 
-            aEntry.nOffset += nLocPos;
-            aEntry.nOffset *= -1;
+            if (o3tl::checked_add<sal_Int64>(aEntry.nOffset, nLocPos, 
aEntry.nOffset))
+                throw ZipException("Integer-overflow");
+            if (o3tl::checked_multiply<sal_Int64>(aEntry.nOffset, -1, 
aEntry.nOffset))
+                throw ZipException("Integer-overflow");
 
             if ( aEntry.nPathLen < 0 )
                 throw ZipException("unexpected name length" );
commit 15338b93c2f26936b0133ce65177b36a75754e25
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Tue Apr 25 12:33:26 2023 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:33 2024 +0200

    tdf#155005 fail gracefully on encountering a negative compression value
    
    we are using sal_Int64 for this so a large enough value can be
    interpreted as negative here
    
    Change-Id: Id547a24591aca4b6ed7b7955621641a0666b0bd5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150968
    Tested-by: Caolán McNamara <caol...@redhat.com>
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit 80805716a409c34203b059f3e03cd934367186c3)

diff --git a/package/source/zipapi/ZipFile.cxx 
b/package/source/zipapi/ZipFile.cxx
index 79dc5bb68a8e..410d9b892ac4 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -1202,6 +1202,12 @@ bool ZipFile::checkSizeAndCRC( const ZipEntry& aEntry )
     if( aEntry.nMethod == STORED )
         return ( getCRC( aEntry.nOffset, aEntry.nSize ) == aEntry.nCrc );
 
+    if (aEntry.nCompressedSize < 0)
+    {
+        SAL_WARN("package", "bogus compressed size of: " << 
aEntry.nCompressedSize);
+        return false;
+    }
+
     getSizeAndCRC( aEntry.nOffset, aEntry.nCompressedSize, &nSize, &nCRC );
     return ( aEntry.nSize == nSize && aEntry.nCrc == nCRC );
 }
commit e6e35bedbc987866d9b8b6156daee493f46c737d
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Jul 4 12:10:29 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Aug 19 14:55:33 2024 +0200

    sfx2: fix signature infobar being shown for every repaired document
    
    (regression from commit 8b333575ee680664fa3d83249ccec90881754ad7)
    
    So it should only be set if the state is still UNKNOWN.  But
    SfxObjectShell::ImplGetSignatureState() is called before the repair
    dialog is shown, so make sure that the second import (with
    RepairPackage) finds both members as SignatureState::UNKOWN.
    
    Change-Id: Ic914016dde6425a4d95fba7f6f66411305553930
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169989
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 8d869b5fe47842df52965804db87db0941f4f2a0)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169997
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    (cherry picked from commit 127194ebbcbf644148fee81773babaf23eab78d8)

diff --git a/sfx2/source/doc/objmisc.cxx b/sfx2/source/doc/objmisc.cxx
index 86f587c20bec..17a6037520de 100644
--- a/sfx2/source/doc/objmisc.cxx
+++ b/sfx2/source/doc/objmisc.cxx
@@ -937,6 +937,12 @@ void SfxObjectShell::BreakMacroSign_Impl( bool 
bBreakMacroSign )
 
 void SfxObjectShell::CheckSecurityOnLoading_Impl()
 {
+    if (GetErrorCode() == ERRCODE_IO_BROKENPACKAGE)
+    {   // safety first: don't run any macros from broken package.
+        pImpl->aMacroMode.disallowMacroExecution();
+        return; // do not get signature status - needs to be done after 
RepairPackage
+    }
+
     // make sure LO evaluates the macro signatures, so it can be preserved
     GetScriptingSignatureState();
 
diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx
index 11f07479e70f..47647ae5b231 100644
--- a/sfx2/source/doc/objserv.cxx
+++ b/sfx2/source/doc/objserv.cxx
@@ -1757,19 +1757,22 @@ SignatureState SfxObjectShell::ImplGetSignatureState( 
bool bScriptingContent )
 {
     SignatureState* pState = bScriptingContent ? 
&pImpl->nScriptingSignatureState : &pImpl->nDocumentSignatureState;
 
-    // repaired package cannot be trusted
-    SfxBoolItem const*const 
pRepairItem{GetMedium()->GetItemSet()->GetItem(SID_REPAIRPACKAGE, false)};
-    if (pRepairItem && pRepairItem->GetValue())
-    {
-        *pState = SignatureState::BROKEN;
-    }
-
     if ( *pState == SignatureState::UNKNOWN )
     {
         *pState = SignatureState::NOSIGNATURES;
 
         uno::Sequence< security::DocumentSignatureInformation > aInfos = 
GetDocumentSignatureInformation( bScriptingContent );
         *pState = DocumentSignatures::getSignatureState(aInfos);
+
+        // repaired package cannot be trusted
+        if (*pState != SignatureState::NOSIGNATURES)
+        {
+            SfxBoolItem const*const 
pRepairItem{GetMedium()->GetItemSet()->GetItem(SID_REPAIRPACKAGE, false)};
+            if (pRepairItem && pRepairItem->GetValue())
+            {
+                *pState = SignatureState::BROKEN;
+            }
+        }
     }
 
     if ( *pState == SignatureState::OK || *pState == 
SignatureState::NOTVALIDATED
diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx
index 288b6a7ae6a9..5dcc38e42a0d 100644
--- a/sfx2/source/doc/objstor.cxx
+++ b/sfx2/source/doc/objstor.cxx
@@ -378,6 +378,8 @@ void SfxObjectShell::PrepareSecondTryLoad_Impl()
 {
     // only for internal use
     pImpl->m_xDocStorage.clear();
+    pImpl->nDocumentSignatureState = SignatureState::UNKNOWN;
+    pImpl->nScriptingSignatureState = SignatureState::UNKNOWN;
     pImpl->m_bIsInit = false;
     ResetError();
 }
commit ab3f0d7118e4fc086763365e3aa0596418cd83e5
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Tue Jul 2 13:24:38 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Thu Aug 15 18:38:55 2024 +0200

    sfx2: SfxObjectShell should not trust any signature on repaired package
    
    Change-Id: I0317f80989e9dabd23e88e3caab26ede3fb5bd56
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169883
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 8b333575ee680664fa3d83249ccec90881754ad7)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169930
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    (cherry picked from commit 05b9e388448b1c8c10b18c22898c4725dd176fed)

diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx
index 3a6a0ceea2a8..11f07479e70f 100644
--- a/sfx2/source/doc/objserv.cxx
+++ b/sfx2/source/doc/objserv.cxx
@@ -1757,6 +1757,13 @@ SignatureState SfxObjectShell::ImplGetSignatureState( 
bool bScriptingContent )
 {
     SignatureState* pState = bScriptingContent ? 
&pImpl->nScriptingSignatureState : &pImpl->nDocumentSignatureState;
 
+    // repaired package cannot be trusted
+    SfxBoolItem const*const 
pRepairItem{GetMedium()->GetItemSet()->GetItem(SID_REPAIRPACKAGE, false)};
+    if (pRepairItem && pRepairItem->GetValue())
+    {
+        *pState = SignatureState::BROKEN;
+    }
+
     if ( *pState == SignatureState::UNKNOWN )
     {
         *pState = SignatureState::NOSIGNATURES;

Reply via email to