1 // Copyright (c) 2006-2008 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 "sandbox/win/src/restricted_token.h" 6 #include "sandbox/win/src/restricted_token_utils.h" 7 #include "sandbox/win/tools/finder/finder.h" 8 #include "sandbox/win/tools/finder/ntundoc.h" 9 10 #define BUFFER_SIZE 0x800 11 #define CHECKPTR(x) if (!x) return ::GetLastError() 12 13 // NT API 14 NTQUERYDIRECTORYOBJECT NtQueryDirectoryObject; 15 NTOPENDIRECTORYOBJECT NtOpenDirectoryObject; 16 NTOPENEVENT NtOpenEvent; 17 NTOPENJOBOBJECT NtOpenJobObject; 18 NTOPENKEYEDEVENT NtOpenKeyedEvent; 19 NTOPENMUTANT NtOpenMutant; 20 NTOPENSECTION NtOpenSection; 21 NTOPENSEMAPHORE NtOpenSemaphore; 22 NTOPENSYMBOLICLINKOBJECT NtOpenSymbolicLinkObject; 23 NTOPENTIMER NtOpenTimer; 24 NTOPENFILE NtOpenFile; 25 NTCLOSE NtClose; 26 27 DWORD Finder::InitNT() { 28 HMODULE ntdll_handle = ::LoadLibrary(L"ntdll.dll"); 29 CHECKPTR(ntdll_handle); 30 31 NtOpenSymbolicLinkObject = (NTOPENSYMBOLICLINKOBJECT) ::GetProcAddress( 32 ntdll_handle, "NtOpenSymbolicLinkObject"); 33 CHECKPTR(NtOpenSymbolicLinkObject); 34 35 NtQueryDirectoryObject = (NTQUERYDIRECTORYOBJECT) ::GetProcAddress( 36 ntdll_handle, "NtQueryDirectoryObject"); 37 CHECKPTR(NtQueryDirectoryObject); 38 39 NtOpenDirectoryObject = (NTOPENDIRECTORYOBJECT) ::GetProcAddress( 40 ntdll_handle, "NtOpenDirectoryObject"); 41 CHECKPTR(NtOpenDirectoryObject); 42 43 NtOpenKeyedEvent = (NTOPENKEYEDEVENT) ::GetProcAddress( 44 ntdll_handle, "NtOpenKeyedEvent"); 45 CHECKPTR(NtOpenKeyedEvent); 46 47 NtOpenJobObject = (NTOPENJOBOBJECT) ::GetProcAddress( 48 ntdll_handle, "NtOpenJobObject"); 49 CHECKPTR(NtOpenJobObject); 50 51 NtOpenSemaphore = (NTOPENSEMAPHORE) ::GetProcAddress( 52 ntdll_handle, "NtOpenSemaphore"); 53 CHECKPTR(NtOpenSemaphore); 54 55 NtOpenSection = (NTOPENSECTION) ::GetProcAddress( 56 ntdll_handle, "NtOpenSection"); 57 CHECKPTR(NtOpenSection); 58 59 NtOpenMutant= (NTOPENMUTANT) ::GetProcAddress(ntdll_handle, "NtOpenMutant"); 60 CHECKPTR(NtOpenMutant); 61 62 NtOpenEvent = (NTOPENEVENT) ::GetProcAddress(ntdll_handle, "NtOpenEvent"); 63 CHECKPTR(NtOpenEvent); 64 65 NtOpenTimer = (NTOPENTIMER) ::GetProcAddress(ntdll_handle, "NtOpenTimer"); 66 CHECKPTR(NtOpenTimer); 67 68 NtOpenFile = (NTOPENFILE) ::GetProcAddress(ntdll_handle, "NtOpenFile"); 69 CHECKPTR(NtOpenFile); 70 71 NtClose = (NTCLOSE) ::GetProcAddress(ntdll_handle, "NtClose"); 72 CHECKPTR(NtClose); 73 74 return ERROR_SUCCESS; 75 } 76 77 DWORD Finder::ParseKernelObjects(ATL::CString path) { 78 UNICODE_STRING unicode_str; 79 unicode_str.Length = (USHORT)path.GetLength()*2; 80 unicode_str.MaximumLength = (USHORT)path.GetLength()*2+2; 81 unicode_str.Buffer = path.GetBuffer(); 82 83 OBJECT_ATTRIBUTES path_attributes; 84 InitializeObjectAttributes(&path_attributes, 85 &unicode_str, 86 0, // No Attributes 87 NULL, // No Root Directory 88 NULL); // No Security Descriptor 89 90 91 DWORD object_index = 0; 92 DWORD data_written = 0; 93 94 // TODO(nsylvain): Do not use BUFFER_SIZE. Try to get the size 95 // dynamically. 96 OBJDIR_INFORMATION *object_directory_info = 97 (OBJDIR_INFORMATION*) ::HeapAlloc(GetProcessHeap(), 98 0, 99 BUFFER_SIZE); 100 101 HANDLE file_handle; 102 NTSTATUS status_code = NtOpenDirectoryObject(&file_handle, 103 DIRECTORY_QUERY, 104 &path_attributes); 105 if (status_code != 0) 106 return ERROR_UNIDENTIFIED_ERROR; 107 108 status_code = NtQueryDirectoryObject(file_handle, 109 object_directory_info, 110 BUFFER_SIZE, 111 TRUE, // Get Next Index 112 TRUE, // Ignore Input Index 113 &object_index, 114 &data_written); 115 116 if (status_code != 0) 117 return ERROR_UNIDENTIFIED_ERROR; 118 119 while (NtQueryDirectoryObject(file_handle, object_directory_info, 120 BUFFER_SIZE, TRUE, FALSE, &object_index, 121 &data_written) == 0 ) { 122 ATL::CString cur_path(object_directory_info->ObjectName.Buffer, 123 object_directory_info->ObjectName.Length / sizeof(WCHAR)); 124 125 ATL::CString cur_type(object_directory_info->ObjectTypeName.Buffer, 126 object_directory_info->ObjectTypeName.Length / sizeof(WCHAR)); 127 128 ATL::CString new_path; 129 if (path == L"\\") { 130 new_path = path + cur_path; 131 } else { 132 new_path = path + L"\\" + cur_path; 133 } 134 135 TestKernelObjectAccess(new_path, cur_type); 136 137 // Call the function recursively for all subdirectories 138 if (cur_type == L"Directory") { 139 ParseKernelObjects(new_path); 140 } 141 } 142 143 NtClose(file_handle); 144 return ERROR_SUCCESS; 145 } 146 147 DWORD Finder::TestKernelObjectAccess(ATL::CString path, ATL::CString type) { 148 Impersonater impersonate(token_handle_); 149 150 kernel_object_stats_[PARSE]++; 151 152 NTGENERICOPEN func = NULL; 153 GetFunctionForType(type, &func); 154 155 if (!func) { 156 kernel_object_stats_[BROKEN]++; 157 Output(OBJ_ERR, type + L" Unsupported", path); 158 return ERROR_UNSUPPORTED_TYPE; 159 } 160 161 UNICODE_STRING unicode_str; 162 unicode_str.Length = (USHORT)path.GetLength()*2; 163 unicode_str.MaximumLength = (USHORT)path.GetLength()*2+2; 164 unicode_str.Buffer = path.GetBuffer(); 165 166 OBJECT_ATTRIBUTES path_attributes; 167 InitializeObjectAttributes(&path_attributes, 168 &unicode_str, 169 0, // No Attributes 170 NULL, // No Root Directory 171 NULL); // No Security Descriptor 172 173 HANDLE handle; 174 NTSTATUS status_code = 0; 175 176 if (access_type_ & kTestForAll) { 177 status_code = NtGenericOpen(GENERIC_ALL, &path_attributes, func, &handle); 178 if (STATUS_SUCCESS == status_code) { 179 kernel_object_stats_[ALL]++; 180 Output(OBJ, L"R/W", path); 181 NtClose(handle); 182 return GENERIC_ALL; 183 } else if (status_code != EXCEPTION_ACCESS_VIOLATION && 184 status_code != STATUS_ACCESS_DENIED) { 185 Output(OBJ_ERR, status_code, path); 186 kernel_object_stats_[BROKEN]++; 187 } 188 } 189 190 if (access_type_ & kTestForWrite) { 191 status_code = NtGenericOpen(GENERIC_WRITE, &path_attributes, func, &handle); 192 if (STATUS_SUCCESS == status_code) { 193 kernel_object_stats_[WRITE]++; 194 Output(OBJ, L"W", path); 195 NtClose(handle); 196 return GENERIC_WRITE; 197 } else if (status_code != EXCEPTION_ACCESS_VIOLATION && 198 status_code != STATUS_ACCESS_DENIED) { 199 Output(OBJ_ERR, status_code, path); 200 kernel_object_stats_[BROKEN]++; 201 } 202 } 203 204 if (access_type_ & kTestForRead) { 205 status_code = NtGenericOpen(GENERIC_READ, &path_attributes, func, &handle); 206 if (STATUS_SUCCESS == status_code) { 207 kernel_object_stats_[READ]++; 208 Output(OBJ, L"R", path); 209 NtClose(handle); 210 return GENERIC_READ; 211 } else if (status_code != EXCEPTION_ACCESS_VIOLATION && 212 status_code != STATUS_ACCESS_DENIED) { 213 Output(OBJ_ERR, status_code, path); 214 kernel_object_stats_[BROKEN]++; 215 } 216 } 217 218 return 0; 219 } 220 221 NTSTATUS Finder::NtGenericOpen(ACCESS_MASK desired_access, 222 OBJECT_ATTRIBUTES *object_attributes, 223 NTGENERICOPEN func_to_call, 224 HANDLE *handle) { 225 return func_to_call(handle, desired_access, object_attributes); 226 } 227 228 bool Finder::GetFunctionForType(ATL::CString type, 229 NTGENERICOPEN * func_to_call) { 230 NTGENERICOPEN func = NULL; 231 232 if (type == L"Event") func = NtOpenEvent; 233 else if (type == L"Job") func = NtOpenJobObject; 234 else if (type == L"KeyedEvent") func = NtOpenKeyedEvent; 235 else if (type == L"Mutant") func = NtOpenMutant; 236 else if (type == L"Section") func = NtOpenSection; 237 else if (type == L"Semaphore") func = NtOpenSemaphore; 238 else if (type == L"Timer") func = NtOpenTimer; 239 else if (type == L"SymbolicLink") func = NtOpenSymbolicLinkObject; 240 else if (type == L"Directory") func = NtOpenDirectoryObject; 241 242 if (func) { 243 *func_to_call = func; 244 return true; 245 } 246 247 return false; 248 } 249