Bug 516709. Do better validation of cmap tables when loading fonts. r=jkew.

This commit is contained in:
John Daggett 2009-09-18 09:45:29 +09:00
Родитель 60a7ed62b0
Коммит 2342c5446d
6 изменённых файлов: 89 добавлений и 32 удалений

Просмотреть файл

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