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)
