Fix crash when reading corrupt font data
When loading the font data, we had some unprotected reads. To harden this, we check everything against the length of the font data before reading. [ChangeLog][QtGui][Windows] Fixed a possible crash that could happen when loading corrupted font data. Fixes: QTBUG-116773 Pick-to: 5.15 6.2 6.5 6.6 6.6.0 Change-Id: I156df3b8833c9ed785fcc690821a7a74d9a51126 Reviewed-by: Lars Knoll <lars@knoll.priv.no> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
a1b55b1360
commit
9fe47cf2e1
@ -873,37 +873,71 @@ QT_WARNING_POP
|
||||
return fontEngine;
|
||||
}
|
||||
|
||||
static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
|
||||
static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData, const uchar *fileEndSentinel)
|
||||
{
|
||||
QList<quint32> offsets;
|
||||
const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
|
||||
if (fileEndSentinel - fontData < 12) {
|
||||
qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
return offsets;
|
||||
}
|
||||
|
||||
const quint32 headerTag = qFromUnaligned<quint32>(fontData);
|
||||
if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
|
||||
if (headerTag != MAKE_TAG(0, 1, 0, 0)
|
||||
&& headerTag != MAKE_TAG('O', 'T', 'T', 'O')
|
||||
&& headerTag != MAKE_TAG('t', 'r', 'u', 'e')
|
||||
&& headerTag != MAKE_TAG('t', 'y', 'p', '1'))
|
||||
&& headerTag != MAKE_TAG('t', 'y', 'p', '1')) {
|
||||
return offsets;
|
||||
}
|
||||
offsets << 0;
|
||||
return offsets;
|
||||
}
|
||||
|
||||
const quint32 maximumNumFonts = 0xffff;
|
||||
const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
|
||||
for (uint i = 0; i < numFonts; ++i) {
|
||||
offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
|
||||
if (numFonts > maximumNumFonts) {
|
||||
qCWarning(lcQpaFonts) << "Font collection of" << numFonts << "fonts is too large. Aborting.";
|
||||
return offsets;
|
||||
}
|
||||
|
||||
if (quintptr(fileEndSentinel - fontData) > 12 + (numFonts - 1) * 4) {
|
||||
for (quint32 i = 0; i < numFonts; ++i)
|
||||
offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
|
||||
} else {
|
||||
qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
}
|
||||
|
||||
return offsets;
|
||||
}
|
||||
|
||||
static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
|
||||
static void getFontTable(const uchar *fileBegin, const uchar *fileEndSentinel, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
|
||||
{
|
||||
if (fileEndSentinel - data >= 6) {
|
||||
const quint16 numTables = qFromBigEndian<quint16>(data + 4);
|
||||
for (uint i = 0; i < numTables; ++i) {
|
||||
if (fileEndSentinel - data >= 28 + 16 * (numTables - 1)) {
|
||||
for (quint32 i = 0; i < numTables; ++i) {
|
||||
const quint32 offset = 12 + 16 * i;
|
||||
if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
|
||||
*table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
|
||||
if (qFromUnaligned<quint32>(data + offset) == tag) {
|
||||
const quint32 tableOffset = qFromBigEndian<quint32>(data + offset + 8);
|
||||
if (quintptr(fileEndSentinel - fileBegin) <= tableOffset) {
|
||||
qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
break;
|
||||
}
|
||||
*table = fileBegin + tableOffset;
|
||||
*length = qFromBigEndian<quint32>(data + offset + 12);
|
||||
if (quintptr(fileEndSentinel - *table) < *length) {
|
||||
qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
}
|
||||
} else {
|
||||
qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
}
|
||||
*table = 0;
|
||||
*length = 0;
|
||||
return;
|
||||
@ -915,8 +949,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
|
||||
QList<QFontValues> *values)
|
||||
{
|
||||
const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
|
||||
const uchar *dataEndSentinel = data + fontData.size();
|
||||
|
||||
QList<quint32> offsets = getTrueTypeFontOffsets(data);
|
||||
QList<quint32> offsets = getTrueTypeFontOffsets(data, dataEndSentinel);
|
||||
if (offsets.isEmpty())
|
||||
return;
|
||||
|
||||
@ -924,7 +959,7 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
|
||||
const uchar *font = data + offsets.at(i);
|
||||
const uchar *table;
|
||||
quint32 length;
|
||||
getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
|
||||
getFontTable(data, dataEndSentinel, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
|
||||
if (!table)
|
||||
continue;
|
||||
QFontNames names = qt_getCanonicalFontNames(table, length);
|
||||
@ -934,7 +969,7 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
|
||||
families->append(std::move(names));
|
||||
|
||||
if (values || signatures)
|
||||
getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
|
||||
getFontTable(data, dataEndSentinel, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
|
||||
|
||||
if (values) {
|
||||
QFontValues fontValues;
|
||||
|
Loading…
Reference in New Issue
Block a user