Index: chrome_frame/test/dll_redirector_test.cc |
diff --git a/chrome_frame/test/dll_redirector_test.cc b/chrome_frame/test/dll_redirector_test.cc |
deleted file mode 100644 |
index 104eba273d83aef9f7572aa56d286416e39a2057..0000000000000000000000000000000000000000 |
--- a/chrome_frame/test/dll_redirector_test.cc |
+++ /dev/null |
@@ -1,395 +0,0 @@ |
-// Copyright (c) 2012 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_frame/dll_redirector.h" |
- |
-#include "base/memory/shared_memory.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "base/version.h" |
-#include "base/win/scoped_handle.h" |
-#include "base/win/windows_version.h" |
-#include "chrome_frame/test/chrome_frame_test_utils.h" |
-#include "gtest/gtest.h" |
- |
-extern "C" IMAGE_DOS_HEADER __ImageBase; |
- |
-const char kMockVersionString[] = "42.42.42.42"; |
-const char kMockVersionString2[] = "133.33.33.7"; |
- |
-const HMODULE kMockModuleHandle = reinterpret_cast<HMODULE>(42); |
-const HMODULE kMockModuleHandle2 = reinterpret_cast<HMODULE>(43); |
- |
-const char kTestVersionBeaconName[] = "DllRedirectorTestVersionBeacon"; |
-const uint32 kSharedMemorySize = 128; |
- |
-// The maximum amount of time we are willing to let a test that Waits timeout |
-// before failing. |
-const uint32 kWaitTestTimeout = 20000; |
- |
-class MockDllRedirector : public DllRedirector { |
- public: |
- explicit MockDllRedirector(const char* beacon_name) |
- : DllRedirector(beacon_name) {} |
- |
- virtual HMODULE LoadVersionedModule() { |
- return kMockModuleHandle; |
- } |
- |
- virtual Version* GetCurrentModuleVersion() { |
- return new Version(kMockVersionString); |
- } |
- |
- virtual HMODULE GetFirstModule() { |
- return DllRedirector::GetFirstModule(); |
- } |
- |
- Version* GetFirstModuleVersion() { |
- // Lazy man's copy. |
- return new Version(dll_version_->GetString()); |
- } |
- |
- base::SharedMemory* shared_memory() { |
- return shared_memory_.get(); |
- } |
-}; |
- |
-class MockDllRedirector2 : public MockDllRedirector { |
- public: |
- explicit MockDllRedirector2(const char* beacon_name) |
- : MockDllRedirector(beacon_name) {} |
- |
- virtual HMODULE LoadVersionedModule() { |
- return kMockModuleHandle2; |
- } |
- |
- virtual Version* GetCurrentModuleVersion() { |
- return new Version(kMockVersionString2); |
- } |
-}; |
- |
-class MockDllRedirectorNoPermissions : public MockDllRedirector { |
- public: |
- explicit MockDllRedirectorNoPermissions(const char* beacon_name) |
- : MockDllRedirector(beacon_name) {} |
- |
- virtual bool BuildSecurityAttributesForLock( |
- ATL::CSecurityAttributes* sec_attr) { |
- return false; |
- } |
- |
- virtual bool SetFileMappingToReadOnly(base::SharedMemoryHandle mapping) { |
- return true; |
- } |
-}; |
- |
-class DllRedirectorTest : public testing::Test { |
- public: |
- virtual void SetUp() { |
- shared_memory_.reset(new base::SharedMemory); |
- mock_version_.reset(new Version(kMockVersionString)); |
- mock_version2_.reset(new Version(kMockVersionString2)); |
- } |
- |
- virtual void TearDown() { |
- CloseBeacon(); |
- } |
- |
- void CreateVersionBeacon(const std::string& name, |
- const std::string& version_string) { |
- // Abort the test if we can't create and map a new named memory object. |
- EXPECT_TRUE(shared_memory_->CreateNamed(name, false, |
- kSharedMemorySize)); |
- EXPECT_TRUE(shared_memory_->Map(0)); |
- EXPECT_TRUE(shared_memory_->memory()); |
- |
- if (shared_memory_->memory()) { |
- memcpy(shared_memory_->memory(), |
- version_string.c_str(), |
- std::min(kSharedMemorySize, version_string.length() + 1)); |
- } |
- } |
- |
- // Opens the named beacon and returns the version. |
- Version* OpenAndReadVersionFromBeacon(const std::string& name) { |
- // Abort the test if we can't open and map the named memory object. |
- EXPECT_TRUE(shared_memory_->Open(name, true /* read_only */)); |
- EXPECT_TRUE(shared_memory_->Map(0)); |
- EXPECT_TRUE(shared_memory_->memory()); |
- |
- char buffer[kSharedMemorySize] = {0}; |
- memcpy(buffer, shared_memory_->memory(), kSharedMemorySize - 1); |
- scoped_ptr<Version> version(new Version(buffer)); |
- if (!version->IsValid()) |
- version.reset(); |
- return version.release(); |
- } |
- |
- void CloseBeacon() { |
- shared_memory_->Close(); |
- } |
- |
- // Shared memory segment that contains the version beacon. |
- scoped_ptr<base::SharedMemory> shared_memory_; |
- scoped_ptr<Version> mock_version_; |
- scoped_ptr<Version> mock_version2_; |
-}; |
- |
-TEST_F(DllRedirectorTest, RegisterAsFirstModule) { |
- scoped_ptr<MockDllRedirector> redirector( |
- new MockDllRedirector(kTestVersionBeaconName)); |
- EXPECT_TRUE(redirector->RegisterAsFirstCFModule()); |
- |
- base::SharedMemory* redirector_memory = redirector->shared_memory(); |
- char buffer[kSharedMemorySize] = {0}; |
- memcpy(buffer, redirector_memory->memory(), kSharedMemorySize - 1); |
- Version redirector_version(buffer); |
- ASSERT_TRUE(redirector_version.IsValid()); |
- EXPECT_TRUE(redirector_version.Equals(*mock_version_.get())); |
- redirector_memory = NULL; |
- |
- scoped_ptr<Version> memory_version( |
- OpenAndReadVersionFromBeacon(kTestVersionBeaconName)); |
- ASSERT_TRUE(memory_version.get()); |
- EXPECT_TRUE(redirector_version.Equals(*memory_version.get())); |
- CloseBeacon(); |
- |
- redirector.reset(); |
- EXPECT_FALSE(shared_memory_->Open(kTestVersionBeaconName, true)); |
-} |
- |
-TEST_F(DllRedirectorTest, SecondModuleLoading) { |
- scoped_ptr<MockDllRedirector> first_redirector( |
- new MockDllRedirector(kTestVersionBeaconName)); |
- EXPECT_TRUE(first_redirector->RegisterAsFirstCFModule()); |
- |
- scoped_ptr<MockDllRedirector2> second_redirector( |
- new MockDllRedirector2(kTestVersionBeaconName)); |
- EXPECT_FALSE(second_redirector->RegisterAsFirstCFModule()); |
- |
- scoped_ptr<Version> first_redirector_version( |
- first_redirector->GetFirstModuleVersion()); |
- scoped_ptr<Version> second_redirector_version( |
- second_redirector->GetFirstModuleVersion()); |
- |
- EXPECT_TRUE( |
- second_redirector_version->Equals(*first_redirector_version.get())); |
- EXPECT_TRUE( |
- second_redirector_version->Equals(*mock_version_.get())); |
-} |
- |
-// This test ensures that the beacon remains alive as long as there is a single |
-// module that used it to determine its version still loaded. |
-TEST_F(DllRedirectorTest, TestBeaconOwnershipHandoff) { |
- scoped_ptr<MockDllRedirector> first_redirector( |
- new MockDllRedirector(kTestVersionBeaconName)); |
- EXPECT_TRUE(first_redirector->RegisterAsFirstCFModule()); |
- |
- scoped_ptr<MockDllRedirector2> second_redirector( |
- new MockDllRedirector2(kTestVersionBeaconName)); |
- EXPECT_FALSE(second_redirector->RegisterAsFirstCFModule()); |
- |
- scoped_ptr<Version> first_redirector_version( |
- first_redirector->GetFirstModuleVersion()); |
- scoped_ptr<Version> second_redirector_version( |
- second_redirector->GetFirstModuleVersion()); |
- |
- EXPECT_TRUE( |
- second_redirector_version->Equals(*first_redirector_version.get())); |
- EXPECT_TRUE( |
- second_redirector_version->Equals(*mock_version_.get())); |
- |
- // Clear out the first redirector. The second, still holding a reference |
- // to the shared memory should ensure that the beacon stays alive. |
- first_redirector.reset(); |
- |
- scoped_ptr<MockDllRedirector2> third_redirector( |
- new MockDllRedirector2(kTestVersionBeaconName)); |
- EXPECT_FALSE(third_redirector->RegisterAsFirstCFModule()); |
- |
- scoped_ptr<Version> third_redirector_version( |
- third_redirector->GetFirstModuleVersion()); |
- |
- EXPECT_TRUE( |
- third_redirector_version->Equals(*second_redirector_version.get())); |
- EXPECT_TRUE( |
- third_redirector_version->Equals(*mock_version_.get())); |
- |
- // Now close all remaining redirectors, which should destroy the beacon. |
- second_redirector.reset(); |
- third_redirector.reset(); |
- |
- // Now create a fourth, expecting that this time it should be the first in. |
- scoped_ptr<MockDllRedirector2> fourth_redirector( |
- new MockDllRedirector2(kTestVersionBeaconName)); |
- EXPECT_TRUE(fourth_redirector->RegisterAsFirstCFModule()); |
- |
- scoped_ptr<Version> fourth_redirector_version( |
- fourth_redirector->GetFirstModuleVersion()); |
- |
- EXPECT_TRUE( |
- fourth_redirector_version->Equals(*mock_version2_.get())); |
-} |
- |
-struct LockSquattingThreadParams { |
- base::win::ScopedHandle is_squatting; |
- base::win::ScopedHandle time_to_die; |
-}; |
- |
-DWORD WINAPI LockSquattingThread(void* in_params) { |
- LockSquattingThreadParams* params = |
- reinterpret_cast<LockSquattingThreadParams*>(in_params); |
- DCHECK(params); |
- |
- // Grab the lock for the shared memory region and hold onto it. |
- base::SharedMemory squatter(base::ASCIIToWide(kTestVersionBeaconName)); |
- base::SharedMemoryAutoLock squatter_lock(&squatter); |
- |
- // Notify our caller that we're squatting. |
- BOOL ret = ::SetEvent(params->is_squatting); |
- DCHECK(ret); |
- |
- // And then wait to be told to shut down. |
- DWORD result = ::WaitForSingleObject(params->time_to_die, kWaitTestTimeout); |
- EXPECT_EQ(WAIT_OBJECT_0, result); |
- |
- return 0; |
-} |
- |
-// Test that the Right Thing happens when someone else is holding onto the |
-// beacon lock and not letting go. (The Right Thing being that the redirector |
-// assumes that it is the right version and doesn't attempt to use the shared |
-// memory region.) |
-TEST_F(DllRedirectorTest, LockSquatting) { |
- scoped_ptr<MockDllRedirector> first_redirector( |
- new MockDllRedirector(kTestVersionBeaconName)); |
- EXPECT_TRUE(first_redirector->RegisterAsFirstCFModule()); |
- |
- LockSquattingThreadParams params; |
- params.is_squatting.Set(::CreateEvent(NULL, FALSE, FALSE, NULL)); |
- params.time_to_die.Set(::CreateEvent(NULL, FALSE, FALSE, NULL)); |
- DWORD tid = 0; |
- base::win::ScopedHandle lock_squat_thread( |
- ::CreateThread(NULL, 0, LockSquattingThread, ¶ms, 0, &tid)); |
- |
- // Make sure the squatter has started squatting. |
- DWORD wait_result = ::WaitForSingleObject(params.is_squatting, |
- kWaitTestTimeout); |
- EXPECT_EQ(WAIT_OBJECT_0, wait_result); |
- |
- scoped_ptr<MockDllRedirector2> second_redirector( |
- new MockDllRedirector2(kTestVersionBeaconName)); |
- EXPECT_TRUE(second_redirector->RegisterAsFirstCFModule()); |
- |
- scoped_ptr<Version> second_redirector_version( |
- second_redirector->GetFirstModuleVersion()); |
- EXPECT_TRUE( |
- second_redirector_version->Equals(*mock_version2_.get())); |
- |
- // Shut down the squatting thread. |
- DWORD ret = ::SetEvent(params.time_to_die); |
- DCHECK(ret); |
- |
- wait_result = ::WaitForSingleObject(lock_squat_thread, kWaitTestTimeout); |
- EXPECT_EQ(WAIT_OBJECT_0, wait_result); |
-} |
- |
-TEST_F(DllRedirectorTest, BadVersionNumber) { |
- std::string bad_version("I am not a version number"); |
- CreateVersionBeacon(kTestVersionBeaconName, bad_version); |
- |
- // The redirector should fail to read the version number and defer to |
- // its own version. |
- scoped_ptr<MockDllRedirector> first_redirector( |
- new MockDllRedirector(kTestVersionBeaconName)); |
- EXPECT_TRUE(first_redirector->RegisterAsFirstCFModule()); |
- |
- HMODULE first_module = first_redirector->GetFirstModule(); |
- EXPECT_EQ(NULL, first_module); |
-} |
- |
-// TODO(robertshield): These tests rely on simulating access checks from a low |
-// integrity process using impersonation. This may not be exactly identical to |
-// actually having a separate low integrity process. |
-TEST_F(DllRedirectorTest, LowIntegrityAccess) { |
- scoped_ptr<MockDllRedirector> first_redirector( |
- new MockDllRedirector(kTestVersionBeaconName)); |
- EXPECT_TRUE(first_redirector->RegisterAsFirstCFModule()); |
- |
- // Ensure that we can acquire the mutex from medium integrity: |
- { |
- base::SharedMemory shared_memory(base::ASCIIToWide(kTestVersionBeaconName)); |
- bool mutex_locked = shared_memory.Lock(kWaitTestTimeout, NULL); |
- EXPECT_TRUE(mutex_locked); |
- |
- // Ensure that the shared memory is read-only: |
- EXPECT_FALSE(shared_memory.Open(kTestVersionBeaconName, false)); |
- shared_memory.Close(); |
- EXPECT_TRUE(shared_memory.Open(kTestVersionBeaconName, true)); |
- shared_memory.Close(); |
- |
- if (mutex_locked) |
- shared_memory.Unlock(); |
- } |
- |
- if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
- // Now move to low integrity |
- chrome_frame_test::LowIntegrityToken low_integrity_token; |
- ASSERT_TRUE(low_integrity_token.Impersonate()); |
- |
- // Ensure that we can also acquire the mutex from low integrity. |
- base::SharedMemory shared_memory(base::ASCIIToWide(kTestVersionBeaconName)); |
- bool mutex_locked = shared_memory.Lock(kWaitTestTimeout, NULL); |
- EXPECT_TRUE(mutex_locked); |
- |
- // Ensure that the shared memory is read-only: |
- EXPECT_FALSE(shared_memory.Open(kTestVersionBeaconName, false)); |
- shared_memory.Close(); |
- EXPECT_TRUE(shared_memory.Open(kTestVersionBeaconName, true)); |
- shared_memory.Close(); |
- |
- if (mutex_locked) |
- shared_memory.Unlock(); |
- } |
-} |
- |
-TEST_F(DllRedirectorTest, LowIntegrityAccessDenied) { |
- // Run this test with a mock DllRedirector that doesn't set permissions |
- // on the shared memory. |
- scoped_ptr<MockDllRedirectorNoPermissions> first_redirector( |
- new MockDllRedirectorNoPermissions(kTestVersionBeaconName)); |
- EXPECT_TRUE(first_redirector->RegisterAsFirstCFModule()); |
- |
- // Ensure that we can acquire the mutex from medium integrity: |
- { |
- base::SharedMemory shared_memory(base::ASCIIToWide(kTestVersionBeaconName)); |
- bool mutex_locked = shared_memory.Lock(kWaitTestTimeout, NULL); |
- EXPECT_TRUE(mutex_locked); |
- |
- // We should be able to open the memory as read/write. |
- EXPECT_TRUE(shared_memory.Open(kTestVersionBeaconName, false)); |
- shared_memory.Close(); |
- |
- if (mutex_locked) |
- shared_memory.Unlock(); |
- } |
- |
- if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
- // Now move to low integrity |
- chrome_frame_test::LowIntegrityToken low_integrity_token; |
- low_integrity_token.Impersonate(); |
- |
- // Ensure that we can't acquire the mutex without having set the |
- // Low Integrity ACE in the SACL. |
- base::SharedMemory shared_memory(base::ASCIIToWide(kTestVersionBeaconName)); |
- bool mutex_locked = shared_memory.Lock(kWaitTestTimeout, NULL); |
- EXPECT_FALSE(mutex_locked); |
- |
- // We shouldn't be able to open the memory. |
- EXPECT_FALSE(shared_memory.Open(kTestVersionBeaconName, false)); |
- shared_memory.Close(); |
- |
- if (mutex_locked) |
- shared_memory.Unlock(); |
- } |
-} |