1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/handle_closer_test.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,194 @@ 1.4 +// Copyright (c) 2011 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/strings/stringprintf.h" 1.9 +#include "base/win/scoped_handle.h" 1.10 +#include "sandbox/win/src/handle_closer_agent.h" 1.11 +#include "sandbox/win/src/sandbox.h" 1.12 +#include "sandbox/win/src/sandbox_factory.h" 1.13 +#include "sandbox/win/src/target_services.h" 1.14 +#include "sandbox/win/tests/common/controller.h" 1.15 +#include "testing/gtest/include/gtest/gtest.h" 1.16 + 1.17 +namespace { 1.18 + 1.19 +const wchar_t *kFileExtensions[] = { L".1", L".2", L".3", L".4" }; 1.20 + 1.21 +// Returns a handle to a unique marker file that can be retrieved between runs. 1.22 +HANDLE GetMarkerFile(const wchar_t *extension) { 1.23 + wchar_t path_buffer[MAX_PATH + 1]; 1.24 + CHECK(::GetTempPath(MAX_PATH, path_buffer)); 1.25 + string16 marker_path = path_buffer; 1.26 + marker_path += L"\\sbox_marker_"; 1.27 + 1.28 + // Generate a unique value from the exe's size and timestamp. 1.29 + CHECK(::GetModuleFileName(NULL, path_buffer, MAX_PATH)); 1.30 + base::win::ScopedHandle module(::CreateFile(path_buffer, 1.31 + FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, 1.32 + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); 1.33 + CHECK(module.IsValid()); 1.34 + FILETIME timestamp; 1.35 + CHECK(::GetFileTime(module, ×tamp, NULL, NULL)); 1.36 + marker_path += base::StringPrintf(L"%08x%08x%08x", 1.37 + ::GetFileSize(module, NULL), 1.38 + timestamp.dwLowDateTime, 1.39 + timestamp.dwHighDateTime); 1.40 + marker_path += extension; 1.41 + 1.42 + // Make the file delete-on-close so cleanup is automatic. 1.43 + return CreateFile(marker_path.c_str(), FILE_ALL_ACCESS, 1.44 + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1.45 + NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); 1.46 +} 1.47 + 1.48 +// Used by the thread pool tests. 1.49 +HANDLE finish_event; 1.50 +const int kWaitCount = 20; 1.51 + 1.52 +} // namespace 1.53 + 1.54 +namespace sandbox { 1.55 + 1.56 +// Checks for the presence of a list of files (in object path form). 1.57 +// Format: CheckForFileHandle (Y|N) \path\to\file1 [\path\to\file2 ...] 1.58 +// - Y or N depending if the file should exist or not. 1.59 +SBOX_TESTS_COMMAND int CheckForFileHandles(int argc, wchar_t **argv) { 1.60 + if (argc < 2) 1.61 + return SBOX_TEST_FAILED_TO_RUN_TEST; 1.62 + bool should_find = argv[0][0] == L'Y'; 1.63 + if (argv[0][1] != L'\0' || !should_find && argv[0][0] != L'N') 1.64 + return SBOX_TEST_FAILED_TO_RUN_TEST; 1.65 + 1.66 + static int state = BEFORE_INIT; 1.67 + switch (state++) { 1.68 + case BEFORE_INIT: 1.69 + // Create a unique marker file that is open while the test is running. 1.70 + // The handles leak, but it will be closed by the test or on exit. 1.71 + for (int i = 0; i < arraysize(kFileExtensions); ++i) 1.72 + EXPECT_NE(GetMarkerFile(kFileExtensions[i]), INVALID_HANDLE_VALUE); 1.73 + return SBOX_TEST_SUCCEEDED; 1.74 + 1.75 + case AFTER_REVERT: { 1.76 + // Brute force the handle table to find what we're looking for. 1.77 + DWORD handle_count = UINT_MAX; 1.78 + const int kInvalidHandleThreshold = 100; 1.79 + const size_t kHandleOffset = sizeof(HANDLE); 1.80 + HANDLE handle = NULL; 1.81 + int invalid_count = 0; 1.82 + string16 handle_name; 1.83 + 1.84 + if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count)) 1.85 + return SBOX_TEST_FAILED_TO_RUN_TEST; 1.86 + 1.87 + while (handle_count && invalid_count < kInvalidHandleThreshold) { 1.88 + reinterpret_cast<size_t&>(handle) += kHandleOffset; 1.89 + if (GetHandleName(handle, &handle_name)) { 1.90 + for (int i = 1; i < argc; ++i) { 1.91 + if (handle_name == argv[i]) 1.92 + return should_find ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED; 1.93 + } 1.94 + --handle_count; 1.95 + } else { 1.96 + ++invalid_count; 1.97 + } 1.98 + } 1.99 + 1.100 + return should_find ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED; 1.101 + } 1.102 + 1.103 + default: // Do nothing. 1.104 + break; 1.105 + } 1.106 + 1.107 + return SBOX_TEST_SUCCEEDED; 1.108 +} 1.109 + 1.110 +TEST(HandleCloserTest, CheckForMarkerFiles) { 1.111 + TestRunner runner; 1.112 + runner.SetTimeout(2000); 1.113 + runner.SetTestState(EVERY_STATE); 1.114 + sandbox::TargetPolicy* policy = runner.GetPolicy(); 1.115 + 1.116 + string16 command = string16(L"CheckForFileHandles Y"); 1.117 + for (int i = 0; i < arraysize(kFileExtensions); ++i) { 1.118 + string16 handle_name; 1.119 + base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i])); 1.120 + CHECK(marker.IsValid()); 1.121 + CHECK(sandbox::GetHandleName(marker, &handle_name)); 1.122 + command += (L" "); 1.123 + command += handle_name; 1.124 + } 1.125 + 1.126 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) << 1.127 + "Failed: " << command; 1.128 +} 1.129 + 1.130 +TEST(HandleCloserTest, CloseMarkerFiles) { 1.131 + TestRunner runner; 1.132 + runner.SetTimeout(2000); 1.133 + runner.SetTestState(EVERY_STATE); 1.134 + sandbox::TargetPolicy* policy = runner.GetPolicy(); 1.135 + 1.136 + string16 command = string16(L"CheckForFileHandles N"); 1.137 + for (int i = 0; i < arraysize(kFileExtensions); ++i) { 1.138 + string16 handle_name; 1.139 + base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i])); 1.140 + CHECK(marker.IsValid()); 1.141 + CHECK(sandbox::GetHandleName(marker, &handle_name)); 1.142 + CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()), 1.143 + SBOX_ALL_OK); 1.144 + command += (L" "); 1.145 + command += handle_name; 1.146 + } 1.147 + 1.148 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) << 1.149 + "Failed: " << command; 1.150 +} 1.151 + 1.152 +void WINAPI ThreadPoolTask(void* event, BOOLEAN timeout) { 1.153 + static volatile LONG waiters_remaining = kWaitCount; 1.154 + CHECK(!timeout); 1.155 + CHECK(::CloseHandle(event)); 1.156 + if (::InterlockedDecrement(&waiters_remaining) == 0) 1.157 + CHECK(::SetEvent(finish_event)); 1.158 +} 1.159 + 1.160 +// Run a thread pool inside a sandbox without a CSRSS connection. 1.161 +SBOX_TESTS_COMMAND int RunThreadPool(int argc, wchar_t **argv) { 1.162 + HANDLE wait_list[20]; 1.163 + CHECK(finish_event = ::CreateEvent(NULL, TRUE, FALSE, NULL)); 1.164 + 1.165 + // Set up a bunch of waiters. 1.166 + HANDLE pool = NULL; 1.167 + for (int i = 0; i < kWaitCount; ++i) { 1.168 + HANDLE event = ::CreateEvent(NULL, TRUE, FALSE, NULL); 1.169 + CHECK(event); 1.170 + CHECK(::RegisterWaitForSingleObject(&pool, event, ThreadPoolTask, event, 1.171 + INFINITE, WT_EXECUTEONLYONCE)); 1.172 + wait_list[i] = event; 1.173 + } 1.174 + 1.175 + // Signal all the waiters. 1.176 + for (int i = 0; i < kWaitCount; ++i) 1.177 + CHECK(::SetEvent(wait_list[i])); 1.178 + 1.179 + CHECK_EQ(::WaitForSingleObject(finish_event, INFINITE), WAIT_OBJECT_0); 1.180 + CHECK(::CloseHandle(finish_event)); 1.181 + 1.182 + return SBOX_TEST_SUCCEEDED; 1.183 +} 1.184 + 1.185 +TEST(HandleCloserTest, RunThreadPool) { 1.186 + TestRunner runner; 1.187 + runner.SetTimeout(2000); 1.188 + runner.SetTestState(AFTER_REVERT); 1.189 + sandbox::TargetPolicy* policy = runner.GetPolicy(); 1.190 + 1.191 + // Sever the CSRSS connection by closing ALPC ports inside the sandbox. 1.192 + CHECK_EQ(policy->AddKernelObjectToClose(L"ALPC Port", NULL), SBOX_ALL_OK); 1.193 + 1.194 + EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"RunThreadPool")); 1.195 +} 1.196 + 1.197 +} // namespace sandbox