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