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