security/sandbox/win/src/handle_closer_test.cc

changeset 0
6474c204b198
     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, &timestamp, 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

mercurial