security/sandbox/win/src/handle_closer_test.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "base/strings/stringprintf.h"
michael@0 6 #include "base/win/scoped_handle.h"
michael@0 7 #include "sandbox/win/src/handle_closer_agent.h"
michael@0 8 #include "sandbox/win/src/sandbox.h"
michael@0 9 #include "sandbox/win/src/sandbox_factory.h"
michael@0 10 #include "sandbox/win/src/target_services.h"
michael@0 11 #include "sandbox/win/tests/common/controller.h"
michael@0 12 #include "testing/gtest/include/gtest/gtest.h"
michael@0 13
michael@0 14 namespace {
michael@0 15
michael@0 16 const wchar_t *kFileExtensions[] = { L".1", L".2", L".3", L".4" };
michael@0 17
michael@0 18 // Returns a handle to a unique marker file that can be retrieved between runs.
michael@0 19 HANDLE GetMarkerFile(const wchar_t *extension) {
michael@0 20 wchar_t path_buffer[MAX_PATH + 1];
michael@0 21 CHECK(::GetTempPath(MAX_PATH, path_buffer));
michael@0 22 string16 marker_path = path_buffer;
michael@0 23 marker_path += L"\\sbox_marker_";
michael@0 24
michael@0 25 // Generate a unique value from the exe's size and timestamp.
michael@0 26 CHECK(::GetModuleFileName(NULL, path_buffer, MAX_PATH));
michael@0 27 base::win::ScopedHandle module(::CreateFile(path_buffer,
michael@0 28 FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL,
michael@0 29 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
michael@0 30 CHECK(module.IsValid());
michael@0 31 FILETIME timestamp;
michael@0 32 CHECK(::GetFileTime(module, &timestamp, NULL, NULL));
michael@0 33 marker_path += base::StringPrintf(L"%08x%08x%08x",
michael@0 34 ::GetFileSize(module, NULL),
michael@0 35 timestamp.dwLowDateTime,
michael@0 36 timestamp.dwHighDateTime);
michael@0 37 marker_path += extension;
michael@0 38
michael@0 39 // Make the file delete-on-close so cleanup is automatic.
michael@0 40 return CreateFile(marker_path.c_str(), FILE_ALL_ACCESS,
michael@0 41 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
michael@0 42 NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
michael@0 43 }
michael@0 44
michael@0 45 // Used by the thread pool tests.
michael@0 46 HANDLE finish_event;
michael@0 47 const int kWaitCount = 20;
michael@0 48
michael@0 49 } // namespace
michael@0 50
michael@0 51 namespace sandbox {
michael@0 52
michael@0 53 // Checks for the presence of a list of files (in object path form).
michael@0 54 // Format: CheckForFileHandle (Y|N) \path\to\file1 [\path\to\file2 ...]
michael@0 55 // - Y or N depending if the file should exist or not.
michael@0 56 SBOX_TESTS_COMMAND int CheckForFileHandles(int argc, wchar_t **argv) {
michael@0 57 if (argc < 2)
michael@0 58 return SBOX_TEST_FAILED_TO_RUN_TEST;
michael@0 59 bool should_find = argv[0][0] == L'Y';
michael@0 60 if (argv[0][1] != L'\0' || !should_find && argv[0][0] != L'N')
michael@0 61 return SBOX_TEST_FAILED_TO_RUN_TEST;
michael@0 62
michael@0 63 static int state = BEFORE_INIT;
michael@0 64 switch (state++) {
michael@0 65 case BEFORE_INIT:
michael@0 66 // Create a unique marker file that is open while the test is running.
michael@0 67 // The handles leak, but it will be closed by the test or on exit.
michael@0 68 for (int i = 0; i < arraysize(kFileExtensions); ++i)
michael@0 69 EXPECT_NE(GetMarkerFile(kFileExtensions[i]), INVALID_HANDLE_VALUE);
michael@0 70 return SBOX_TEST_SUCCEEDED;
michael@0 71
michael@0 72 case AFTER_REVERT: {
michael@0 73 // Brute force the handle table to find what we're looking for.
michael@0 74 DWORD handle_count = UINT_MAX;
michael@0 75 const int kInvalidHandleThreshold = 100;
michael@0 76 const size_t kHandleOffset = sizeof(HANDLE);
michael@0 77 HANDLE handle = NULL;
michael@0 78 int invalid_count = 0;
michael@0 79 string16 handle_name;
michael@0 80
michael@0 81 if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count))
michael@0 82 return SBOX_TEST_FAILED_TO_RUN_TEST;
michael@0 83
michael@0 84 while (handle_count && invalid_count < kInvalidHandleThreshold) {
michael@0 85 reinterpret_cast<size_t&>(handle) += kHandleOffset;
michael@0 86 if (GetHandleName(handle, &handle_name)) {
michael@0 87 for (int i = 1; i < argc; ++i) {
michael@0 88 if (handle_name == argv[i])
michael@0 89 return should_find ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
michael@0 90 }
michael@0 91 --handle_count;
michael@0 92 } else {
michael@0 93 ++invalid_count;
michael@0 94 }
michael@0 95 }
michael@0 96
michael@0 97 return should_find ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED;
michael@0 98 }
michael@0 99
michael@0 100 default: // Do nothing.
michael@0 101 break;
michael@0 102 }
michael@0 103
michael@0 104 return SBOX_TEST_SUCCEEDED;
michael@0 105 }
michael@0 106
michael@0 107 TEST(HandleCloserTest, CheckForMarkerFiles) {
michael@0 108 TestRunner runner;
michael@0 109 runner.SetTimeout(2000);
michael@0 110 runner.SetTestState(EVERY_STATE);
michael@0 111 sandbox::TargetPolicy* policy = runner.GetPolicy();
michael@0 112
michael@0 113 string16 command = string16(L"CheckForFileHandles Y");
michael@0 114 for (int i = 0; i < arraysize(kFileExtensions); ++i) {
michael@0 115 string16 handle_name;
michael@0 116 base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
michael@0 117 CHECK(marker.IsValid());
michael@0 118 CHECK(sandbox::GetHandleName(marker, &handle_name));
michael@0 119 command += (L" ");
michael@0 120 command += handle_name;
michael@0 121 }
michael@0 122
michael@0 123 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) <<
michael@0 124 "Failed: " << command;
michael@0 125 }
michael@0 126
michael@0 127 TEST(HandleCloserTest, CloseMarkerFiles) {
michael@0 128 TestRunner runner;
michael@0 129 runner.SetTimeout(2000);
michael@0 130 runner.SetTestState(EVERY_STATE);
michael@0 131 sandbox::TargetPolicy* policy = runner.GetPolicy();
michael@0 132
michael@0 133 string16 command = string16(L"CheckForFileHandles N");
michael@0 134 for (int i = 0; i < arraysize(kFileExtensions); ++i) {
michael@0 135 string16 handle_name;
michael@0 136 base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
michael@0 137 CHECK(marker.IsValid());
michael@0 138 CHECK(sandbox::GetHandleName(marker, &handle_name));
michael@0 139 CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
michael@0 140 SBOX_ALL_OK);
michael@0 141 command += (L" ");
michael@0 142 command += handle_name;
michael@0 143 }
michael@0 144
michael@0 145 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) <<
michael@0 146 "Failed: " << command;
michael@0 147 }
michael@0 148
michael@0 149 void WINAPI ThreadPoolTask(void* event, BOOLEAN timeout) {
michael@0 150 static volatile LONG waiters_remaining = kWaitCount;
michael@0 151 CHECK(!timeout);
michael@0 152 CHECK(::CloseHandle(event));
michael@0 153 if (::InterlockedDecrement(&waiters_remaining) == 0)
michael@0 154 CHECK(::SetEvent(finish_event));
michael@0 155 }
michael@0 156
michael@0 157 // Run a thread pool inside a sandbox without a CSRSS connection.
michael@0 158 SBOX_TESTS_COMMAND int RunThreadPool(int argc, wchar_t **argv) {
michael@0 159 HANDLE wait_list[20];
michael@0 160 CHECK(finish_event = ::CreateEvent(NULL, TRUE, FALSE, NULL));
michael@0 161
michael@0 162 // Set up a bunch of waiters.
michael@0 163 HANDLE pool = NULL;
michael@0 164 for (int i = 0; i < kWaitCount; ++i) {
michael@0 165 HANDLE event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
michael@0 166 CHECK(event);
michael@0 167 CHECK(::RegisterWaitForSingleObject(&pool, event, ThreadPoolTask, event,
michael@0 168 INFINITE, WT_EXECUTEONLYONCE));
michael@0 169 wait_list[i] = event;
michael@0 170 }
michael@0 171
michael@0 172 // Signal all the waiters.
michael@0 173 for (int i = 0; i < kWaitCount; ++i)
michael@0 174 CHECK(::SetEvent(wait_list[i]));
michael@0 175
michael@0 176 CHECK_EQ(::WaitForSingleObject(finish_event, INFINITE), WAIT_OBJECT_0);
michael@0 177 CHECK(::CloseHandle(finish_event));
michael@0 178
michael@0 179 return SBOX_TEST_SUCCEEDED;
michael@0 180 }
michael@0 181
michael@0 182 TEST(HandleCloserTest, RunThreadPool) {
michael@0 183 TestRunner runner;
michael@0 184 runner.SetTimeout(2000);
michael@0 185 runner.SetTestState(AFTER_REVERT);
michael@0 186 sandbox::TargetPolicy* policy = runner.GetPolicy();
michael@0 187
michael@0 188 // Sever the CSRSS connection by closing ALPC ports inside the sandbox.
michael@0 189 CHECK_EQ(policy->AddKernelObjectToClose(L"ALPC Port", NULL), SBOX_ALL_OK);
michael@0 190
michael@0 191 EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"RunThreadPool"));
michael@0 192 }
michael@0 193
michael@0 194 } // namespace sandbox

mercurial