Home | History | Annotate | Download | only in validation_tests
      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 SBOX_TESTS_COMMAND int AllocateCmd(int argc, wchar_t **argv) {
    314   if (argc != 1)
    315     return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
    316 
    317   size_t mem_size = static_cast<size_t>(_wtoll(argv[0]));
    318   void* memory = ::VirtualAlloc(NULL, mem_size, MEM_COMMIT | MEM_RESERVE,
    319                                 PAGE_READWRITE);
    320   if (!memory) {
    321     // We need to give the broker a chance to kill our process on failure.
    322     ::Sleep(5000);
    323     return SBOX_TEST_DENIED;
    324   }
    325 
    326   if (!::VirtualFree(memory, 0, MEM_RELEASE))
    327     return SBOX_TEST_FAILED;
    328 
    329   return SBOX_TEST_SUCCEEDED;
    330 }
    331 
    332 
    333 }  // namespace sandbox
    334