security/sandbox/win/src/process_policy_test.cc

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
     2 // Use of this source code is governed by a BSD-style license that can be
     3 // found in the LICENSE file.
     5 #include <memory>
     6 #include <string>
     8 #include "base/strings/string16.h"
     9 #include "base/strings/sys_string_conversions.h"
    10 #include "base/win/scoped_handle.h"
    11 #include "base/win/scoped_process_information.h"
    12 #include "base/win/windows_version.h"
    13 #include "sandbox/win/src/sandbox.h"
    14 #include "sandbox/win/src/sandbox_factory.h"
    15 #include "sandbox/win/src/sandbox_policy.h"
    16 #include "sandbox/win/tests/common/controller.h"
    17 #include "testing/gtest/include/gtest/gtest.h"
    19 namespace {
    21 // While the shell API provides better calls than this home brew function
    22 // we use GetSystemWindowsDirectoryW which does not query the registry so
    23 // it is safe to use after revert.
    24 string16 MakeFullPathToSystem32(const wchar_t* name) {
    25   wchar_t windows_path[MAX_PATH] = {0};
    26   ::GetSystemWindowsDirectoryW(windows_path, MAX_PATH);
    27   string16 full_path(windows_path);
    28   if (full_path.empty()) {
    29     return full_path;
    30   }
    31   full_path += L"\\system32\\";
    32   full_path += name;
    33   return full_path;
    34 }
    36 // Creates a process with the |exe| and |command| parameter using the
    37 // unicode and ascii version of the api.
    38 sandbox::SboxTestResult CreateProcessHelper(const string16& exe,
    39                                             const string16& command) {
    40   base::win::ScopedProcessInformation pi;
    41   STARTUPINFOW si = {sizeof(si)};
    43   const wchar_t *exe_name = NULL;
    44   if (!exe.empty())
    45     exe_name = exe.c_str();
    47   const wchar_t *cmd_line = NULL;
    48   if (!command.empty())
    49     cmd_line = command.c_str();
    51   // Create the process with the unicode version of the API.
    52   sandbox::SboxTestResult ret1 = sandbox::SBOX_TEST_FAILED;
    53   if (!::CreateProcessW(exe_name, const_cast<wchar_t*>(cmd_line), NULL, NULL,
    54                         FALSE, 0, NULL, NULL, &si, pi.Receive())) {
    55     DWORD last_error = GetLastError();
    56     if ((ERROR_NOT_ENOUGH_QUOTA == last_error) ||
    57         (ERROR_ACCESS_DENIED == last_error) ||
    58         (ERROR_FILE_NOT_FOUND == last_error)) {
    59       ret1 = sandbox::SBOX_TEST_DENIED;
    60     } else {
    61       ret1 = sandbox::SBOX_TEST_FAILED;
    62     }
    63   } else {
    64     ret1 = sandbox::SBOX_TEST_SUCCEEDED;
    65   }
    67   pi.Close();
    69   // Do the same with the ansi version of the api
    70   STARTUPINFOA sia = {sizeof(sia)};
    71   sandbox::SboxTestResult ret2 = sandbox::SBOX_TEST_FAILED;
    73   std::string narrow_cmd_line;
    74   if (cmd_line)
    75     narrow_cmd_line = base::SysWideToMultiByte(cmd_line, CP_UTF8);
    76   if (!::CreateProcessA(
    77         exe_name ? base::SysWideToMultiByte(exe_name, CP_UTF8).c_str() : NULL,
    78         cmd_line ? const_cast<char*>(narrow_cmd_line.c_str()) : NULL,
    79         NULL, NULL, FALSE, 0, NULL, NULL, &sia, pi.Receive())) {
    80     DWORD last_error = GetLastError();
    81     if ((ERROR_NOT_ENOUGH_QUOTA == last_error) ||
    82         (ERROR_ACCESS_DENIED == last_error) ||
    83         (ERROR_FILE_NOT_FOUND == last_error)) {
    84       ret2 = sandbox::SBOX_TEST_DENIED;
    85     } else {
    86       ret2 = sandbox::SBOX_TEST_FAILED;
    87     }
    88   } else {
    89     ret2 = sandbox::SBOX_TEST_SUCCEEDED;
    90   }
    92   if (ret1 == ret2)
    93     return ret1;
    95   return sandbox::SBOX_TEST_FAILED;
    96 }
    98 }  // namespace
   100 namespace sandbox {
   102 SBOX_TESTS_COMMAND int Process_RunApp1(int argc, wchar_t **argv) {
   103   if (argc != 1) {
   104     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   105   }
   106   if ((NULL == argv) || (NULL == argv[0])) {
   107     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   108   }
   109   string16 path = MakeFullPathToSystem32(argv[0]);
   111   // TEST 1: Try with the path in the app_name.
   112   return CreateProcessHelper(path, string16());
   113 }
   115 SBOX_TESTS_COMMAND int Process_RunApp2(int argc, wchar_t **argv) {
   116   if (argc != 1) {
   117     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   118   }
   119   if ((NULL == argv) || (NULL == argv[0])) {
   120     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   121   }
   122   string16 path = MakeFullPathToSystem32(argv[0]);
   124   // TEST 2: Try with the path in the cmd_line.
   125   string16 cmd_line = L"\"";
   126   cmd_line += path;
   127   cmd_line += L"\"";
   128   return CreateProcessHelper(string16(), cmd_line);
   129 }
   131 SBOX_TESTS_COMMAND int Process_RunApp3(int argc, wchar_t **argv) {
   132   if (argc != 1) {
   133     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   134   }
   135   if ((NULL == argv) || (NULL == argv[0])) {
   136     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   137   }
   139   // TEST 3: Try file name in the cmd_line.
   140   return CreateProcessHelper(string16(), argv[0]);
   141 }
   143 SBOX_TESTS_COMMAND int Process_RunApp4(int argc, wchar_t **argv) {
   144   if (argc != 1) {
   145     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   146   }
   147   if ((NULL == argv) || (NULL == argv[0])) {
   148     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   149   }
   151   // TEST 4: Try file name in the app_name and current directory sets correctly.
   152   string16 system32 = MakeFullPathToSystem32(L"");
   153   wchar_t current_directory[MAX_PATH + 1];
   154   int result4;
   155   bool test_succeeded = false;
   156   DWORD ret = ::GetCurrentDirectory(MAX_PATH, current_directory);
   157   if (!ret)
   158     return SBOX_TEST_FIRST_ERROR;
   160   if (ret < MAX_PATH) {
   161     current_directory[ret] = L'\\';
   162     current_directory[ret+1] = L'\0';
   163     if (::SetCurrentDirectory(system32.c_str())) {
   164       result4 = CreateProcessHelper(argv[0], string16());
   165       if (::SetCurrentDirectory(current_directory)) {
   166         test_succeeded = true;
   167       }
   168     } else {
   169       return SBOX_TEST_SECOND_ERROR;
   170     }
   171   }
   172   if (!test_succeeded)
   173     result4 = SBOX_TEST_FAILED;
   175   return result4;
   176 }
   178 SBOX_TESTS_COMMAND int Process_RunApp5(int argc, wchar_t **argv) {
   179   if (argc != 1) {
   180     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   181   }
   182   if ((NULL == argv) || (NULL == argv[0])) {
   183     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   184   }
   185   string16 path = MakeFullPathToSystem32(argv[0]);
   187   // TEST 5: Try with the path in the cmd_line and arguments.
   188   string16 cmd_line = L"\"";
   189   cmd_line += path;
   190   cmd_line += L"\" /I";
   191   return CreateProcessHelper(string16(), cmd_line);
   192 }
   194 SBOX_TESTS_COMMAND int Process_RunApp6(int argc, wchar_t **argv) {
   195   if (argc != 1) {
   196     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   197   }
   198   if ((NULL == argv) || (NULL == argv[0])) {
   199     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   200   }
   202   // TEST 6: Try with the file_name in the cmd_line and arguments.
   203   string16 cmd_line = argv[0];
   204   cmd_line += L" /I";
   205   return CreateProcessHelper(string16(), cmd_line);
   206 }
   208 // Creates a process and checks if it's possible to get a handle to it's token.
   209 SBOX_TESTS_COMMAND int Process_GetChildProcessToken(int argc, wchar_t **argv) {
   210   if (argc != 1)
   211     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   213   if ((NULL == argv) || (NULL == argv[0]))
   214     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
   216   string16 path = MakeFullPathToSystem32(argv[0]);
   218   base::win::ScopedProcessInformation pi;
   219   STARTUPINFOW si = {sizeof(si)};
   221   if (!::CreateProcessW(path.c_str(), NULL, NULL, NULL, FALSE, CREATE_SUSPENDED,
   222                         NULL, NULL, &si, pi.Receive())) {
   223       return SBOX_TEST_FAILED;
   224   }
   226   HANDLE token = NULL;
   227   BOOL result =
   228       ::OpenProcessToken(pi.process_handle(), TOKEN_IMPERSONATE, &token);
   229   DWORD error = ::GetLastError();
   231   base::win::ScopedHandle token_handle(token);
   233   if (!::TerminateProcess(pi.process_handle(), 0))
   234     return SBOX_TEST_FAILED;
   236   if (result && token)
   237     return SBOX_TEST_SUCCEEDED;
   239   if (ERROR_ACCESS_DENIED == error)
   240     return SBOX_TEST_DENIED;
   242   return SBOX_TEST_FAILED;
   243 }
   246 SBOX_TESTS_COMMAND int Process_OpenToken(int argc, wchar_t **argv) {
   247   HANDLE token;
   248   if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
   249     if (ERROR_ACCESS_DENIED == ::GetLastError()) {
   250       return SBOX_TEST_DENIED;
   251     }
   252   } else {
   253     ::CloseHandle(token);
   254     return SBOX_TEST_SUCCEEDED;
   255   }
   257   return SBOX_TEST_FAILED;
   258 }
   260 TEST(ProcessPolicyTest, TestAllAccess) {
   261   // Check if the "all access" rule fails to be added when the token is too
   262   // powerful.
   263   TestRunner runner;
   265   // Check the failing case.
   266   runner.GetPolicy()->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
   267   EXPECT_EQ(SBOX_ERROR_UNSUPPORTED,
   268             runner.GetPolicy()->AddRule(TargetPolicy::SUBSYS_PROCESS,
   269                                         TargetPolicy::PROCESS_ALL_EXEC,
   270                                         L"this is not important"));
   272   // Check the working case.
   273   runner.GetPolicy()->SetTokenLevel(USER_INTERACTIVE, USER_INTERACTIVE);
   275   EXPECT_EQ(SBOX_ALL_OK,
   276             runner.GetPolicy()->AddRule(TargetPolicy::SUBSYS_PROCESS,
   277                                         TargetPolicy::PROCESS_ALL_EXEC,
   278                                         L"this is not important"));
   279 }
   281 TEST(ProcessPolicyTest, CreateProcessAW) {
   282   TestRunner runner;
   283   string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
   284   string16 system32 = MakeFullPathToSystem32(L"");
   285   ASSERT_TRUE(!exe_path.empty());
   286   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
   287                              TargetPolicy::PROCESS_MIN_EXEC,
   288                              exe_path.c_str()));
   290   // Need to add directory rules for the directories that we use in
   291   // SetCurrentDirectory.
   292   EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_DIR_ANY,
   293                                system32.c_str()));
   295   wchar_t current_directory[MAX_PATH];
   296   DWORD ret = ::GetCurrentDirectory(MAX_PATH, current_directory);
   297   ASSERT_TRUE(0 != ret && ret < MAX_PATH);
   299   wcscat_s(current_directory, MAX_PATH, L"\\");
   300   EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_DIR_ANY,
   301                                current_directory));
   303   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp1 calc.exe"));
   304   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp2 calc.exe"));
   305   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp3 calc.exe"));
   306   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp5 calc.exe"));
   307   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp6 calc.exe"));
   309   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
   310             runner.RunTest(L"Process_RunApp1 findstr.exe"));
   311   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
   312             runner.RunTest(L"Process_RunApp2 findstr.exe"));
   313   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
   314             runner.RunTest(L"Process_RunApp3 findstr.exe"));
   315   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
   316             runner.RunTest(L"Process_RunApp5 findstr.exe"));
   317   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
   318             runner.RunTest(L"Process_RunApp6 findstr.exe"));
   320 #if !defined(_WIN64)
   321   if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
   322     // WinXP results are not reliable.
   323     EXPECT_EQ(SBOX_TEST_SECOND_ERROR,
   324         runner.RunTest(L"Process_RunApp4 calc.exe"));
   325     EXPECT_EQ(SBOX_TEST_SECOND_ERROR,
   326         runner.RunTest(L"Process_RunApp4 findstr.exe"));
   327   }
   328 #endif
   329 }
   331 TEST(ProcessPolicyTest, OpenToken) {
   332   TestRunner runner;
   333   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Process_OpenToken"));
   334 }
   336 TEST(ProcessPolicyTest, TestGetProcessTokenMinAccess) {
   337   TestRunner runner;
   338   string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
   339   ASSERT_TRUE(!exe_path.empty());
   340   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
   341                              TargetPolicy::PROCESS_MIN_EXEC,
   342                              exe_path.c_str()));
   344   EXPECT_EQ(SBOX_TEST_DENIED,
   345             runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
   346 }
   348 TEST(ProcessPolicyTest, TestGetProcessTokenMaxAccess) {
   349   TestRunner runner(JOB_UNPROTECTED, USER_INTERACTIVE, USER_INTERACTIVE);
   350   string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
   351   ASSERT_TRUE(!exe_path.empty());
   352   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
   353                              TargetPolicy::PROCESS_ALL_EXEC,
   354                              exe_path.c_str()));
   356   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
   357             runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
   358 }
   360 TEST(ProcessPolicyTest, TestGetProcessTokenMinAccessNoJob) {
   361   TestRunner runner(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
   362   string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
   363   ASSERT_TRUE(!exe_path.empty());
   364   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
   365                              TargetPolicy::PROCESS_MIN_EXEC,
   366                              exe_path.c_str()));
   368   EXPECT_EQ(SBOX_TEST_DENIED,
   369             runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
   370 }
   372 TEST(ProcessPolicyTest, TestGetProcessTokenMaxAccessNoJob) {
   373   TestRunner runner(JOB_NONE, USER_INTERACTIVE, USER_INTERACTIVE);
   374   string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
   375   ASSERT_TRUE(!exe_path.empty());
   376   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
   377                              TargetPolicy::PROCESS_ALL_EXEC,
   378                              exe_path.c_str()));
   380   EXPECT_EQ(SBOX_TEST_SUCCEEDED,
   381             runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
   382 }
   384 }  // namespace sandbox

mercurial