From 909b0de5d16f2af3b3d6a3ca4c7e53b84836ad37 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 15 May 2014 13:32:27 +0200 Subject: [PATCH] Windows: Fix another crash when creating QRawFont from invalid data The sanity check added in d16508a285a5423ae9a5034e969801bce74ffb98 didn't actually catch the case where the invalid data is large enough to contain the offset table and table directory. Added sanity checks to all the code that accesses the font data now, so this should fix crashes with partial data as well as invalid data. Task-number: QTBUG-37190 Change-Id: Ie43f10d8cf0b09007783b9b1c4d91bfed8c6b0f0 Reviewed-by: Konstantin Ritt --- .../windows/qwindowsfontdatabase.cpp | 36 ++++++++++++++----- tests/auto/gui/text/qrawfont/tst_qrawfont.cpp | 5 +++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 6d9f01da4e..696dc06cee 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -164,15 +164,18 @@ namespace { { Q_ASSERT(tagName.size() == 4); quint32 tagId = *(reinterpret_cast(tagName.constData())); - - if (m_fontData.size() < sizeof(OffsetSubTable) + sizeof(TableDirectory)) + if (Q_UNLIKELY(m_fontData.size() < sizeof(OffsetSubTable))) return 0; OffsetSubTable *offsetSubTable = reinterpret_cast(m_fontData.data()); TableDirectory *tableDirectory = reinterpret_cast(offsetSubTable + 1); + quint16 tableCount = qFromBigEndian(offsetSubTable->numTables); + if (Q_UNLIKELY(quint32(m_fontData.size()) < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount)) + return 0; + TableDirectory *nameTableDirectoryEntry = 0; - for (int i = 0; i < qFromBigEndian(offsetSubTable->numTables); ++i, ++tableDirectory) { + for (int i = 0; i < tableCount; ++i, ++tableDirectory) { if (tableDirectory->identifier == tagId) { nameTableDirectoryEntry = tableDirectory; break; @@ -190,19 +193,34 @@ namespace { nameTableDirectoryEntry = tableDirectoryEntry("name"); if (nameTableDirectoryEntry != 0) { - NameTable *nameTable = reinterpret_cast( - m_fontData.data() + qFromBigEndian(nameTableDirectoryEntry->offset)); + quint32 offset = qFromBigEndian(nameTableDirectoryEntry->offset); + if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameTable))) + return QString(); + + NameTable *nameTable = reinterpret_cast(m_fontData.data() + offset); NameRecord *nameRecord = reinterpret_cast(nameTable + 1); - for (int i = 0; i < qFromBigEndian(nameTable->count); ++i, ++nameRecord) { + + quint16 nameTableCount = qFromBigEndian(nameTable->count); + if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameRecord) * nameTableCount)) + return QString(); + + for (int i = 0; i < nameTableCount; ++i, ++nameRecord) { if (qFromBigEndian(nameRecord->nameID) == 1 && qFromBigEndian(nameRecord->platformID) == 3 // Windows && qFromBigEndian(nameRecord->languageID) == 0x0409) { // US English + quint16 stringOffset = qFromBigEndian(nameTable->stringOffset); + quint16 nameOffset = qFromBigEndian(nameRecord->offset); + quint16 nameLength = qFromBigEndian(nameRecord->length); + + if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength)) + return QString(); + const void *ptr = reinterpret_cast(nameTable) - + qFromBigEndian(nameTable->stringOffset) - + qFromBigEndian(nameRecord->offset); + + stringOffset + + nameOffset; const quint16 *s = reinterpret_cast(ptr); - const quint16 *e = s + qFromBigEndian(nameRecord->length) / sizeof(quint16); + const quint16 *e = s + nameLength / sizeof(quint16); while (s != e) name += QChar( qFromBigEndian(*s++)); break; diff --git a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp index 20bfaf99dd..a39277b093 100644 --- a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp +++ b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp @@ -948,6 +948,11 @@ void tst_QRawFont::rawFontFromInvalidData() font.loadFromData(invalidData, 10, QFont::PreferDefaultHinting); QVERIFY(!font.isValid()); + + invalidData.fill(255, 1024); + font.loadFromData(invalidData, 10, QFont::PreferDefaultHinting); + + QVERIFY(!font.isValid()); } #endif // QT_NO_RAWFONT