This sets up API to release OutputSurface from LTHClient.
[chromium-blink-merge.git] / chrome / common / safe_browsing / mach_o_image_reader_mac_unittest.cc
blobde01cdc717f2cb06897fe17bf7d703ea314158cb
1 // Copyright 2015 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.
5 #include "chrome/common/safe_browsing/mach_o_image_reader_mac.h"
7 #include <arpa/inet.h>
8 #include <libkern/OSByteOrder.h>
9 #include <mach-o/fat.h>
10 #include <mach-o/loader.h>
11 #include <string.h>
12 #include <uuid/uuid.h>
14 #include "base/files/file_path.h"
15 #include "base/files/memory_mapped_file.h"
16 #include "base/path_service.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/stringprintf.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 namespace safe_browsing {
23 namespace {
25 // Definitions from
26 // <http://opensource.apple.com/source/xnu/xnu-2782.1.97/bsd/sys/codesign.h>.
28 enum {
29 CSMAGIC_CODEDIRECTORY = 0xfade0c02,
30 CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0,
32 CSSLOT_CODEDIRECTORY = 0,
35 struct CodeSigningBlob {
36 uint32_t type;
37 uint32_t offset;
40 struct CodeSigningSuperBlob {
41 uint32_t magic;
42 uint32_t length;
43 uint32_t count;
44 CodeSigningBlob index[];
47 struct CodeSigningDirectory {
48 uint32_t magic;
49 uint32_t length;
50 uint32_t version;
51 uint32_t flags;
52 uint32_t hashOffset;
53 uint32_t identOffset;
54 uint32_t nSpecialSlots;
55 uint32_t nCodeSlots;
56 uint32_t codeLimit;
57 uint8_t hashSize;
58 uint8_t hashType;
59 uint8_t spare1;
60 uint8_t pageSize;
61 uint32_t spare2;
62 // Version 0x20100.
63 uint32_t scatterOffset;
64 // Version 0x20200.
65 uint32_t teamOffset;
68 class MachOImageReaderTest : public testing::Test {
69 protected:
70 void OpenTestFile(const char* file_name, base::MemoryMappedFile* file) {
71 base::FilePath test_data;
72 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data));
74 base::FilePath path = test_data.AppendASCII("safe_browsing")
75 .AppendASCII("mach_o")
76 .AppendASCII(file_name);
78 ASSERT_TRUE(file->Initialize(path));
81 // Returns the identity of the signed code data.
82 void GetSigningIdentity(const std::vector<uint8_t>& signature,
83 std::string* identity) {
84 auto super_blob =
85 reinterpret_cast<const CodeSigningSuperBlob*>(&signature[0]);
86 EXPECT_EQ(CSMAGIC_EMBEDDED_SIGNATURE, ntohl(super_blob->magic));
87 ASSERT_EQ(CSSLOT_CODEDIRECTORY, ntohl(super_blob->index[0].type));
88 size_t dir_offset = ntohl(super_blob->index[0].offset);
89 auto directory =
90 reinterpret_cast<const CodeSigningDirectory*>(&signature[dir_offset]);
91 ASSERT_EQ(CSMAGIC_CODEDIRECTORY, ntohl(directory->magic));
92 size_t ident_offset = ntohl(directory->identOffset) + dir_offset;
93 *identity =
94 std::string(reinterpret_cast<const char*>(&signature[ident_offset]));
97 // Returns the hash of the code data itself. Note that this is not the
98 // CDHash, but is instead the hash in the CodeDirectory blob, which is
99 // over the contents of the signed data. This is visible as hash #0
100 // when using `codesign -d -vvvvvv`.
101 void GetCodeSignatureHash(const std::vector<uint8_t>& signature,
102 std::vector<uint8_t>* hash) {
103 auto super_blob =
104 reinterpret_cast<const CodeSigningSuperBlob*>(&signature[0]);
105 EXPECT_EQ(CSMAGIC_EMBEDDED_SIGNATURE, ntohl(super_blob->magic));
106 ASSERT_EQ(CSSLOT_CODEDIRECTORY, ntohl(super_blob->index[0].type));
107 size_t dir_offset = ntohl(super_blob->index[0].offset);
108 auto directory =
109 reinterpret_cast<const CodeSigningDirectory*>(&signature[dir_offset]);
110 ASSERT_EQ(CSMAGIC_CODEDIRECTORY, ntohl(directory->magic));
111 size_t hash_offset = ntohl(directory->hashOffset) + dir_offset;
112 std::vector<uint8_t> actual_hash(&signature[hash_offset],
113 &signature[hash_offset + directory->hashSize]);
114 EXPECT_EQ(20u, actual_hash.size());
115 *hash = actual_hash;
118 void ExpectCodeSignatureHash(const std::vector<uint8_t>& signature,
119 const char* expected) {
120 std::vector<uint8_t> actual_hash;
121 GetCodeSignatureHash(signature, &actual_hash);
123 std::vector<uint8_t> expected_hash;
124 ASSERT_TRUE(base::HexStringToBytes(expected, &expected_hash));
125 EXPECT_EQ(expected_hash, actual_hash);
129 TEST_F(MachOImageReaderTest, Executable32) {
130 base::MemoryMappedFile file;
131 ASSERT_NO_FATAL_FAILURE(OpenTestFile("executable32", &file));
132 MachOImageReader reader;
133 ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
135 EXPECT_FALSE(reader.IsFat());
136 EXPECT_FALSE(reader.Is64Bit());
137 EXPECT_TRUE(reader.GetMachHeader());
138 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.GetFileType());
139 EXPECT_EQ(15u, reader.GetLoadCommands().size());
141 std::vector<uint8_t> signature;
142 EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
143 EXPECT_TRUE(signature.empty());
145 // Test an arbitrary load command.
146 auto commands = reader.GetLoadCommands();
147 ASSERT_EQ(15u, commands.size());
148 auto command = commands[11];
149 ASSERT_EQ(static_cast<uint32_t>(LC_LOAD_DYLIB), command.cmd());
150 auto actual = command.as_command<dylib_command>();
151 EXPECT_EQ(2u, actual->dylib.timestamp);
152 EXPECT_EQ(0x4ad0101u, actual->dylib.current_version);
153 EXPECT_EQ(0x10000u, actual->dylib.compatibility_version);
156 TEST_F(MachOImageReaderTest, Executable64) {
157 base::MemoryMappedFile file;
158 ASSERT_NO_FATAL_FAILURE(OpenTestFile("executable64", &file));
159 MachOImageReader reader;
160 ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
162 EXPECT_FALSE(reader.IsFat());
163 EXPECT_TRUE(reader.Is64Bit());
164 EXPECT_TRUE(reader.GetMachHeader());
165 EXPECT_TRUE(reader.GetMachHeader64());
166 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.GetFileType());
167 EXPECT_EQ(15u, reader.GetLoadCommands().size());
169 std::vector<uint8_t> signature;
170 EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
171 EXPECT_TRUE(signature.empty());
174 TEST_F(MachOImageReaderTest, ExecutableFat) {
175 base::MemoryMappedFile file;
176 ASSERT_NO_FATAL_FAILURE(OpenTestFile("executablefat", &file));
177 MachOImageReader reader;
178 ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
180 EXPECT_TRUE(reader.IsFat());
181 auto images = reader.GetFatImages();
182 ASSERT_EQ(2u, images.size());
184 // Note: this image is crafted to have 32-bit first.
186 EXPECT_FALSE(images[0]->IsFat());
187 EXPECT_FALSE(images[0]->Is64Bit());
188 EXPECT_TRUE(images[0]->GetMachHeader());
189 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[0]->GetFileType());
191 std::vector<uint8_t> signature;
192 EXPECT_FALSE(images[0]->GetCodeSignatureInfo(&signature));
193 EXPECT_TRUE(signature.empty());
197 EXPECT_FALSE(images[1]->IsFat());
198 EXPECT_TRUE(images[1]->Is64Bit());
199 EXPECT_TRUE(images[1]->GetMachHeader());
200 EXPECT_TRUE(images[1]->GetMachHeader64());
201 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[1]->GetFileType());
203 std::vector<uint8_t> signature;
204 EXPECT_FALSE(images[1]->GetCodeSignatureInfo(&signature));
205 EXPECT_TRUE(signature.empty());
207 // Test an arbitrary load command.
208 auto commands = images[1]->GetLoadCommands();
209 ASSERT_EQ(15u, commands.size());
210 auto command = commands[1];
211 ASSERT_EQ(static_cast<uint32_t>(LC_SEGMENT_64), command.cmd());
212 auto actual = command.as_command<segment_command_64>();
213 EXPECT_EQ("__TEXT", std::string(actual->segname));
214 EXPECT_EQ(0u, actual->fileoff);
215 EXPECT_EQ(4096u, actual->filesize);
216 EXPECT_EQ(0x7, actual->maxprot);
217 EXPECT_EQ(0x5, actual->initprot);
218 EXPECT_EQ(3u, actual->nsects);
219 EXPECT_EQ(0u, actual->flags);
223 TEST_F(MachOImageReaderTest, ExecutablePPC) {
224 base::MemoryMappedFile file;
225 ASSERT_NO_FATAL_FAILURE(OpenTestFile("executableppc", &file));
226 MachOImageReader reader;
227 ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
229 EXPECT_FALSE(reader.IsFat());
230 EXPECT_FALSE(reader.Is64Bit());
231 EXPECT_TRUE(reader.GetMachHeader());
232 EXPECT_EQ(OSSwapInt32(MH_EXECUTE), reader.GetFileType());
233 EXPECT_EQ(10u, reader.GetLoadCommands().size());
235 std::vector<uint8_t> signature;
236 EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
237 EXPECT_TRUE(signature.empty());
240 TEST_F(MachOImageReaderTest, Dylib32) {
241 base::MemoryMappedFile file;
242 ASSERT_NO_FATAL_FAILURE(OpenTestFile("lib32.dylib", &file));
243 MachOImageReader reader;
244 ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
246 EXPECT_FALSE(reader.IsFat());
247 EXPECT_FALSE(reader.Is64Bit());
248 EXPECT_TRUE(reader.GetMachHeader());
249 EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), reader.GetFileType());
250 EXPECT_EQ(13u, reader.GetLoadCommands().size());
252 std::vector<uint8_t> signature;
253 EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
254 EXPECT_TRUE(signature.empty());
257 TEST_F(MachOImageReaderTest, Dylib64) {
258 base::MemoryMappedFile file;
259 ASSERT_NO_FATAL_FAILURE(OpenTestFile("lib64.dylib", &file));
260 MachOImageReader reader;
261 ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
263 EXPECT_FALSE(reader.IsFat());
264 EXPECT_TRUE(reader.Is64Bit());
265 EXPECT_TRUE(reader.GetMachHeader());
266 EXPECT_TRUE(reader.GetMachHeader64());
267 EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), reader.GetFileType());
268 EXPECT_EQ(13u, reader.GetLoadCommands().size());
270 std::vector<uint8_t> signature;
271 EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
272 EXPECT_TRUE(signature.empty());
274 // Test an arbitrary load command.
275 auto commands = reader.GetLoadCommands();
276 ASSERT_EQ(13u, commands.size());
277 auto command = commands[6];
278 ASSERT_EQ(static_cast<uint32_t>(LC_UUID), command.cmd());
279 uuid_t expected = {0xB6, 0xB5, 0x12, 0xD7,
280 0x64, 0xE9,
281 0x3F, 0x7A,
282 0xAB, 0x4A,
283 0x87, 0x46, 0x36, 0x76, 0x87, 0x47};
284 EXPECT_EQ(0, uuid_compare(expected,
285 command.as_command<uuid_command>()->uuid));
288 TEST_F(MachOImageReaderTest, DylibFat) {
289 base::MemoryMappedFile file;
290 ASSERT_NO_FATAL_FAILURE(OpenTestFile("libfat.dylib", &file));
291 MachOImageReader reader;
292 ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
294 EXPECT_TRUE(reader.IsFat());
295 auto images = reader.GetFatImages();
296 ASSERT_EQ(2u, images.size());
298 // Note: this image is crafted to have 64-bit first.
300 EXPECT_FALSE(images[0]->IsFat());
301 EXPECT_TRUE(images[0]->Is64Bit());
302 EXPECT_TRUE(images[0]->GetMachHeader());
303 EXPECT_TRUE(images[0]->GetMachHeader64());
304 EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), images[0]->GetFileType());
306 std::vector<uint8_t> signature;
307 EXPECT_FALSE(images[0]->GetCodeSignatureInfo(&signature));
308 EXPECT_TRUE(signature.empty());
312 EXPECT_FALSE(images[1]->IsFat());
313 EXPECT_FALSE(images[1]->Is64Bit());
314 EXPECT_TRUE(images[1]->GetMachHeader());
315 EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), images[1]->GetFileType());
317 std::vector<uint8_t> signature;
318 EXPECT_FALSE(images[1]->GetCodeSignatureInfo(&signature));
319 EXPECT_TRUE(signature.empty());
323 TEST_F(MachOImageReaderTest, SignedExecutable32) {
324 base::MemoryMappedFile file;
325 ASSERT_NO_FATAL_FAILURE(OpenTestFile("signedexecutable32", &file));
326 MachOImageReader reader;
327 ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
329 EXPECT_FALSE(reader.IsFat());
330 EXPECT_FALSE(reader.Is64Bit());
331 EXPECT_TRUE(reader.GetMachHeader());
332 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.GetFileType());
333 EXPECT_EQ(16u, reader.GetLoadCommands().size());
335 std::vector<uint8_t> signature;
336 EXPECT_TRUE(reader.GetCodeSignatureInfo(&signature));
337 EXPECT_EQ(9344u, signature.size());
339 std::string identity;
340 GetSigningIdentity(signature, &identity);
341 EXPECT_EQ("signedexecutable32", identity);
343 ExpectCodeSignatureHash(signature,
344 "11fb88eb63c10dfc3d24a2545ea2a9c50c2921b5");
347 TEST_F(MachOImageReaderTest, SignedExecutableFat) {
348 base::MemoryMappedFile file;
349 ASSERT_NO_FATAL_FAILURE(OpenTestFile("signedexecutablefat", &file));
350 MachOImageReader reader;
351 ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
353 EXPECT_TRUE(reader.IsFat());
354 auto images = reader.GetFatImages();
355 ASSERT_EQ(2u, images.size());
357 // Note: this image is crafted to have 32-bit first.
359 EXPECT_FALSE(images[0]->IsFat());
360 EXPECT_FALSE(images[0]->Is64Bit());
361 EXPECT_TRUE(images[0]->GetMachHeader());
362 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[0]->GetFileType());
364 std::vector<uint8_t> signature;
365 EXPECT_TRUE(images[0]->GetCodeSignatureInfo(&signature));
366 EXPECT_EQ(9344u, signature.size());
368 std::string identity;
369 GetSigningIdentity(signature, &identity);
370 EXPECT_EQ("signedexecutablefat", identity);
372 ExpectCodeSignatureHash(signature,
373 "11fb88eb63c10dfc3d24a2545ea2a9c50c2921b5");
377 EXPECT_FALSE(images[1]->IsFat());
378 EXPECT_TRUE(images[1]->Is64Bit());
379 EXPECT_TRUE(images[1]->GetMachHeader());
380 EXPECT_TRUE(images[1]->GetMachHeader64());
381 EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[1]->GetFileType());
383 std::vector<uint8_t> signature;
384 EXPECT_TRUE(images[1]->GetCodeSignatureInfo(&signature));
385 EXPECT_EQ(9344u, signature.size());
387 std::string identity;
388 GetSigningIdentity(signature, &identity);
389 EXPECT_EQ("signedexecutablefat", identity);
391 ExpectCodeSignatureHash(signature,
392 "750a57326ba85857371094900475defd837f5e14");
396 TEST_F(MachOImageReaderTest, SignedDylib64) {
397 base::MemoryMappedFile file;
398 ASSERT_NO_FATAL_FAILURE(OpenTestFile("libsigned64.dylib", &file));
399 MachOImageReader reader;
400 ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
402 EXPECT_FALSE(reader.IsFat());
403 EXPECT_TRUE(reader.Is64Bit());
404 EXPECT_TRUE(reader.GetMachHeader());
405 EXPECT_TRUE(reader.GetMachHeader64());
406 EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), reader.GetFileType());
407 EXPECT_EQ(14u, reader.GetLoadCommands().size());
409 std::vector<uint8_t> signature;
410 EXPECT_TRUE(reader.GetCodeSignatureInfo(&signature));
411 EXPECT_EQ(9328u, signature.size());
413 std::string identity;
414 GetSigningIdentity(signature, &identity);
415 EXPECT_EQ("libsigned64", identity);
417 ExpectCodeSignatureHash(signature,
418 "8b1c79b60bb53a7f17b5618d5feb10dc8b88d806");
421 TEST_F(MachOImageReaderTest, NotMachO) {
422 base::MemoryMappedFile file;
423 ASSERT_NO_FATAL_FAILURE(OpenTestFile("src.c", &file));
424 MachOImageReader reader;
425 EXPECT_FALSE(reader.Initialize(file.data(), file.length()));
428 TEST_F(MachOImageReaderTest, IsMachOMagicValue) {
429 static const uint32_t kMagics[] = { MH_MAGIC, MH_MAGIC, FAT_MAGIC };
430 for (uint32_t magic : kMagics) {
431 SCOPED_TRACE(base::StringPrintf("0x%x", magic));
432 EXPECT_TRUE(MachOImageReader::IsMachOMagicValue(magic));
433 EXPECT_TRUE(MachOImageReader::IsMachOMagicValue(OSSwapInt32(magic)));
437 // https://crbug.com/524044
438 TEST_F(MachOImageReaderTest, CmdsizeSmallerThanLoadCommand) {
439 #pragma pack(push, 1)
440 struct TestImage {
441 mach_header_64 header;
442 segment_command_64 page_zero;
443 load_command small_sized;
444 segment_command_64 fake_code;
446 #pragma pack(pop)
448 TestImage test_image = {};
450 test_image.header.magic = MH_MAGIC_64;
451 test_image.header.cputype = CPU_TYPE_X86_64;
452 test_image.header.filetype = MH_EXECUTE;
453 test_image.header.ncmds = 3;
454 test_image.header.sizeofcmds = sizeof(test_image) - sizeof(test_image.header);
456 test_image.page_zero.cmd = LC_SEGMENT;
457 test_image.page_zero.cmdsize = sizeof(test_image.page_zero);
458 strcpy(test_image.page_zero.segname, SEG_PAGEZERO);
459 test_image.page_zero.vmsize = PAGE_SIZE;
461 test_image.small_sized.cmd = LC_SYMSEG;
462 test_image.small_sized.cmdsize = sizeof(test_image.small_sized) - 3;
464 test_image.fake_code.cmd = LC_SEGMENT;
465 test_image.fake_code.cmdsize = sizeof(test_image.fake_code);
466 strcpy(test_image.fake_code.segname, SEG_TEXT);
468 MachOImageReader reader;
469 EXPECT_TRUE(reader.Initialize(reinterpret_cast<const uint8_t*>(&test_image),
470 sizeof(test_image)));
472 EXPECT_FALSE(reader.IsFat());
473 EXPECT_TRUE(reader.Is64Bit());
475 const auto& load_commands = reader.GetLoadCommands();
476 EXPECT_EQ(3u, load_commands.size());
478 EXPECT_EQ(static_cast<uint32_t>(LC_SEGMENT), load_commands[0].cmd());
479 EXPECT_EQ(static_cast<uint32_t>(LC_SYMSEG), load_commands[1].cmd());
480 EXPECT_EQ(sizeof(load_command) - 3, load_commands[1].cmdsize());
481 EXPECT_EQ(static_cast<uint32_t>(LC_SEGMENT), load_commands[2].cmd());
484 } // namespace
485 } // namespace safe_browsing