зеркало из https://github.com/mozilla/gecko-dev.git
Bug 516709. Do better validation of cmap tables when loading fonts. r=jkew.
This commit is contained in:
Родитель
60a7ed62b0
Коммит
2342c5446d
|
@ -62,10 +62,6 @@
|
|||
#undef max
|
||||
#endif
|
||||
|
||||
#include <bitset>
|
||||
|
||||
// code from gfxWindowsFonts.h
|
||||
|
||||
class gfxSparseBitSet {
|
||||
private:
|
||||
enum { BLOCK_SIZE = 32 }; // ==> 256 codepoints per block
|
||||
|
@ -425,7 +421,10 @@ public:
|
|||
LANG_ID_MAC_CZECH = 38,
|
||||
LANG_ID_MAC_SLOVAK = 39,
|
||||
|
||||
LANG_ID_MICROSOFT_EN_US = 0x0409 // with Microsoft platformID, EN US lang code
|
||||
LANG_ID_MICROSOFT_EN_US = 0x0409, // with Microsoft platformID, EN US lang code
|
||||
|
||||
CMAP_MAX_CODEPOINT = 0x10ffff // maximum possible Unicode codepoint
|
||||
// contained in a cmap
|
||||
};
|
||||
|
||||
// name table has a header, followed by name records, followed by string data
|
||||
|
|
|
@ -54,6 +54,17 @@ typedef double gfxFloat;
|
|||
# define THEBES_API NS_IMPORT
|
||||
#endif
|
||||
|
||||
/**
|
||||
* gfx errors
|
||||
*/
|
||||
|
||||
/* nsIDeviceContext.h defines a set of printer errors */
|
||||
#define NS_ERROR_GFX_GENERAL_BASE (50)
|
||||
|
||||
/* Font cmap is strangely structured - avoid this font! */
|
||||
#define NS_ERROR_GFX_CMAP_MALFORMED \
|
||||
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GFX,NS_ERROR_GFX_GENERAL_BASE+1)
|
||||
|
||||
/**
|
||||
* Priority of a line break opportunity.
|
||||
*
|
||||
|
|
|
@ -53,6 +53,10 @@
|
|||
#include <usp10.h>
|
||||
#include <cairo-win32.h>
|
||||
|
||||
// xxx - used in FontEntry. should be trimmed, moz code doesn't use
|
||||
// exceptions. use gfxSparseBitSet instead?
|
||||
#include <bitset>
|
||||
|
||||
/**
|
||||
* List of different types of fonts we support on Windows.
|
||||
* These can generally be lumped in to 3 categories where we have to
|
||||
|
|
|
@ -246,25 +246,35 @@ gfxFontUtils::ReadCMAPTableFormat12(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBi
|
|||
GroupOffsetStartCode = 0,
|
||||
GroupOffsetEndCode = 4
|
||||
};
|
||||
NS_ENSURE_TRUE(aLength >= 16, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(aLength >= 16, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 12, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetReserved) == 0, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 12,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetReserved) == 0,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
PRUint32 tablelen = ReadLongAt(aBuf, OffsetTableLength);
|
||||
NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tablelen >= 16, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
NS_ENSURE_TRUE(tablelen >= 16, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
NS_ENSURE_TRUE(ReadLongAt(aBuf, OffsetLanguage) == 0, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(ReadLongAt(aBuf, OffsetLanguage) == 0,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
const PRUint32 numGroups = ReadLongAt(aBuf, OffsetNumberGroups);
|
||||
NS_ENSURE_TRUE(tablelen >= 16 + (12 * numGroups), NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tablelen >= 16 + (12 * numGroups),
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
const PRUint8 *groups = aBuf + OffsetGroups;
|
||||
PRUint32 prevEndCharCode = 0;
|
||||
for (PRUint32 i = 0; i < numGroups; i++, groups += SizeOfGroup) {
|
||||
const PRUint32 startCharCode = ReadLongAt(groups, GroupOffsetStartCode);
|
||||
const PRUint32 endCharCode = ReadLongAt(groups, GroupOffsetEndCode);
|
||||
NS_ENSURE_TRUE((prevEndCharCode < startCharCode || i == 0) &&
|
||||
startCharCode <= endCharCode &&
|
||||
endCharCode <= CMAP_MAX_CODEPOINT,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
aCharacterMap.SetRange(startCharCode, endCharCode);
|
||||
prevEndCharCode = endCharCode;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -280,18 +290,21 @@ gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBit
|
|||
OffsetSegCountX2 = 6
|
||||
};
|
||||
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 4, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetFormat) == 4,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
PRUint16 tablelen = ReadShortAt(aBuf, OffsetLength);
|
||||
NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tablelen > 16, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tablelen <= aLength, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
NS_ENSURE_TRUE(tablelen > 16, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
// some buggy fonts on Mac OS report lang = English (e.g. Arial Narrow Bold, v. 1.1 (Tiger))
|
||||
#if defined(XP_WIN)
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetLanguage) == 0, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(ReadShortAt(aBuf, OffsetLanguage) == 0,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
#endif
|
||||
|
||||
PRUint16 segCountX2 = ReadShortAt(aBuf, OffsetSegCountX2);
|
||||
NS_ENSURE_TRUE(tablelen >= 16 + (segCountX2 * 4), NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(tablelen >= 16 + (segCountX2 * 4),
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
const PRUint16 segCount = segCountX2 / 2;
|
||||
|
||||
|
@ -299,10 +312,18 @@ gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBit
|
|||
const PRUint16 *startCounts = endCounts + 1 /* skip one uint16 for reservedPad */ + segCount;
|
||||
const PRUint16 *idDeltas = startCounts + segCount;
|
||||
const PRUint16 *idRangeOffsets = idDeltas + segCount;
|
||||
PRUint16 prevEndCount = 0;
|
||||
for (PRUint16 i = 0; i < segCount; i++) {
|
||||
const PRUint16 endCount = ReadShortAt16(endCounts, i);
|
||||
const PRUint16 startCount = ReadShortAt16(startCounts, i);
|
||||
const PRUint16 idRangeOffset = ReadShortAt16(idRangeOffsets, i);
|
||||
|
||||
// sanity-check range
|
||||
NS_ENSURE_TRUE((startCount > prevEndCount || i == 0) &&
|
||||
startCount <= endCount,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
prevEndCount = endCount;
|
||||
|
||||
if (idRangeOffset == 0) {
|
||||
aCharacterMap.SetRange(startCount, endCount);
|
||||
} else {
|
||||
|
@ -315,7 +336,9 @@ gfxFontUtils::ReadCMAPTableFormat4(PRUint8 *aBuf, PRUint32 aLength, gfxSparseBit
|
|||
+ (c - startCount)
|
||||
+ &idRangeOffsets[i]);
|
||||
|
||||
NS_ENSURE_TRUE((PRUint8*)gdata > aBuf && (PRUint8*)gdata < aBuf + aLength, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE((PRUint8*)gdata > aBuf &&
|
||||
(PRUint8*)gdata < aBuf + aLength,
|
||||
NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
// make sure we have a glyph
|
||||
if (*gdata != 0) {
|
||||
|
@ -390,7 +413,7 @@ gfxFontUtils::ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCha
|
|||
const PRUint32 offset = ReadLongAt(table, TableOffsetOffset);
|
||||
|
||||
NS_ASSERTION(offset < aBufLength, "cmap table offset is longer than table size");
|
||||
NS_ENSURE_TRUE(offset < aBufLength, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(offset < aBufLength, NS_ERROR_GFX_CMAP_MALFORMED);
|
||||
|
||||
const PRUint8 *subtable = aBuf + offset;
|
||||
const PRUint16 format = ReadShortAt(subtable, SubtableOffsetFormat);
|
||||
|
|
|
@ -195,6 +195,11 @@ MacOSFontEntry::ReadCMAP()
|
|||
PRPackedBool unicodeFont, symbolFont; // currently ignored
|
||||
nsresult rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
|
||||
mCharacterMap, unicodeFont, symbolFont);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mCharacterMap.reset();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// for complex scripts, check for the presence of mort/morx
|
||||
PRBool checkedForMorphTable = PR_FALSE, hasMorphTable = PR_FALSE;
|
||||
|
@ -798,8 +803,8 @@ gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
// if we succeeded (which should always be the case), return the new font
|
||||
if (newFontEntry->mIsValid)
|
||||
// if succeeded and font cmap is good, return the new font
|
||||
if (newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP()))
|
||||
return newFontEntry;
|
||||
|
||||
// if something is funky about this font, delete immediately
|
||||
|
|
|
@ -657,6 +657,8 @@ FontEntry::CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType,
|
|||
FontEntry *fe;
|
||||
|
||||
fe = new FontEntry(aName, aFontType, aItalic, aWeight, aUserFontData);
|
||||
if (!fe)
|
||||
return nsnull;
|
||||
|
||||
if (!aLogFont) {
|
||||
aLogFont = &logFont;
|
||||
|
@ -673,20 +675,33 @@ FontEntry::CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType,
|
|||
|
||||
if (font) {
|
||||
AutoPushPopFont fontCleanup(hdc, font);
|
||||
nsresult rv;
|
||||
|
||||
// ReadCMAP may change the values of mUnicodeFont and mSymbolFont
|
||||
if (NS_FAILED(::ReadCMAP(hdc, fe))) {
|
||||
// Type1 fonts aren't necessarily Unicode but
|
||||
// this is the best guess we can make here
|
||||
if (fe->IsType1())
|
||||
fe->mUnicodeFont = PR_TRUE;
|
||||
else
|
||||
fe->mUnicodeFont = PR_FALSE;
|
||||
rv = ::ReadCMAP(hdc, fe);
|
||||
|
||||
// For fonts where we failed to read the character map,
|
||||
// we can take a slow path to look up glyphs character by character
|
||||
fe->mUnknownCMAP = PR_TRUE;
|
||||
if (NS_FAILED(rv)) {
|
||||
|
||||
// ReadCMAP can fail but only handle failure cases when the font
|
||||
// did *not* have a cmap that appears to be malformed. Uniscribe
|
||||
// can crash with corrupt cmaps.
|
||||
if (rv == NS_ERROR_GFX_CMAP_MALFORMED) {
|
||||
delete fe;
|
||||
return nsnull;
|
||||
} else {
|
||||
|
||||
// ReadCMAP may change the values of mUnicodeFont and mSymbolFont
|
||||
|
||||
// Type1 fonts aren't necessarily Unicode but
|
||||
// this is the best guess we can make here
|
||||
if (fe->IsType1())
|
||||
fe->mUnicodeFont = PR_TRUE;
|
||||
else
|
||||
fe->mUnicodeFont = PR_FALSE;
|
||||
|
||||
// For fonts where we failed to read the character map,
|
||||
// we can take a slow path to look up glyphs character by character
|
||||
fe->mUnknownCMAP = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче