1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #if !defined(_MSC_VER) 6 #ifdef __linux__ 7 // Linux 8 #include <freetype/ftoutln.h> 9 #include <ft2build.h> 10 #include FT_FREETYPE_H 11 #else 12 // Mac OS X 13 #include <ApplicationServices/ApplicationServices.h> // g++ -framework Cocoa 14 #endif // __linux__ 15 #else 16 // Windows 17 // TODO(yusukes): Support Windows. 18 #endif // _MSC_VER 19 20 #include <fcntl.h> 21 #include <sys/stat.h> 22 #include <sys/types.h> 23 #include <unistd.h> 24 25 #include <cstdio> 26 #include <cstdlib> 27 #include <cstring> 28 29 #include "opentype-sanitiser.h" 30 #include "ots-memory-stream.h" 31 32 namespace { 33 34 #if !defined(_MSC_VER) 35 #ifdef __linux__ 36 // Linux 37 void LoadChar(FT_Face face, int pt, FT_ULong c) { 38 FT_Matrix matrix; 39 matrix.xx = matrix.yy = 1 << 16; 40 matrix.xy = matrix.yx = 0 << 16; 41 42 FT_Set_Char_Size(face, pt * (1 << 6), 0, 72, 0); 43 FT_Set_Transform(face, &matrix, 0); 44 FT_Load_Char(face, c, FT_LOAD_RENDER); 45 } 46 47 int OpenAndLoadChars( 48 const char *file_name, uint8_t *trans_font, size_t trans_len) { 49 FT_Library library; 50 FT_Error error = FT_Init_FreeType(&library); 51 if (error) { 52 std::fprintf(stderr, "Failed to initialize FreeType2!\n"); 53 return 1; 54 } 55 56 FT_Face trans_face; 57 error = FT_New_Memory_Face(library, trans_font, trans_len, 0, &trans_face); 58 if (error) { 59 std::fprintf(stderr, 60 "OK: FreeType2 couldn't open the transcoded font: %s\n", 61 file_name); 62 return 0; 63 } 64 65 static const int kPts[] = {100, 20, 18, 16, 12, 10, 8}; // pt 66 static const size_t kPtsLen = sizeof(kPts) / sizeof(kPts[0]); 67 68 static const int kUnicodeRanges[] = { 69 0x0020, 0x007E, // Basic Latin (ASCII) 70 0x00A1, 0x017F, // Latin-1 71 0x1100, 0x11FF, // Hangul 72 0x3040, 0x309F, // Japanese HIRAGANA letters 73 0x3130, 0x318F, // Hangul 74 0x4E00, 0x4F00, // CJK Kanji/Hanja 75 0xAC00, 0xAD00, // Hangul 76 }; 77 static const size_t kUnicodeRangesLen 78 = sizeof(kUnicodeRanges) / sizeof(kUnicodeRanges[0]); 79 80 for (size_t i = 0; i < kPtsLen; ++i) { 81 for (size_t j = 0; j < kUnicodeRangesLen; j += 2) { 82 for (int k = 0; k <= kUnicodeRanges[j + 1] - kUnicodeRanges[j]; ++k) { 83 LoadChar(trans_face, kPts[i], kUnicodeRanges[j] + k); 84 } 85 } 86 } 87 88 std::fprintf(stderr, "OK: FreeType2 didn't crash: %s\n", file_name); 89 return 0; 90 } 91 #else 92 // Mac OS X 93 int OpenAndLoadChars( 94 const char *file_name, uint8_t *trans_font, size_t trans_len) { 95 CFDataRef data = CFDataCreate(0, trans_font, trans_len); 96 if (!data) { 97 std::fprintf(stderr, 98 "OK: font renderer couldn't open the transcoded font: %s\n", 99 file_name); 100 return 0; 101 } 102 103 CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); 104 CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider); 105 CGDataProviderRelease(dataProvider); 106 CFRelease(data); 107 if (!cgFontRef) { 108 std::fprintf(stderr, 109 "OK: font renderer couldn't open the transcoded font: %s\n", 110 file_name); 111 return 0; 112 } 113 114 size_t numGlyphs = CGFontGetNumberOfGlyphs(cgFontRef); 115 CGFontRelease(cgFontRef); 116 if (!numGlyphs) { 117 std::fprintf(stderr, 118 "OK: font renderer couldn't open the transcoded font: %s\n", 119 file_name); 120 return 0; 121 } 122 std::fprintf(stderr, "OK: font renderer didn't crash: %s\n", file_name); 123 // TODO(yusukes): would be better to perform LoadChar() like Linux. 124 return 0; 125 } 126 #endif // __linux__ 127 #else 128 // Windows 129 // TODO(yusukes): Support Windows. 130 #endif // _MSC_VER 131 132 } // namespace 133 134 int main(int argc, char **argv) { 135 ots::DisableDebugOutput(); // turn off ERROR and WARNING outputs. 136 137 if (argc != 2) { 138 std::fprintf(stderr, "Usage: %s ttf_or_otf_filename\n", argv[0]); 139 return 1; 140 } 141 142 // load the font to memory. 143 const int fd = ::open(argv[1], O_RDONLY); 144 if (fd < 0) { 145 ::perror("open"); 146 return 1; 147 } 148 149 struct stat st; 150 ::fstat(fd, &st); 151 const off_t orig_len = st.st_size; 152 153 uint8_t *orig_font = new uint8_t[orig_len]; 154 if (::read(fd, orig_font, orig_len) != orig_len) { 155 std::fprintf(stderr, "Failed to read file!\n"); 156 return 1; 157 } 158 ::close(fd); 159 160 // transcode the malicious font. 161 static const size_t kBigPadLen = 1024 * 1024; // 1MB 162 uint8_t *trans_font = new uint8_t[orig_len + kBigPadLen]; 163 ots::MemoryStream output(trans_font, orig_len + kBigPadLen); 164 165 bool result = ots::Process(&output, orig_font, orig_len); 166 if (!result) { 167 std::fprintf(stderr, "OK: the malicious font was filtered: %s\n", argv[1]); 168 return 0; 169 } 170 const size_t trans_len = output.Tell(); 171 172 return OpenAndLoadChars(argv[1], trans_font, trans_len); 173 } 174