OLD | NEW |
| (Empty) |
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 <ft2build.h> | |
9 #include FT_FREETYPE_H | |
10 #include FT_OUTLINE_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 if (argc != 2) { | |
136 std::fprintf(stderr, "Usage: %s ttf_or_otf_filename\n", argv[0]); | |
137 return 1; | |
138 } | |
139 | |
140 // load the font to memory. | |
141 const int fd = ::open(argv[1], O_RDONLY); | |
142 if (fd < 0) { | |
143 ::perror("open"); | |
144 return 1; | |
145 } | |
146 | |
147 struct stat st; | |
148 ::fstat(fd, &st); | |
149 const off_t orig_len = st.st_size; | |
150 | |
151 uint8_t *orig_font = new uint8_t[orig_len]; | |
152 if (::read(fd, orig_font, orig_len) != orig_len) { | |
153 std::fprintf(stderr, "Failed to read file!\n"); | |
154 return 1; | |
155 } | |
156 ::close(fd); | |
157 | |
158 // transcode the malicious font. | |
159 static const size_t kBigPadLen = 1024 * 1024; // 1MB | |
160 uint8_t *trans_font = new uint8_t[orig_len + kBigPadLen]; | |
161 ots::MemoryStream output(trans_font, orig_len + kBigPadLen); | |
162 ots::OTSContext context; | |
163 | |
164 bool result = context.Process(&output, orig_font, orig_len); | |
165 if (!result) { | |
166 std::fprintf(stderr, "OK: the malicious font was filtered: %s\n", argv[1]); | |
167 return 0; | |
168 } | |
169 const size_t trans_len = output.Tell(); | |
170 | |
171 return OpenAndLoadChars(argv[1], trans_font, trans_len); | |
172 } | |
OLD | NEW |