15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <stdint.h>
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <windows.h>
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <algorithm>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <vector>
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/base_paths.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/basictypes.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/compiler_specific.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/files/file_path.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/files/memory_mapped_file.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/path_service.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_util.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/win/pe_image.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class ELFImportsTest : public testing::Test {
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) protected:
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static bool ImportsCallback(const base::win::PEImage &image,
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              LPCSTR module,
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              PIMAGE_THUNK_DATA name_table,
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              PIMAGE_THUNK_DATA iat,
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              PVOID cookie) {
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<std::string>* import_list =
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reinterpret_cast<std::vector<std::string>*>(cookie);
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    import_list->push_back(module);
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void GetImports(const base::FilePath& module_path,
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  std::vector<std::string>* imports) {
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_TRUE(imports != NULL);
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::MemoryMappedFile module_mmap;
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_TRUE(module_mmap.Initialize(module_path));
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::win::PEImageAsData pe_image_data(
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reinterpret_cast<HMODULE>(const_cast<uint8*>(module_mmap.data())));
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    pe_image_data.EnumImportChunks(ELFImportsTest::ImportsCallback, imports);
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(ELFImportsTest, ChromeElfSanityCheck) {
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string> elf_imports;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath dll;
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(PathService::Get(base::DIR_EXE, &dll));
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dll = dll.Append(L"chrome_elf.dll");
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GetImports(dll, &elf_imports);
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Check that ELF has imports.
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_LT(0u, elf_imports.size()) << "Ensure the chrome_elf_unittests "
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "target was built, instead of chrome_elf_unittests.exe";
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string>::iterator it(elf_imports.begin());
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const char* const kValidFilePatterns[] = {
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    "KERNEL32.dll",
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    "MSVC*",
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#if defined(SYZYASAN)
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    "syzyasan_rtl.dll",
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    "ADVAPI32.dll"
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  };
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Make sure all of ELF's imports are in the valid imports list.
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (; it != elf_imports.end(); it++) {
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool match = false;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (int i = 0; i < arraysize(kValidFilePatterns); ++i) {
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (MatchPattern(*it, kValidFilePatterns[i]))
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        match = true;
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_TRUE(match) << "Illegal import in chrome_elf.dll.";
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(ELFImportsTest, ChromeExeSanityCheck) {
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string> exe_imports;
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath exe;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(PathService::Get(base::DIR_EXE, &exe));
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  exe = exe.Append(L"chrome.exe");
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GetImports(exe, &exe_imports);
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Check that chrome.exe has imports.
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_LT(0u, exe_imports.size()) << "Ensure the chrome_elf_unittests "
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "target was built, instead of chrome_elf_unittests.exe";
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Chrome.exe's first import must be ELF.
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("chrome_elf.dll", exe_imports[0]) <<
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Illegal import order in chrome.exe (ensure the chrome_elf_unittest "
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "target was built, instead of just chrome_elf_unittests.exe)";
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
102