diff options
-rw-r--r-- | include/o3tl/safeint.hxx | 124 | ||||
-rw-r--r-- | vcl/inc/sft.hxx | 14 | ||||
-rw-r--r-- | vcl/source/fontsubset/sft.cxx | 111 |
3 files changed, 197 insertions, 52 deletions
diff --git a/include/o3tl/safeint.hxx b/include/o3tl/safeint.hxx new file mode 100644 index 000000000000..5ebf353b6bd6 --- /dev/null +++ b/include/o3tl/safeint.hxx @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_O3TL_SAFEINT_HXX +#define INCLUDED_O3TL_SAFEINT_HXX + +#include <limits> +#if defined(_MSC_VER) +#include <safeint.h> +#else +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif +#endif + +namespace o3tl +{ + +#if defined(_MSC_VER) + +template<typename T> inline bool checked_multiply(T a, T b, T& result) +{ + return !msl::utilities::SafeMultiply(a, b, result); +} + +template<typename T> inline bool checked_add(T a, T b, T& result) +{ + return !msl::utilities::SafeAdd(a, b, result); +} + +#elif (defined __GNUC__ && __GNUC__ >= 5) || (__has_builtin(__builtin_mul_overflow) && !(defined ANDROID && defined __clang__)) + +template<typename T> inline bool checked_multiply(T a, T b, T& result) +{ + return __builtin_mul_overflow(a, b, &result); +} + +template<typename T> inline bool checked_add(T a, T b, T& result) +{ + return __builtin_add_overflow(a, b, &result); +} + +#else + +//https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow +template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_multiply(T a, T b, T& result) +{ + if (a > 0) { /* a is positive */ + if (b > 0) { /* a and b are positive */ + if (a > (std::numeric_limits<T>::max() / b)) { + return true; /* Handle error */ + } + } else { /* a positive, b nonpositive */ + if (b < (std::numeric_limits<T>::min() / a)) { + return true; /* Handle error */ + } + } /* a positive, b nonpositive */ + } else { /* a is nonpositive */ + if (b > 0) { /* a is nonpositive, b is positive */ + if (a < (std::numeric_limits<T>::min() / b)) { + return true; /* Handle error */ + } + } else { /* a and b are nonpositive */ + if ( (a != 0) && (b < (std::numeric_limits<T>::max() / a))) { + return true; /* Handle error */ + } + } /* End if a and b are nonpositive */ + } /* End if a is nonpositive */ + + result = a * b; + + return false; +} + +//https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap +template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_multiply(T a, T b, T& result) +{ + if (b && a > std::numeric_limits<T>::max() / b) { + return true;/* Handle error */ + } + + result = a * b; + + return false; +} + +//https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow +template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_add(T a, T b, T& result) +{ + if (((b > 0) && (a > (std::numeric_limits<T>::max() - b))) || + ((b < 0) && (a < (std::numeric_limits<T>::min() - b)))) { + return true; + } + + result = a + b; + + return false; +} + +//https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap +template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_add(T a, T b, T& result) +{ + if (std::numeric_limits<T>::max() - a < b) { + return true;/* Handle error */ + } + + result = a + b; + + return false; +} + +#endif + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/sft.hxx b/vcl/inc/sft.hxx index 80c62c11b878..0b3c3afcfbef 100644 --- a/vcl/inc/sft.hxx +++ b/vcl/inc/sft.hxx @@ -189,21 +189,15 @@ namespace vcl int descender; /**< typographic descent. */ int linegap; /**< typographic line gap.\ Negative values are treated as zero in Win 3.1, System 6 and System 7. */ - int vascent; /**< typographic ascent for vertical writing mode */ - int vdescent; /**< typographic descent for vertical writing mode */ int typoAscender; /**< OS/2 portable typographic ascender */ int typoDescender; /**< OS/2 portable typographic descender */ int typoLineGap; /**< OS/2 portable typographic line gap */ int winAscent; /**< ascender metric for Windows */ int winDescent; /**< descender metric for Windows */ bool symbolEncoded; /**< true: MS symbol encoded */ - int rangeFlag; /**< if set to 1 Unicode Range flags are applicable */ - sal_uInt32 ur1; /**< bits 0 - 31 of Unicode Range flags */ - sal_uInt32 ur2; /**< bits 32 - 63 of Unicode Range flags */ - sal_uInt32 ur3; /**< bits 64 - 95 of Unicode Range flags */ - sal_uInt32 ur4; /**< bits 96 - 127 of Unicode Range flags */ - sal_uInt8 panose[10]; /**< PANOSE classification number */ - sal_uInt32 typeFlags; /**< type flags (copyright bits + PS-OpenType flag) */ + sal_uInt8 panose[10]; /**< PANOSE classification number */ + sal_uInt32 typeFlags; /**< type flags (copyright bits + PS-OpenType flag) */ + sal_uInt16 fsSelection; /**< OS/2 fsSelection */ } TTGlobalFontInfo; #define TYPEFLAG_INVALID 0x8000000 @@ -521,8 +515,6 @@ namespace vcl /*- private definitions */ struct TrueTypeFont { - sal_uInt32 tag; - char *fname; sal_Int32 fsize; sal_uInt8 *ptr; diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx index 150b21ec676a..e6bfd7509da3 100644 --- a/vcl/source/fontsubset/sft.cxx +++ b/vcl/source/fontsubset/sft.cxx @@ -39,7 +39,7 @@ #include "xlat.hxx" #include <rtl/crc.h> #include <rtl/ustring.hxx> - +#include <o3tl/safeint.hxx> #include <osl/endian.h> #include <algorithm> @@ -104,9 +104,6 @@ typedef struct { sal_uInt32 *offs; /* array of nGlyphs offsets */ } GlyphOffsets; -/* private tags */ -static const sal_uInt32 TTFontClassTag = 0x74746663; /* 'ttfc' */ - static const sal_uInt32 T_true = 0x74727565; /* 'true' */ static const sal_uInt32 T_ttcf = 0x74746366; /* 'ttcf' */ static const sal_uInt32 T_otto = 0x4f54544f; /* 'OTTO' */ @@ -1341,6 +1338,13 @@ static void FindCmap(TrueTypeFont *ttf) } if (ttf->cmapType != CMAP_NOT_USABLE) { + if( (ttf->cmap - ttf->ptr + 2U) > static_cast<sal_uInt32>(ttf->fsize) ) { + ttf->cmapType = CMAP_NOT_USABLE; + ttf->cmap = nullptr; + } + } + + if (ttf->cmapType != CMAP_NOT_USABLE) { switch (GetUInt16(ttf->cmap, 0, 1)) { case 0: ttf->mapper = getGlyph0; break; case 2: ttf->mapper = getGlyph2; break; @@ -1461,7 +1465,6 @@ static void allocTrueTypeFont( TrueTypeFont** ttf ) *ttf = static_cast<TrueTypeFont*>(calloc(1,sizeof(TrueTypeFont))); if( *ttf != nullptr ) { - (*ttf)->tag = 0; (*ttf)->fname = nullptr; (*ttf)->fsize = -1; (*ttf)->ptr = nullptr; @@ -1546,10 +1549,41 @@ int OpenTTFontBuffer(const void* pBuffer, sal_uInt32 nLen, sal_uInt32 facenum, T return doOpenTTFont( facenum, *ttf ); } +namespace { + +bool withinBounds(sal_uInt32 tdoffset, sal_uInt32 moreoffset, sal_uInt32 len, sal_uInt32 available) +{ + sal_uInt32 result; + if (o3tl::checked_add(tdoffset, moreoffset, result)) + return false; + if (o3tl::checked_add(result, len, result)) + return false; + return result <= available; +} + +class TTFontCloser +{ + TrueTypeFont* m_font; +public: + TTFontCloser(TrueTypeFont* t) + : m_font(t) + { + } + void clear() { m_font = nullptr; } + ~TTFontCloser() + { + if (m_font) + CloseTTFont(m_font); + } +}; + +} + static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) { + TTFontCloser aCloseGuard(t); + if (t->fsize < 4) { - CloseTTFont(t); return SF_TTFORMAT; } int i; @@ -1563,27 +1597,28 @@ static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) } else if (TTCTag == T_otto) { /* PS-OpenType font */ tdoffset = 0; } else if (TTCTag == T_ttcf) { /* TrueType collection */ + if (!withinBounds(12, 4 * facenum, sizeof(sal_uInt32), t->fsize)) { + return SF_FONTNO; + } sal_uInt32 Version = GetUInt32(t->ptr, 4, 1); if (Version != 0x00010000 && Version != 0x00020000) { - CloseTTFont(t); return SF_TTFORMAT; } if (facenum >= GetUInt32(t->ptr, 8, 1)) { - CloseTTFont(t); return SF_FONTNO; } tdoffset = GetUInt32(t->ptr, 12 + 4 * facenum, 1); } else { - CloseTTFont(t); return SF_TTFORMAT; } - /* magic number */ - t->tag = TTFontClassTag; + if (withinBounds(tdoffset, 0, 4 + sizeof(sal_uInt16), t->fsize)) { + t->ntables = GetUInt16(t->ptr + tdoffset, 4, 1); + } - t->ntables = GetUInt16(t->ptr + tdoffset, 4, 1); - if( t->ntables >= 128 ) + if (t->ntables >= 128 || t->ntables == 0) { return SF_TTFORMAT; + } t->tables = static_cast<const sal_uInt8**>(calloc(NUM_TAGS, sizeof(sal_uInt8 *))); assert(t->tables != nullptr); @@ -1595,7 +1630,7 @@ static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) int nIndex; const sal_uInt32 nStart = tdoffset + 12; const sal_uInt32 nOffset = 16 * i; - if (nStart + nOffset + sizeof(sal_uInt32) <= static_cast<sal_uInt32>(t->fsize)) + if (withinBounds(nStart, nOffset, sizeof(sal_uInt32), t->fsize)) tag = GetUInt32(t->ptr + nStart, nOffset, 1); else tag = static_cast<sal_uInt32>(-1); @@ -1620,9 +1655,10 @@ static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) case T_CFF: nIndex = O_CFF; break; default: nIndex = -1; break; } - if( nIndex >= 0 ) { - sal_uInt32 nTableOffset = GetUInt32(t->ptr + tdoffset + 12, 16 * i + 8, 1); - length = GetUInt32(t->ptr + tdoffset + 12, 16 * i + 12, 1); + + if ((nIndex >= 0) && withinBounds(nStart, nOffset, 12 + sizeof(sal_uInt32), t->fsize)) { + sal_uInt32 nTableOffset = GetUInt32(t->ptr + nStart, nOffset + 8, 1); + length = GetUInt32(t->ptr + nStart, nOffset + 12, 1); t->tables[nIndex] = t->ptr + nTableOffset; t->tlens[nIndex] = length; } @@ -1631,8 +1667,9 @@ static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) /* Fixup offsets when only a TTC extract was provided */ if( facenum == (sal_uInt32)~0 ) { sal_uInt8* pHead = const_cast<sal_uInt8*>(t->tables[O_head]); - if( !pHead ) + if (!pHead) { return SF_TTFORMAT; + } /* limit Head candidate to TTC extract's limits */ if( pHead > t->ptr + (t->fsize - 54) ) pHead = t->ptr + (t->fsize - 54); @@ -1648,8 +1685,9 @@ static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) break; } } - if( p <= t->ptr ) + if (p <= t->ptr) { return SF_TTFORMAT; + } } /* Check the table offsets after TTC correction */ @@ -1671,7 +1709,7 @@ static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) } else if( const_cast<sal_uInt8*>(t->tables[i]) + t->tlens[i] > t->ptr + t->fsize ) { - int nMaxLen = (t->ptr + t->fsize) - t->tables[i]; + sal_PtrDiff nMaxLen = (t->ptr + t->fsize) - t->tables[i]; if( nMaxLen < 0 ) nMaxLen = 0; t->tlens[i] = nMaxLen; @@ -1689,7 +1727,6 @@ static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) */ if( !(getTable(t, O_maxp) && getTable(t, O_head) && getTable(t, O_name) && getTable(t, O_cmap)) ) { - CloseTTFont(t); return SF_TTFORMAT; } @@ -1700,14 +1737,12 @@ static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) table = getTable(t, O_head); table_size = getTableSize(t, O_head); if (table_size < 52) { - CloseTTFont(t); return SF_TTFORMAT; } t->unitsPerEm = GetUInt16(table, 18, 1); int indexfmt = GetInt16(table, 50, 1); if( ((indexfmt != 0) && (indexfmt != 1)) || (t->unitsPerEm <= 0) ) { - CloseTTFont(t); return SF_TTFORMAT; } @@ -1731,7 +1766,6 @@ static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) /* TODO: implement to get subsetting */ assert(t->goffsets != nullptr); } else { - CloseTTFont(t); return SF_TTFORMAT; } @@ -1748,6 +1782,8 @@ static int doOpenTTFont( sal_uInt32 facenum, TrueTypeFont* t ) GetKern(t); ReadGSUB( t, 0, 0 ); + aCloseGuard.clear(); + return SF_OK; } @@ -2590,13 +2626,6 @@ void GetTTGlobalFontInfo(TrueTypeFont *ttf, TTGlobalFontInfo *info) if( info->winDescent > 5*UPEm ) info->winDescent = XUnits(UPEm, GetInt16(table, 76,1)); } - if (ttf->cmapType == CMAP_MS_Unicode) { - info->rangeFlag = 1; - info->ur1 = GetUInt32(table, 42, 1); - info->ur2 = GetUInt32(table, 46, 1); - info->ur3 = GetUInt32(table, 50, 1); - info->ur4 = GetUInt32(table, 54, 1); - } memcpy(info->panose, table + 32, 10); info->typeFlags = GetUInt16( table, 8, 1 ); if( getTable(ttf, O_CFF) ) @@ -2610,24 +2639,24 @@ void GetTTGlobalFontInfo(TrueTypeFont *ttf, TTGlobalFontInfo *info) } table = getTable(ttf, O_head); /* 'head' tables is always there */ - info->xMin = XUnits(UPEm, GetInt16(table, 36, 1)); - info->yMin = XUnits(UPEm, GetInt16(table, 38, 1)); - info->xMax = XUnits(UPEm, GetInt16(table, 40, 1)); - info->yMax = XUnits(UPEm, GetInt16(table, 42, 1)); - info->macStyle = GetInt16(table, 44, 1); + table_size = getTableSize(ttf, O_head); + if (table_size >= 46) { + info->xMin = XUnits(UPEm, GetInt16(table, 36, 1)); + info->yMin = XUnits(UPEm, GetInt16(table, 38, 1)); + info->xMax = XUnits(UPEm, GetInt16(table, 40, 1)); + info->yMax = XUnits(UPEm, GetInt16(table, 42, 1)); + info->macStyle = GetInt16(table, 44, 1); + } table = getTable(ttf, O_hhea); - if (table) { + table_size = getTableSize(ttf, O_hhea); + if (table && table_size >= 10) { info->ascender = XUnits(UPEm, GetInt16(table, 4, 1)); info->descender = XUnits(UPEm, GetInt16(table, 6, 1)); info->linegap = XUnits(UPEm, GetInt16(table, 8, 1)); } table = getTable(ttf, O_vhea); - if (table) { - info->vascent = XUnits(UPEm, GetInt16(table, 4, 1)); - info->vdescent = XUnits(UPEm, GetInt16(table, 6, 1)); - } } GlyphData *GetTTRawGlyphData(TrueTypeFont *ttf, sal_uInt32 glyphID) |