diff options
author | Konstantin Ritt <ritt.ks@gmail.com> | 2014-11-25 15:41:29 +0400 |
---|---|---|
committer | Konstantin Ritt <ritt.ks@gmail.com> | 2014-12-24 15:05:24 +0100 |
commit | e9dbaa328e7d26ad6a7b5fd2490191751a7731b4 (patch) | |
tree | f4a2b2f62d4388a106e13edefd782adb242adb26 /src/plugins/platforms/windows | |
parent | 5b11e43e9f7551b9cb1ea7a6effdcab4bfa6b8c9 (diff) |
Fix potential memory access violation issues
LOGFONT docs clearly states `lfFaceName` member is a null-terminated
string of length not longer than LF_FACESIZE, including trailing null.
This patch covers two cases at once:
1. If family name is longer than LF_FACESIZE - 1, it would be truncated
and terminated with null, to prevent memory access beyond
the LOGFONT instance.
2. If family name is a fromRawData QString, we don't assume it is
null-terminated either and guarantee trailing null ourselves.
Change-Id: I8f607efc7d0901537a4179e36cc51df94203f08d
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
Diffstat (limited to 'src/plugins/platforms/windows')
3 files changed, 33 insertions, 28 deletions
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index c9851a1c65..46b05de4ae 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -794,7 +794,7 @@ QString getEnglishName(const QString &familyName) HDC hdc = GetDC( 0 ); LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); - memcpy(lf.lfFaceName, familyName.utf16(), qMin(LF_FACESIZE, familyName.length()) * sizeof(wchar_t)); + memcpy(lf.lfFaceName, familyName.utf16(), qMin(familyName.length(), LF_FACESIZE - 1) * sizeof(wchar_t)); lf.lfCharSet = DEFAULT_CHARSET; HFONT hfont = CreateFontIndirect(&lf); @@ -958,14 +958,9 @@ static int QT_WIN_CALLBACK storeFontSub(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textm HDC dummy = GetDC(0); LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); lf.lfCharSet = DEFAULT_CHARSET; - if (wcslen(f->elfLogFont.lfFaceName) >= LF_FACESIZE) { - qWarning("%s: Unable to enumerate family '%s'.", - __FUNCTION__, qPrintable(QString::fromWCharArray(f->elfLogFont.lfFaceName))); - return 1; - } - wmemcpy(lf.lfFaceName, f->elfLogFont.lfFaceName, - wcslen(f->elfLogFont.lfFaceName) + 1); + memcpy(lf.lfFaceName, f->elfLogFont.lfFaceName, LF_FACESIZE * sizeof(wchar_t)); lf.lfPitchAndFamily = 0; EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFont, (LPARAM)namesSetIn, 0); @@ -1001,20 +996,21 @@ void QWindowsFontDatabase::populate(const QString &family) HDC dummy = GetDC(0); LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); lf.lfCharSet = DEFAULT_CHARSET; if (family.size() >= LF_FACESIZE) { qWarning("%s: Unable to enumerate family '%s'.", __FUNCTION__, qPrintable(family)); return; } - wmemcpy(lf.lfFaceName, reinterpret_cast<const wchar_t*>(family.utf16()), - family.size() + 1); + lf.lfPitchAndFamily = 0; if (family.isEmpty()) { EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFontSub, (LPARAM)&m_families, 0); } else { + memcpy(lf.lfFaceName, family.utf16(), family.size() * sizeof(wchar_t)); EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFont, (LPARAM)&m_families, 0); } @@ -1350,7 +1346,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, HDC hdc = GetDC(0); LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); - memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE, familyName.size())); + memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size())); lf.lfCharSet = DEFAULT_CHARSET; HFONT hfont = CreateFontIndirect(&lf); HGDIOBJ oldobj = SelectObject(hdc, hfont); @@ -1575,6 +1571,10 @@ LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request) lf.lfPitchAndFamily = DEFAULT_PITCH | hint; QString fam = request.family; + if (fam.size() >= LF_FACESIZE) { + qCritical("%s: Family name '%s' is too long.", __FUNCTION__, qPrintable(fam)); + fam.truncate(LF_FACESIZE - 1); + } if (fam.isEmpty()) fam = QStringLiteral("MS Sans Serif"); @@ -1586,7 +1586,7 @@ LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request) if (fam == QLatin1String("Courier") && !(request.styleStrategy & QFont::PreferBitmap)) fam = QStringLiteral("Courier New"); - memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded + memcpy(lf.lfFaceName, fam.utf16(), fam.size() * sizeof(wchar_t)); return lf; } @@ -1767,9 +1767,13 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, // turns out okay) useDirectWrite = false; if (initDirectWrite(data.data())) { - const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName)); - memcpy(lf.lfFaceName, nameSubstitute.utf16(), - sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE)); + const QString fam = QString::fromWCharArray(lf.lfFaceName); + const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam); + if (nameSubstitute != fam) { + const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1); + memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t)); + lf.lfFaceName[nameSubstituteLength] = 0; + } HRESULT hr = data->directWriteGdiInterop->CreateFontFromLOGFONT( &lf, diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 41e767dd1b..a2d9c3e75b 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -369,14 +369,9 @@ static int QT_WIN_CALLBACK storeFontSub(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textm HDC dummy = GetDC(0); LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); lf.lfCharSet = DEFAULT_CHARSET; - if (wcslen(f->elfLogFont.lfFaceName) >= LF_FACESIZE) { - qWarning("%s: Unable to enumerate family '%s'.", - __FUNCTION__, qPrintable(QString::fromWCharArray(f->elfLogFont.lfFaceName))); - return 1; - } - wmemcpy(lf.lfFaceName, f->elfLogFont.lfFaceName, - wcslen(f->elfLogFont.lfFaceName) + 1); + memcpy(lf.lfFaceName, f->elfLogFont.lfFaceName, LF_FACESIZE * sizeof(wchar_t)); lf.lfPitchAndFamily = 0; EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFont, (LPARAM)namesSetIn, 0); @@ -411,20 +406,21 @@ void QWindowsFontDatabaseFT::populate(const QString &family) HDC dummy = GetDC(0); LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); lf.lfCharSet = DEFAULT_CHARSET; if (family.size() >= LF_FACESIZE) { qWarning("%s: Unable to enumerate family '%s'.", __FUNCTION__, qPrintable(family)); return; } - wmemcpy(lf.lfFaceName, reinterpret_cast<const wchar_t*>(family.utf16()), - family.size() + 1); + lf.lfPitchAndFamily = 0; if (family.isEmpty()) { EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFontSub, (LPARAM)&m_families, 0); } else { + memcpy(lf.lfFaceName, family.utf16(), family.size() * sizeof(wchar_t)); EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFont, (LPARAM)&m_families, 0); } diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index a182987e3f..5790360d34 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -1329,13 +1329,18 @@ QFontEngine *QWindowsMultiFontEngine::loadEngine(int at) } const QString fam = fallbackFamilyAt(at - 1); - memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded + const int faceNameLength = qMin(fam.length(), LF_FACESIZE - 1); + memcpy(lf.lfFaceName, fam.utf16(), faceNameLength * sizeof(wchar_t)); + lf.lfFaceName[faceNameLength] = 0; #ifndef QT_NO_DIRECTWRITE if (fontEngine->type() == QFontEngine::DirectWrite) { - const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName)); - memcpy(lf.lfFaceName, nameSubstitute.utf16(), - sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE)); + const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam); + if (nameSubstitute != fam) { + const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1); + memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t)); + lf.lfFaceName[nameSubstituteLength] = 0; + } IDWriteFont *directWriteFont = 0; HRESULT hr = data->directWriteGdiInterop->CreateFontFromLOGFONT(&lf, &directWriteFont); |