OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <Aclapi.h> | |
6 #include <windows.h> | |
7 #include <stddef.h> | |
8 #include <string> | |
9 | |
10 #include "sandbox/win/tests/validation_tests/commands.h" | |
11 | |
12 #include "sandbox/win/tests/common/controller.h" | |
13 | |
14 namespace { | |
15 | |
16 // Returns the HKEY corresponding to name. If there is no HKEY corresponding | |
17 // to the name it returns NULL. | |
18 HKEY GetHKEYFromString(const base::string16 &name) { | |
19 if (name == L"HKLM") | |
20 return HKEY_LOCAL_MACHINE; | |
21 if (name == L"HKCR") | |
22 return HKEY_CLASSES_ROOT; | |
23 if (name == L"HKCC") | |
24 return HKEY_CURRENT_CONFIG; | |
25 if (name == L"HKCU") | |
26 return HKEY_CURRENT_USER; | |
27 if (name == L"HKU") | |
28 return HKEY_USERS; | |
29 | |
30 return NULL; | |
31 } | |
32 | |
33 // Modifies string to remove the leading and trailing quotes. | |
34 void trim_quote(base::string16* string) { | |
35 base::string16::size_type pos1 = string->find_first_not_of(L'"'); | |
36 base::string16::size_type pos2 = string->find_last_not_of(L'"'); | |
37 | |
38 if (pos1 == base::string16::npos || pos2 == base::string16::npos) | |
39 string->clear(); | |
40 else | |
41 (*string) = string->substr(pos1, pos2 + 1); | |
42 } | |
43 | |
44 int TestOpenFile(base::string16 path, bool for_write) { | |
45 wchar_t path_expanded[MAX_PATH + 1] = {0}; | |
46 DWORD size = ::ExpandEnvironmentStrings(path.c_str(), path_expanded, | |
47 MAX_PATH); | |
48 if (!size) | |
49 return sandbox::SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
50 | |
51 HANDLE file; | |
52 file = ::CreateFile(path_expanded, | |
53 for_write ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ, | |
54 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
55 NULL, // No security attributes. | |
56 OPEN_EXISTING, | |
57 FILE_FLAG_BACKUP_SEMANTICS, | |
58 NULL); // No template. | |
59 | |
60 if (file != INVALID_HANDLE_VALUE) { | |
61 ::CloseHandle(file); | |
62 return sandbox::SBOX_TEST_SUCCEEDED; | |
63 } | |
64 return (::GetLastError() == ERROR_ACCESS_DENIED) ? | |
65 sandbox::SBOX_TEST_DENIED : sandbox::SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
66 } | |
67 | |
68 } // namespace | |
69 | |
70 namespace sandbox { | |
71 | |
72 SBOX_TESTS_COMMAND int ValidWindow(int argc, wchar_t **argv) { | |
73 return (argc == 1) ? | |
74 TestValidWindow( | |
75 reinterpret_cast<HWND>(static_cast<ULONG_PTR>(_wtoi(argv[0])))) : | |
76 SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
77 } | |
78 | |
79 int TestValidWindow(HWND window) { | |
80 return ::IsWindow(window) ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED; | |
81 } | |
82 | |
83 SBOX_TESTS_COMMAND int OpenProcessCmd(int argc, wchar_t **argv) { | |
84 return (argc == 2) ? | |
85 TestOpenProcess(_wtol(argv[0]), _wtol(argv[1])) : | |
86 SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
87 } | |
88 | |
89 int TestOpenProcess(DWORD process_id, DWORD access_mask) { | |
90 HANDLE process = ::OpenProcess(access_mask, | |
91 FALSE, // Do not inherit handle. | |
92 process_id); | |
93 if (process != NULL) { | |
94 ::CloseHandle(process); | |
95 return SBOX_TEST_SUCCEEDED; | |
96 } | |
97 return (::GetLastError() == ERROR_ACCESS_DENIED) ? | |
98 sandbox::SBOX_TEST_DENIED : sandbox::SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
99 } | |
100 | |
101 SBOX_TESTS_COMMAND int OpenThreadCmd(int argc, wchar_t **argv) { | |
102 return (argc == 1) ? | |
103 TestOpenThread(_wtoi(argv[0])) : SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
104 } | |
105 | |
106 int TestOpenThread(DWORD thread_id) { | |
107 HANDLE thread = ::OpenThread(THREAD_QUERY_INFORMATION, | |
108 FALSE, // Do not inherit handles. | |
109 thread_id); | |
110 if (thread != NULL) { | |
111 ::CloseHandle(thread); | |
112 return SBOX_TEST_SUCCEEDED; | |
113 } | |
114 return (::GetLastError() == ERROR_ACCESS_DENIED) ? | |
115 sandbox::SBOX_TEST_DENIED : sandbox::SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
116 } | |
117 | |
118 SBOX_TESTS_COMMAND int OpenFileCmd(int argc, wchar_t **argv) { | |
119 if (1 != argc) | |
120 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
121 | |
122 base::string16 path = argv[0]; | |
123 trim_quote(&path); | |
124 | |
125 return TestOpenReadFile(path); | |
126 } | |
127 | |
128 int TestOpenReadFile(const base::string16& path) { | |
129 return TestOpenFile(path, false); | |
130 } | |
131 | |
132 int TestOpenWriteFile(int argc, wchar_t **argv) { | |
133 if (argc != 1) | |
134 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
135 | |
136 base::string16 path = argv[0]; | |
137 trim_quote(&path); | |
138 return TestOpenWriteFile(path); | |
139 } | |
140 | |
141 int TestOpenWriteFile(const base::string16& path) { | |
142 return TestOpenFile(path, true); | |
143 } | |
144 | |
145 SBOX_TESTS_COMMAND int OpenKey(int argc, wchar_t **argv) { | |
146 if (argc != 1 && argc != 2) | |
147 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
148 | |
149 // Get the hive. | |
150 HKEY base_key = GetHKEYFromString(argv[0]); | |
151 | |
152 // Get the subkey. | |
153 base::string16 subkey; | |
154 if (argc == 2) { | |
155 subkey = argv[1]; | |
156 trim_quote(&subkey); | |
157 } | |
158 | |
159 return TestOpenKey(base_key, subkey); | |
160 } | |
161 | |
162 int TestOpenKey(HKEY base_key, base::string16 subkey) { | |
163 HKEY key; | |
164 LONG err_code = ::RegOpenKeyEx(base_key, | |
165 subkey.c_str(), | |
166 0, // Reserved, must be 0. | |
167 MAXIMUM_ALLOWED, | |
168 &key); | |
169 if (err_code == ERROR_SUCCESS) { | |
170 ::RegCloseKey(key); | |
171 return SBOX_TEST_SUCCEEDED; | |
172 } | |
173 return (err_code == ERROR_INVALID_HANDLE || err_code == ERROR_ACCESS_DENIED) ? | |
174 SBOX_TEST_DENIED : SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
175 } | |
176 | |
177 // Returns true if the current's thread desktop is the interactive desktop. | |
178 // In Vista there is a more direct test but for XP and w2k we need to check | |
179 // the object name. | |
180 bool IsInteractiveDesktop(bool* is_interactive) { | |
181 HDESK current_desk = ::GetThreadDesktop(::GetCurrentThreadId()); | |
182 if (current_desk == NULL) | |
183 return false; | |
184 wchar_t current_desk_name[256] = {0}; | |
185 if (!::GetUserObjectInformationW(current_desk, UOI_NAME, current_desk_name, | |
186 sizeof(current_desk_name), NULL)) | |
187 return false; | |
188 *is_interactive = (0 == _wcsicmp(L"default", current_desk_name)); | |
189 return true; | |
190 } | |
191 | |
192 SBOX_TESTS_COMMAND int OpenInteractiveDesktop(int, wchar_t **) { | |
193 return TestOpenInputDesktop(); | |
194 } | |
195 | |
196 int TestOpenInputDesktop() { | |
197 bool is_interactive = false; | |
198 if (IsInteractiveDesktop(&is_interactive) && is_interactive) | |
199 return SBOX_TEST_SUCCEEDED; | |
200 HDESK desk = ::OpenInputDesktop(0, FALSE, DESKTOP_CREATEWINDOW); | |
201 if (desk) { | |
202 ::CloseDesktop(desk); | |
203 return SBOX_TEST_SUCCEEDED; | |
204 } | |
205 return SBOX_TEST_DENIED; | |
206 } | |
207 | |
208 SBOX_TESTS_COMMAND int SwitchToSboxDesktop(int, wchar_t **) { | |
209 return TestSwitchDesktop(); | |
210 } | |
211 | |
212 int TestSwitchDesktop() { | |
213 HDESK desktop = ::GetThreadDesktop(::GetCurrentThreadId()); | |
214 if (desktop == NULL) | |
215 return SBOX_TEST_FAILED; | |
216 return ::SwitchDesktop(desktop) ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED; | |
217 } | |
218 | |
219 SBOX_TESTS_COMMAND int OpenAlternateDesktop(int, wchar_t **argv) { | |
220 return TestOpenAlternateDesktop(argv[0]); | |
221 } | |
222 | |
223 int TestOpenAlternateDesktop(wchar_t *desktop_name) { | |
224 // Test for WRITE_DAC permission on the handle. | |
225 HDESK desktop = ::GetThreadDesktop(::GetCurrentThreadId()); | |
226 if (desktop) { | |
227 HANDLE test_handle; | |
228 if (::DuplicateHandle(::GetCurrentProcess(), desktop, | |
229 ::GetCurrentProcess(), &test_handle, | |
230 WRITE_DAC, FALSE, 0)) { | |
231 DWORD result = ::SetSecurityInfo(test_handle, SE_WINDOW_OBJECT, | |
232 DACL_SECURITY_INFORMATION, NULL, NULL, | |
233 NULL, NULL); | |
234 ::CloseHandle(test_handle); | |
235 if (result == ERROR_SUCCESS) | |
236 return SBOX_TEST_SUCCEEDED; | |
237 } else if (::GetLastError() != ERROR_ACCESS_DENIED) { | |
238 return SBOX_TEST_FAILED; | |
239 } | |
240 } | |
241 | |
242 // Open by name with WRITE_DAC. | |
243 desktop = ::OpenDesktop(desktop_name, 0, FALSE, WRITE_DAC); | |
244 if (!desktop && ::GetLastError() == ERROR_ACCESS_DENIED) | |
245 return SBOX_TEST_DENIED; | |
246 ::CloseDesktop(desktop); | |
247 return SBOX_TEST_SUCCEEDED; | |
248 } | |
249 | |
250 BOOL CALLBACK DesktopTestEnumProc(LPTSTR desktop_name, LPARAM result) { | |
251 return TRUE; | |
252 } | |
253 | |
254 SBOX_TESTS_COMMAND int EnumAlternateWinsta(int, wchar_t **) { | |
255 return TestEnumAlternateWinsta(); | |
256 } | |
257 | |
258 int TestEnumAlternateWinsta() { | |
259 // Try to enumerate the destops on the alternate windowstation. | |
260 return ::EnumDesktopsW(NULL, DesktopTestEnumProc, 0) ? | |
261 SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED; | |
262 } | |
263 | |
264 SBOX_TESTS_COMMAND int SleepCmd(int argc, wchar_t **argv) { | |
265 if (argc != 1) | |
266 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
267 | |
268 ::Sleep(_wtoi(argv[0])); | |
269 return SBOX_TEST_SUCCEEDED; | |
270 } | |
271 | |
272 SBOX_TESTS_COMMAND int AllocateCmd(int argc, wchar_t **argv) { | |
273 if (argc != 1) | |
274 return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND; | |
275 | |
276 size_t mem_size = static_cast<size_t>(_wtoll(argv[0])); | |
277 void* memory = ::VirtualAlloc(NULL, mem_size, MEM_COMMIT | MEM_RESERVE, | |
278 PAGE_READWRITE); | |
279 if (!memory) { | |
280 // We need to give the broker a chance to kill our process on failure. | |
281 ::Sleep(5000); | |
282 return SBOX_TEST_DENIED; | |
283 } | |
284 | |
285 return ::VirtualFree(memory, 0, MEM_RELEASE) ? | |
286 SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED; | |
287 } | |
288 | |
289 | |
290 } // namespace sandbox | |
OLD | NEW |