|
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 |