vcl/inc/font/TTFReader.hxx       |   95 +++++++++++++++++++++++++++++----------
 vcl/source/font/EOTConverter.cxx |    2 
 2 files changed, 75 insertions(+), 22 deletions(-)

New commits:
commit 80c67cce37d03fcb0eed57f01318106bc2d8db87
Author:     Caolán McNamara <[email protected]>
AuthorDate: Tue May 27 11:20:34 2025 +0100
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Wed Jun 4 09:54:58 2025 +0200

    sanity check on TableDirectory length
    
    sanity check and clip number of records possible
    
    Change-Id: I5c6ded1087302aa9fe4bbe1ee252964a266f6957
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185896
    Reviewed-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins
    (cherry picked from commit 65fdd33cc49a667d3e212163fde99e3ce7433ab5)
    
    sanity check table offsets and claimed lengths
    
    Change-Id: I9c9f3b5f3efcecbe12f6a8ad08455e1f18e6a642
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185900
    Tested-by: Caolán McNamara <[email protected]>
    Reviewed-by: Caolán McNamara <[email protected]>
    (cherry picked from commit e6f2f0744e1595cbe7bb03933f71e7dbb5e06174)
    
    sanity check NameTable
    
    Change-Id: I8eba80747511ac3114676be486337183315890e1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185903
    Reviewed-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins
    (cherry picked from commit cae28bbd3c9504f25a2910c5c75498d17fd618df)
    
    sanity check NameRecords
    
    may also fix cid#1646781 Untrusted loop bound
    
    Change-Id: I3ddb44de3ba45a3654400014bf19a4b202a68325
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185909
    Reviewed-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins
    (cherry picked from commit 0b62b122cfed6b864f9dd613bd238474ad99dafe)
    
    Change-Id: Ibaa2fa09114db3dde97eaa93085718711eb676eb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185893
    Reviewed-by: Tomaž Vajngerl <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/vcl/inc/font/TTFReader.hxx b/vcl/inc/font/TTFReader.hxx
index eb8d2be34de8..29482d4024a8 100644
--- a/vcl/inc/font/TTFReader.hxx
+++ b/vcl/inc/font/TTFReader.hxx
@@ -12,6 +12,7 @@
 #include <font/TTFStructure.hxx>
 #include <vcl/font/FontDataContainer.hxx>
 #include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
 
 namespace font
 {
@@ -24,9 +25,21 @@ private:
     const TableDirectoryEntry* mpTableDirectoryEntry;
     const char* mpNameTablePointer;
     const NameTable* mpNameTable;
+    sal_uInt16 mnNumberOfRecords;
 
-    const char* getTablePointer(const TableDirectoryEntry* pEntry)
+    const char* getTablePointer(const TableDirectoryEntry* pEntry, size_t 
nEntrySize)
     {
+        size_t nSize = mrFontDataContainer.size();
+        if (pEntry->offset > nSize)
+        {
+            SAL_WARN("vcl.fonts", "Table offset beyond end of available data");
+            return nullptr;
+        }
+        if (nEntrySize > nSize - pEntry->offset)
+        {
+            SAL_WARN("vcl.fonts", "Insufficient available data for table 
entry");
+            return nullptr;
+        }
         return mrFontDataContainer.getPointer() + pEntry->offset;
     }
 
@@ -35,9 +48,27 @@ public:
                      const TableDirectoryEntry* pTableDirectoryEntry)
         : mrFontDataContainer(rFontDataContainer)
         , mpTableDirectoryEntry(pTableDirectoryEntry)
-        , mpNameTablePointer(getTablePointer(mpTableDirectoryEntry))
+        , mpNameTablePointer(getTablePointer(mpTableDirectoryEntry, 
sizeof(NameTable)))
         , mpNameTable(reinterpret_cast<const NameTable*>(mpNameTablePointer))
+        , mnNumberOfRecords(0)
     {
+        if (mpNameTable)
+        {
+            mnNumberOfRecords = mpNameTable->nCount;
+
+            const char* pEnd = mrFontDataContainer.getPointer() + 
mrFontDataContainer.size();
+            const char* pStart = mpNameTablePointer + sizeof(NameTable);
+            size_t nAvailableData = pEnd - pStart;
+            size_t nMaxRecordsPossible = nAvailableData / sizeof(NameRecord);
+            if (mnNumberOfRecords > nMaxRecordsPossible)
+            {
+                SAL_WARN("vcl.fonts", "Font claimed to have "
+                                          << mnNumberOfRecords
+                                          << " name records, but only space 
for "
+                                          << nMaxRecordsPossible);
+                mnNumberOfRecords = nMaxRecordsPossible;
+            }
+        }
     }
 
     sal_uInt32 getTableOffset() { return mpTableDirectoryEntry->offset; }
@@ -45,7 +76,7 @@ public:
     const NameTable* getNameTable() { return mpNameTable; }
 
     /** Number of tables */
-    sal_uInt16 getNumberOfRecords() { return mpNameTable->nCount; }
+    sal_uInt16 getNumberOfRecords() { return mnNumberOfRecords; }
 
     /** Get a name table record for index */
     const NameRecord* getNameRecord(sal_uInt32 index)
@@ -92,18 +123,42 @@ private:
     const char* mpFirstPosition;
     sal_uInt16 mnNumberOfTables;
 
-    const char* getTablePointer(const TableDirectoryEntry* pEntry)
+    const char* getTablePointer(const TableDirectoryEntry* pEntry, size_t 
nEntrySize)
     {
+        size_t nSize = mrFontDataContainer.size();
+        if (pEntry->offset > nSize)
+        {
+            SAL_WARN("vcl.fonts", "Table offset beyond end of available data");
+            return nullptr;
+        }
+        if (nEntrySize > nSize - pEntry->offset)
+        {
+            SAL_WARN("vcl.fonts", "Insufficient available data for table 
entry");
+            return nullptr;
+        }
         return mrFontDataContainer.getPointer() + pEntry->offset;
     }
 
 public:
-    TableEntriesHandler(FontDataContainer const& rFontDataContainer, const 
char* pPosition,
-                        sal_uInt16 nNumberOfTables)
+    TableEntriesHandler(FontDataContainer const& rFontDataContainer)
         : mrFontDataContainer(rFontDataContainer)
-        , mpFirstPosition(pPosition)
-        , mnNumberOfTables(nNumberOfTables)
     {
+        const char* pData = mrFontDataContainer.getPointer();
+        assert(mrFontDataContainer.size() >= sizeof(TableDirectory));
+        mpFirstPosition = pData + sizeof(TableDirectory);
+
+        const TableDirectory* pDirectory = reinterpret_cast<const 
TableDirectory*>(pData);
+        mnNumberOfTables = pDirectory->nNumberOfTables;
+
+        size_t nAvailableData = mrFontDataContainer.size() - 
sizeof(TableDirectory);
+        size_t nMaxRecordsPossible = nAvailableData / 
sizeof(TableDirectoryEntry);
+        if (mnNumberOfTables > nMaxRecordsPossible)
+        {
+            SAL_WARN("vcl.fonts", "Font claimed to have " << mnNumberOfTables
+                                                          << " table records, 
but only space for "
+                                                          << 
nMaxRecordsPossible);
+            mnNumberOfTables = nMaxRecordsPossible;
+        }
     }
 
     const TableDirectoryEntry* getEntry(sal_uInt32 nTag)
@@ -124,7 +179,7 @@ public:
         const auto* pEntry = getEntry(T_OS2);
         if (!pEntry)
             return nullptr;
-        return reinterpret_cast<const OS2Table*>(getTablePointer(pEntry));
+        return reinterpret_cast<const OS2Table*>(getTablePointer(pEntry, 
sizeof(OS2Table)));
     }
 
     const HeadTable* getHeadTable()
@@ -132,7 +187,7 @@ public:
         const auto* pEntry = getEntry(T_head);
         if (!pEntry)
             return nullptr;
-        return reinterpret_cast<const HeadTable*>(getTablePointer(pEntry));
+        return reinterpret_cast<const HeadTable*>(getTablePointer(pEntry, 
sizeof(HeadTable)));
     }
 
     const NameTable* getNameTable()
@@ -140,7 +195,7 @@ public:
         const auto* pEntry = getEntry(T_name);
         if (!pEntry)
             return nullptr;
-        return reinterpret_cast<const NameTable*>(getTablePointer(pEntry));
+        return reinterpret_cast<const NameTable*>(getTablePointer(pEntry, 
sizeof(NameTable)));
     }
 
     std::unique_ptr<NameTableHandler> getNameTableHandler()
@@ -170,19 +225,15 @@ public:
     {
     }
 
-    const TableDirectory* getTableDirector()
-    {
-        return reinterpret_cast<const 
TableDirectory*>(mrFontDataContainer.getPointer());
-    }
-
     std::unique_ptr<TableEntriesHandler> getTableEntriesHandler()
     {
-        auto* pDirectory = getTableDirector();
-        const char* pPosition = mrFontDataContainer.getPointer() + 
sizeof(TableDirectory);
-
-        std::unique_ptr<TableEntriesHandler> pHandler(
-            new TableEntriesHandler(mrFontDataContainer, pPosition, 
pDirectory->nNumberOfTables));
-        return pHandler;
+        size_t nSize = mrFontDataContainer.size();
+        if (nSize < sizeof(TableDirectory))
+        {
+            SAL_WARN("vcl.fonts", "Font Data shorter than a TableDirectory");
+            return nullptr;
+        }
+        return std::make_unique<TableEntriesHandler>(mrFontDataContainer);
     }
 
     /** Gets the string from a name table */
diff --git a/vcl/source/font/EOTConverter.cxx b/vcl/source/font/EOTConverter.cxx
index d8b044dfc413..89b1199e2a40 100644
--- a/vcl/source/font/EOTConverter.cxx
+++ b/vcl/source/font/EOTConverter.cxx
@@ -79,6 +79,8 @@ bool EOTConverter::convert(std::vector<sal_uInt8>& rEotOutput)
     pEot->nReserved4 = 0;
 
     auto pHanlder = aFont.getTableEntriesHandler();
+    if (!pHanlder)
+        return false;
 
     const font::OS2Table* pOS2 = pHanlder->getOS2Table();
     if (pOS2)

Reply via email to