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