Home | History | Annotate | Download | only in finder
      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