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>
bb10
Konstantin Ritt 2014-11-25 15:41:29 +04:00
parent 5b11e43e9f
commit e9dbaa328e
4 changed files with 38 additions and 29 deletions

View File

@ -923,7 +923,11 @@ public:
static const char keyC[] = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes";
const QString familyName = QString::fromWCharArray(lf.lfFaceName);
const QString nameSubstitute = QSettings(QLatin1String(keyC), QSettings::NativeFormat).value(familyName, familyName).toString();
memcpy(lf.lfFaceName, nameSubstitute.utf16(), sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE));
if (nameSubstitute != familyName) {
const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1);
memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t));
lf.lfFaceName[nameSubstituteLength] = 0;
}
ComPtr<IDWriteFont> dwriteFont;
HRESULT hr = QWindowsDirect2DContext::instance()->dwriteGdiInterop()->CreateFontFromLOGFONT(&lf, &dwriteFont);

View File

@ -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,

View File

@ -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);
}

View File

@ -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);