Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2006-2010 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.
      4 
      5 #include <shlobj.h>
      6 
      7 #include "testing/gtest/include/gtest/gtest.h"
      8 #include "sandbox/win/src/registry_policy.h"
      9 #include "sandbox/win/src/sandbox.h"
     10 #include "sandbox/win/src/sandbox_policy.h"
     11 #include "sandbox/win/src/sandbox_factory.h"
     12 #include "sandbox/win/src/nt_internals.h"
     13 #include "sandbox/win/src/win_utils.h"
     14 #include "sandbox/win/tests/common/controller.h"
     15 
     16 namespace {
     17 
     18 static const DWORD kAllowedRegFlags = KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS |
     19                                       KEY_NOTIFY | KEY_READ | GENERIC_READ |
     20                                       GENERIC_EXECUTE | READ_CONTROL;
     21 
     22 #define BINDNTDLL(name) \
     23   name ## Function name = reinterpret_cast<name ## Function>( \
     24     ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
     25 
     26 bool IsKeyOpenForRead(HKEY handle) {
     27   BINDNTDLL(NtQueryObject);
     28 
     29   OBJECT_BASIC_INFORMATION info = {0};
     30   NTSTATUS status = NtQueryObject(handle, ObjectBasicInformation, &info,
     31                                   sizeof(info), NULL);
     32 
     33   if (!NT_SUCCESS(status))
     34     return false;
     35 
     36   if ((info.GrantedAccess & (~kAllowedRegFlags)) != 0)
     37     return false;
     38   return true;
     39 }
     40 
     41 }
     42 
     43 namespace sandbox {
     44 
     45 SBOX_TESTS_COMMAND int Reg_OpenKey(int argc, wchar_t **argv) {
     46   if (argc != 4)
     47     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
     48 
     49   REGSAM desired_access = 0;
     50   ULONG options = 0;
     51   if (wcscmp(argv[1], L"read") == 0) {
     52     desired_access = KEY_READ;
     53   } else if (wcscmp(argv[1], L"write") == 0) {
     54     desired_access = KEY_ALL_ACCESS;
     55   } else if (wcscmp(argv[1], L"link") == 0) {
     56     options = REG_OPTION_CREATE_LINK;
     57     desired_access = KEY_ALL_ACCESS;
     58   } else {
     59     desired_access = MAXIMUM_ALLOWED;
     60   }
     61 
     62   HKEY root = GetReservedKeyFromName(argv[2]);
     63   HKEY key;
     64   LRESULT result = 0;
     65 
     66   if (wcscmp(argv[0], L"create") == 0)
     67     result = ::RegCreateKeyEx(root, argv[3], 0, NULL, options, desired_access,
     68                               NULL, &key, NULL);
     69   else
     70     result = ::RegOpenKeyEx(root, argv[3], 0, desired_access, &key);
     71 
     72   if (ERROR_SUCCESS == result) {
     73     if (MAXIMUM_ALLOWED == desired_access) {
     74       if (!IsKeyOpenForRead(key)) {
     75         ::RegCloseKey(key);
     76         return SBOX_TEST_FAILED;
     77       }
     78     }
     79     ::RegCloseKey(key);
     80     return SBOX_TEST_SUCCEEDED;
     81   } else if (ERROR_ACCESS_DENIED == result) {
     82     return SBOX_TEST_DENIED;
     83   }
     84 
     85   return SBOX_TEST_FAILED;
     86 }
     87 
     88 TEST(RegistryPolicyTest, TestKeyAnyAccess) {
     89   TestRunner runner;
     90   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
     91                              TargetPolicy::REG_ALLOW_READONLY,
     92                              L"HKEY_LOCAL_MACHINE"));
     93 
     94   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
     95                              TargetPolicy::REG_ALLOW_ANY,
     96                              L"HKEY_LOCAL_MACHINE\\Software\\Microsoft"));
     97 
     98   // Tests read access on key allowed for read-write.
     99   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
    100       L"Reg_OpenKey create read HKEY_LOCAL_MACHINE software\\microsoft"));
    101 
    102   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
    103       L"Reg_OpenKey open read HKEY_LOCAL_MACHINE software\\microsoft"));
    104 
    105   if (::IsUserAnAdmin()) {
    106     // Tests write access on key allowed for read-write.
    107     EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
    108         L"Reg_OpenKey create write HKEY_LOCAL_MACHINE software\\microsoft"));
    109 
    110     EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
    111         L"Reg_OpenKey open write HKEY_LOCAL_MACHINE software\\microsoft"));
    112   }
    113 
    114   // Tests subdirectory access on keys where we don't have subdirectory acess.
    115   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Reg_OpenKey create read "
    116       L"HKEY_LOCAL_MACHINE software\\microsoft\\Windows"));
    117 
    118   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Reg_OpenKey open read "
    119       L"HKEY_LOCAL_MACHINE software\\microsoft\\windows"));
    120 
    121   // Tests to see if we can create keys where we dont have subdirectory access.
    122   // This is denied.
    123   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Reg_OpenKey create write "
    124       L"HKEY_LOCAL_MACHINE software\\Microsoft\\google_unit_tests"));
    125 
    126   RegDeleteKey(HKEY_LOCAL_MACHINE, L"software\\Microsoft\\google_unit_tests");
    127 
    128   // Tests if we need to handle differently the "\\" at the end.
    129   // This is denied. We need to add both rules.
    130   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
    131       L"Reg_OpenKey create read HKEY_LOCAL_MACHINE software\\microsoft\\"));
    132 
    133   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
    134       L"Reg_OpenKey open read HKEY_LOCAL_MACHINE software\\microsoft\\"));
    135 }
    136 
    137 TEST(RegistryPolicyTest, TestKeyNoAccess) {
    138   TestRunner runner;
    139 
    140   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    141                              TargetPolicy::REG_ALLOW_READONLY,
    142                              L"HKEY_LOCAL_MACHINE"));
    143 
    144   // Tests read access where we don't have access at all.
    145   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
    146       L"Reg_OpenKey create read HKEY_LOCAL_MACHINE software"));
    147 
    148   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
    149       L"Reg_OpenKey open read HKEY_LOCAL_MACHINE software"));
    150 }
    151 
    152 TEST(RegistryPolicyTest, TestKeyReadOnlyAccess) {
    153   TestRunner runner;
    154 
    155   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    156                              TargetPolicy::REG_ALLOW_READONLY,
    157                              L"HKEY_LOCAL_MACHINE"));
    158 
    159   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    160                              TargetPolicy::REG_ALLOW_READONLY,
    161                              L"HKEY_LOCAL_MACHINE\\Software\\Policies"));
    162 
    163   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    164                              TargetPolicy::REG_ALLOW_READONLY,
    165                              L"HKEY_LOCAL_MACHINE\\Software\\Policies\\*"));
    166 
    167   // Tests subdirectory acess on keys where we have subdirectory acess.
    168   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Reg_OpenKey create read "
    169       L"HKEY_LOCAL_MACHINE software\\Policies\\microsoft"));
    170 
    171   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Reg_OpenKey open read "
    172       L"HKEY_LOCAL_MACHINE software\\Policies\\microsoft"));
    173 
    174   // Tests to see if we can create keys where we have subdirectory access.
    175   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Reg_OpenKey create write "
    176       L"HKEY_LOCAL_MACHINE software\\Policies\\google_unit_tests"));
    177 
    178   RegDeleteKey(HKEY_LOCAL_MACHINE, L"software\\Policies\\google_unit_tests");
    179 }
    180 
    181 TEST(RegistryPolicyTest, TestKeyAllAccessSubDir) {
    182   TestRunner runner;
    183 
    184   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    185                              TargetPolicy::REG_ALLOW_READONLY,
    186                              L"HKEY_LOCAL_MACHINE"));
    187 
    188   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    189                              TargetPolicy::REG_ALLOW_ANY,
    190                              L"HKEY_LOCAL_MACHINE\\Software\\Policies"));
    191 
    192   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    193                              TargetPolicy::REG_ALLOW_ANY,
    194                              L"HKEY_LOCAL_MACHINE\\Software\\Policies\\*"));
    195 
    196   if (::IsUserAnAdmin()) {
    197     // Tests to see if we can create keys where we have subdirectory access.
    198     EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Reg_OpenKey create write "
    199         L"HKEY_LOCAL_MACHINE software\\Policies\\google_unit_tests"));
    200 
    201     RegDeleteKey(HKEY_LOCAL_MACHINE, L"software\\Policies\\google_unit_tests");
    202   }
    203 }
    204 
    205 TEST(RegistryPolicyTest, TestKeyCreateLink) {
    206   TestRunner runner;
    207 
    208   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    209                              TargetPolicy::REG_ALLOW_READONLY,
    210                              L"HKEY_LOCAL_MACHINE"));
    211 
    212   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    213                              TargetPolicy::REG_ALLOW_ANY,
    214                              L"HKEY_LOCAL_MACHINE\\Software\\Policies"));
    215 
    216   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    217                              TargetPolicy::REG_ALLOW_ANY,
    218                              L"HKEY_LOCAL_MACHINE\\Software\\Policies\\*"));
    219 
    220   // Tests to see if we can create a registry link key.
    221   // NOTE: In theory here we should make sure to check for SBOX_TEST_DENIED
    222   // instead of !SBOX_TEST_SUCCEEDED, but unfortunately the result is not
    223   // access denied. Internally RegCreateKeyEx (At least on Vista 64) tries to
    224   // create the link, and we return successfully access denied, then, it
    225   // decides to try to break the path in multiple chunks, and create the links
    226   // one by one. In this scenario, it tries to create "HKLM\Software" as a
    227   // link key, which obviously fail with STATUS_OBJECT_NAME_COLLISION, and
    228   // this is what is returned to the user.
    229   EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Reg_OpenKey create link "
    230       L"HKEY_LOCAL_MACHINE software\\Policies\\google_unit_tests"));
    231 
    232   // In case our code fails, and the call works, we need to delete the new
    233   // link. There is no api for this, so we need to use the NT call.
    234   HKEY key = NULL;
    235   LRESULT result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
    236                                   L"software\\Policies\\google_unit_tests",
    237                                   REG_OPTION_OPEN_LINK, MAXIMUM_ALLOWED,
    238                                   &key);
    239 
    240   if (!result) {
    241     HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
    242     NtDeleteKeyFunction NtDeleteKey =
    243         reinterpret_cast<NtDeleteKeyFunction>(GetProcAddress(ntdll,
    244                                                              "NtDeleteKey"));
    245     NtDeleteKey(key);
    246   }
    247 }
    248 
    249 TEST(RegistryPolicyTest, TestKeyReadOnlyHKCU) {
    250   TestRunner runner;
    251   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    252                              TargetPolicy::REG_ALLOW_READONLY,
    253                              L"HKEY_CURRENT_USER"));
    254 
    255   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    256                              TargetPolicy::REG_ALLOW_READONLY,
    257                              L"HKEY_CURRENT_USER\\Software"));
    258 
    259   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    260                              TargetPolicy::REG_ALLOW_READONLY,
    261                              L"HKEY_USERS\\.default"));
    262 
    263   EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
    264                              TargetPolicy::REG_ALLOW_READONLY,
    265                              L"HKEY_USERS\\.default\\software"));
    266 
    267   // Tests read access where we only have read-only access.
    268   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
    269       L"Reg_OpenKey create read HKEY_CURRENT_USER software"));
    270 
    271   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
    272       L"Reg_OpenKey open read HKEY_CURRENT_USER software"));
    273 
    274   // Tests write access where we only have read-only acess.
    275   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
    276       L"Reg_OpenKey create write HKEY_CURRENT_USER software"));
    277 
    278   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
    279       L"Reg_OpenKey open write HKEY_CURRENT_USER software"));
    280 
    281   // Tests maximum allowed access where we only have read-only access.
    282   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
    283       L"Reg_OpenKey create maximum_allowed HKEY_CURRENT_USER software"));
    284 
    285   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
    286       L"Reg_OpenKey open maximum_allowed HKEY_CURRENT_USER software"));
    287 }
    288 
    289 }  // namespace sandbox
    290