1d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// Copyright (c) 2009 The Chromium Authors. All rights reserved. 2d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// Use of this source code is governed by a BSD-style license that can be 3d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// found in the LICENSE file. 4d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 59601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#if !defined(_MSC_VER) 69601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#ifdef __linux__ 79601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Linux 89601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#include <freetype/ftoutln.h> 9d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <ft2build.h> 10d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include FT_FREETYPE_H 119601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#else 129601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Mac OS X 139601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#include <ApplicationServices/ApplicationServices.h> // g++ -framework Cocoa 149601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#endif // __linux__ 159601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#else 169601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Windows 179601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// TODO(yusukes): Support Windows. 189601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#endif // _MSC_VER 199601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org 209601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#include <fcntl.h> 21d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <sys/stat.h> 22d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <sys/types.h> 238ad0a175fe440054932dd25ae9b4b1867e66d387yusukes@chromium.org#include <unistd.h> 24d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 25d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <cstdio> 26d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <cstdlib> 27d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <cstring> 28d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 29d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include "opentype-sanitiser.h" 30d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include "ots-memory-stream.h" 31d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 32d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgnamespace { 33d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 349601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#if !defined(_MSC_VER) 359601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#ifdef __linux__ 369601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Linux 37d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgvoid LoadChar(FT_Face face, int pt, FT_ULong c) { 38d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org FT_Matrix matrix; 39d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org matrix.xx = matrix.yy = 1 << 16; 40d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org matrix.xy = matrix.yx = 0 << 16; 41d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 42d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org FT_Set_Char_Size(face, pt * (1 << 6), 0, 72, 0); 43d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org FT_Set_Transform(face, &matrix, 0); 44d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org FT_Load_Char(face, c, FT_LOAD_RENDER); 45d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} 46d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 479601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.orgint OpenAndLoadChars( 489601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org const char *file_name, uint8_t *trans_font, size_t trans_len) { 499601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org FT_Library library; 509601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org FT_Error error = FT_Init_FreeType(&library); 519601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org if (error) { 529601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org std::fprintf(stderr, "Failed to initialize FreeType2!\n"); 539601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org return 1; 549601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org } 559601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org 56d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org FT_Face trans_face; 579601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org error = FT_New_Memory_Face(library, trans_font, trans_len, 0, &trans_face); 58d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (error) { 59d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::fprintf(stderr, 60d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org "OK: FreeType2 couldn't open the transcoded font: %s\n", 61d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org file_name); 62d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return 0; 63d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 64d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 65d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org static const int kPts[] = {100, 20, 18, 16, 12, 10, 8}; // pt 66d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org static const size_t kPtsLen = sizeof(kPts) / sizeof(kPts[0]); 67d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 68d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org static const int kUnicodeRanges[] = { 69d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 0x0020, 0x007E, // Basic Latin (ASCII) 70d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 0x00A1, 0x017F, // Latin-1 71d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 0x1100, 0x11FF, // Hangul 72d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 0x3040, 0x309F, // Japanese HIRAGANA letters 73d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 0x3130, 0x318F, // Hangul 74d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 0x4E00, 0x4F00, // CJK Kanji/Hanja 75d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 0xAC00, 0xAD00, // Hangul 76d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org }; 77d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org static const size_t kUnicodeRangesLen 78d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org = sizeof(kUnicodeRanges) / sizeof(kUnicodeRanges[0]); 79d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 80d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (size_t i = 0; i < kPtsLen; ++i) { 81d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (size_t j = 0; j < kUnicodeRangesLen; j += 2) { 82d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (int k = 0; k <= kUnicodeRanges[j + 1] - kUnicodeRanges[j]; ++k) { 83d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org LoadChar(trans_face, kPts[i], kUnicodeRanges[j] + k); 84d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 85d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 86d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 87d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 88d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::fprintf(stderr, "OK: FreeType2 didn't crash: %s\n", file_name); 89d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return 0; 90d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} 919601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#else 929601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Mac OS X 939601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.orgint OpenAndLoadChars( 949601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org const char *file_name, uint8_t *trans_font, size_t trans_len) { 952e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org CFDataRef data = CFDataCreate(0, trans_font, trans_len); 962e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org if (!data) { 979601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org std::fprintf(stderr, 989601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org "OK: font renderer couldn't open the transcoded font: %s\n", 999601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org file_name); 1009601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org return 0; 1019601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org } 1029601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org 1032e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); 1042e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider); 1052e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org CGDataProviderRelease(dataProvider); 1062e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org CFRelease(data); 1072e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org if (!cgFontRef) { 1089601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org std::fprintf(stderr, 1099601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org "OK: font renderer couldn't open the transcoded font: %s\n", 1109601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org file_name); 1119601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org return 0; 1129601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org } 1139601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org 1142e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org size_t numGlyphs = CGFontGetNumberOfGlyphs(cgFontRef); 1152e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org CGFontRelease(cgFontRef); 1162e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org if (!numGlyphs) { 1179601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org std::fprintf(stderr, 1189601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org "OK: font renderer couldn't open the transcoded font: %s\n", 1199601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org file_name); 1209601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org return 0; 1219601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org } 1229601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org std::fprintf(stderr, "OK: font renderer didn't crash: %s\n", file_name); 1239601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org // TODO(yusukes): would be better to perform LoadChar() like Linux. 1249601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org return 0; 1259601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org} 1269601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#endif // __linux__ 1279601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#else 1289601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Windows 1299601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// TODO(yusukes): Support Windows. 1309601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#endif // _MSC_VER 131d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 132d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} // namespace 133d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 134d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgint main(int argc, char **argv) { 135d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org ots::DisableDebugOutput(); // turn off ERROR and WARNING outputs. 136d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 137d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (argc != 2) { 138d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::fprintf(stderr, "Usage: %s ttf_or_otf_filename\n", argv[0]); 139d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return 1; 140d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 141d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 142d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // load the font to memory. 143d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const int fd = ::open(argv[1], O_RDONLY); 144d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (fd < 0) { 145d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org ::perror("open"); 146d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return 1; 147d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 148d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 149d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org struct stat st; 150d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org ::fstat(fd, &st); 151d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const off_t orig_len = st.st_size; 152d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 153d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org uint8_t *orig_font = new uint8_t[orig_len]; 154d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (::read(fd, orig_font, orig_len) != orig_len) { 155d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::fprintf(stderr, "Failed to read file!\n"); 156d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return 1; 157d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 158d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org ::close(fd); 159d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 160d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // transcode the malicious font. 161d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org static const size_t kBigPadLen = 1024 * 1024; // 1MB 162d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org uint8_t *trans_font = new uint8_t[orig_len + kBigPadLen]; 163d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org ots::MemoryStream output(trans_font, orig_len + kBigPadLen); 164d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 165d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org bool result = ots::Process(&output, orig_font, orig_len); 166d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!result) { 167d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::fprintf(stderr, "OK: the malicious font was filtered: %s\n", argv[1]); 168d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return 0; 169d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 170d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const size_t trans_len = output.Tell(); 171d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 1729601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org return OpenAndLoadChars(argv[1], trans_font, trans_len); 173d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} 174