| OLD | NEW |
| (Empty) |
| 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/src/registry_policy.h" | |
| 9 #include "sandbox/src/sandbox.h" | |
| 10 #include "sandbox/src/sandbox_policy.h" | |
| 11 #include "sandbox/src/sandbox_factory.h" | |
| 12 #include "sandbox/src/nt_internals.h" | |
| 13 #include "sandbox/src/win_utils.h" | |
| 14 #include "sandbox/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 | |
| OLD | NEW |