• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
InitNT()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 
ParseKernelObjects(ATL::CString path)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 
TestKernelObjectAccess(ATL::CString path,ATL::CString type)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 
NtGenericOpen(ACCESS_MASK desired_access,OBJECT_ATTRIBUTES * object_attributes,NTGENERICOPEN func_to_call,HANDLE * handle)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 
GetFunctionForType(ATL::CString type,NTGENERICOPEN * func_to_call)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