| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/elevation_service/elevated_recovery_impl.h" |
| |
| #include <windows.h> |
| #include <memory> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/path_service.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace elevation_service { |
| |
| namespace { |
| |
| // There is no exe in "valid_publisher.crx3", so we point to the manifest |
| // instead for these tests. |
| constexpr base::FilePath::CharType kManifestJSONFileName[] = |
| FILE_PATH_LITERAL("manifest.json"); |
| |
| // The SHA256 of the SubjectPublicKeyInfo used to sign "valid_publisher.crx3", |
| // which houses extension id ojjgnpkioondelmggbekfhllhdaimnho. |
| std::vector<uint8_t> GetValidPublisherCrx3Hash() { |
| return std::vector<uint8_t>{0xe9, 0x96, 0xdf, 0xa8, 0xee, 0xd3, 0x4b, 0xc6, |
| 0x61, 0x4a, 0x57, 0xbb, 0x73, 0x08, 0xcd, 0x7e, |
| 0x51, 0x9b, 0xcc, 0x69, 0x08, 0x41, 0xe1, 0x96, |
| 0x9f, 0x7c, 0xb1, 0x73, 0xef, 0x16, 0x80, 0x0a}; |
| } |
| |
| // The test exe within components/test/data/update_client/ChromeRecovery.crx3. |
| constexpr base::FilePath::CharType kRecoveryExeName[] = |
| FILE_PATH_LITERAL("ChromeRecovery.exe"); |
| |
| // The SHA256 of the SubjectPublicKeyInfo used to sign |
| // components/test/data/update_client/ChromeRecovery.crx3. |
| std::vector<uint8_t> GetRunactionTestWinCrx3Hash() { |
| return std::vector<uint8_t>{0x69, 0xfc, 0x41, 0xf6, 0x17, 0x20, 0xc6, 0x36, |
| 0x92, 0xcd, 0x95, 0x76, 0x69, 0xf6, 0x28, 0xcc, |
| 0xbe, 0x98, 0x4b, 0x93, 0x17, 0xd6, 0x9c, 0xb3, |
| 0x64, 0x0c, 0x0d, 0x25, 0x61, 0xc5, 0x80, 0x1d}; |
| } |
| |
| const base::FilePath GetUnpackDir() { |
| base::FilePath path; |
| base::PathService::Get(base::DIR_TEMP, &path); |
| return path; |
| } |
| |
| const base::FilePath TestFile(const std::string& file) { |
| base::FilePath path; |
| base::PathService::Get(base::DIR_MODULE, &path); |
| return path.AppendASCII("elevated_recovery_unittest") |
| .AppendASCII(file); |
| } |
| |
| } // namespace |
| |
| TEST(ElevatedRecoveryTest, Do_RunChromeRecoveryCRX_InvalidArgs) { |
| base::win::ScopedHandle proc_handle; |
| |
| // Empty browser_appid/browser_version/session_id. |
| EXPECT_EQ(E_INVALIDARG, |
| elevation_service::RunChromeRecoveryCRX( |
| TestFile("valid_publisher.crx3"), base::string16(), |
| base::string16(), base::string16(), 0, &proc_handle)); |
| |
| // Invalid browser_appid, valid browser_version/session_id. |
| EXPECT_EQ(E_INVALIDARG, |
| elevation_service::RunChromeRecoveryCRX( |
| TestFile("valid_publisher.crx3"), L"invalidappid", |
| L"1.2.3.4", L"{c49ab053-2387-4809-b188-1902648802e1}", 0, |
| &proc_handle)); |
| |
| // Empty browser_appid, invalid browser_version, valid session_id. |
| EXPECT_EQ(E_INVALIDARG, |
| elevation_service::RunChromeRecoveryCRX( |
| TestFile("valid_publisher.crx3"), base::string16(), |
| L"invalidbrowserversion", |
| L"{c49ab053-2387-4809-b188-1902648802e1}", 0, &proc_handle)); |
| |
| // Valid browser_appid, invalid browser_version, valid session_id. |
| EXPECT_EQ( |
| E_INVALIDARG, |
| elevation_service::RunChromeRecoveryCRX( |
| TestFile("valid_publisher.crx3"), |
| L"{c49ab053-2387-4809-b188-1902648802e1}", L"invalidbrowserversion", |
| L"{c49ab053-2387-4809-b188-1902648802e1}", 0, &proc_handle)); |
| |
| // Valid browser_appid, valid browser_version, invalid session_id. |
| EXPECT_EQ(E_INVALIDARG, |
| elevation_service::RunChromeRecoveryCRX( |
| TestFile("valid_publisher.crx3"), |
| L"{c49ab053-2387-4809-b188-1902648802e1}", L"57.8.0.1", |
| L"invalidsessionid", 0, &proc_handle)); |
| } |
| |
| TEST(ElevatedRecoveryTest, Do_RunCRX_InvalidArgs) { |
| base::win::ScopedHandle proc_handle; |
| |
| // Non-matching CRX/CRX-hash. |
| EXPECT_EQ(CRYPT_E_NO_MATCH, |
| elevation_service::RunCRX( |
| TestFile("valid_no_publisher.crx3"), |
| base::CommandLine(base::CommandLine::NO_PROGRAM), |
| crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF, |
| GetValidPublisherCrx3Hash(), GetUnpackDir(), |
| base::FilePath(kManifestJSONFileName), 0, &proc_handle)); |
| |
| // Non-existent CRX file. |
| EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), |
| elevation_service::RunCRX( |
| TestFile("nonexistent.crx3"), |
| base::CommandLine(base::CommandLine::NO_PROGRAM), |
| crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF, |
| GetValidPublisherCrx3Hash(), GetUnpackDir(), |
| base::FilePath(kManifestJSONFileName), 0, &proc_handle)); |
| |
| // manifest.json is not a Windows executable, ::CreateProcess therefore |
| // returns ERROR_BAD_EXE_FORMAT. |
| EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT), |
| elevation_service::RunCRX( |
| TestFile("valid_publisher.crx3"), |
| base::CommandLine(base::CommandLine::NO_PROGRAM), |
| crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF, |
| GetValidPublisherCrx3Hash(), GetUnpackDir(), |
| base::FilePath(kManifestJSONFileName), 0, &proc_handle)); |
| } |
| |
| TEST(ElevatedRecoveryTest, Do_RunCRX_ValidArgs) { |
| base::win::ScopedHandle proc_handle; |
| |
| // ChromeRecovery.crx3 contains ChromeRecovery.exe which returns a hardcoded |
| // value of 1877345072. |
| EXPECT_EQ(S_OK, elevation_service::RunCRX( |
| TestFile("ChromeRecovery.crx3"), |
| base::CommandLine(base::CommandLine::NO_PROGRAM), |
| crx_file::VerifierFormat::CRX3, |
| GetRunactionTestWinCrx3Hash(), GetUnpackDir(), |
| base::FilePath(kRecoveryExeName), 0, &proc_handle)); |
| |
| EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(proc_handle.Get(), 500)); |
| DWORD exit_code = 0; |
| EXPECT_TRUE(::GetExitCodeProcess(proc_handle.Get(), &exit_code)); |
| EXPECT_EQ(1877345072UL, exit_code); |
| } |
| |
| TEST(ElevatedRecoveryTest, Do_CleanupChromeRecoveryDirectory) { |
| base::FilePath recovery_dir; |
| ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &recovery_dir)); |
| recovery_dir = recovery_dir.DirName().DirName().Append( |
| FILE_PATH_LITERAL("ChromeRecovery")); |
| ASSERT_TRUE(base::CreateDirectory(recovery_dir)); |
| |
| base::FilePath temp_file; |
| ASSERT_TRUE(base::CreateTemporaryFileInDir(recovery_dir, &temp_file)); |
| ASSERT_TRUE(base::CreateTemporaryFileInDir(recovery_dir, &temp_file)); |
| ASSERT_TRUE(base::CreateTemporaryFileInDir(recovery_dir, &temp_file)); |
| |
| base::ScopedTempDir scoped_dir; |
| ASSERT_TRUE(scoped_dir.CreateUniqueTempDirUnderPath(recovery_dir)); |
| ASSERT_TRUE(base::CreateTemporaryFileInDir(scoped_dir.GetPath(), &temp_file)); |
| ASSERT_TRUE(base::CreateTemporaryFileInDir(scoped_dir.GetPath(), &temp_file)); |
| |
| EXPECT_EQ(S_OK, elevation_service::CleanupChromeRecoveryDirectory()); |
| |
| EXPECT_TRUE(base::PathExists(recovery_dir)); |
| EXPECT_TRUE(base::IsDirectoryEmpty(recovery_dir)); |
| } |
| |
| } // namespace elevation_service |