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
14NTQUERYDIRECTORYOBJECT    NtQueryDirectoryObject;
15NTOPENDIRECTORYOBJECT     NtOpenDirectoryObject;
16NTOPENEVENT               NtOpenEvent;
17NTOPENJOBOBJECT           NtOpenJobObject;
18NTOPENKEYEDEVENT          NtOpenKeyedEvent;
19NTOPENMUTANT              NtOpenMutant;
20NTOPENSECTION             NtOpenSection;
21NTOPENSEMAPHORE           NtOpenSemaphore;
22NTOPENSYMBOLICLINKOBJECT  NtOpenSymbolicLinkObject;
23NTOPENTIMER               NtOpenTimer;
24NTOPENFILE                NtOpenFile;
25NTCLOSE                   NtClose;
26
27DWORD 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
77DWORD 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
147DWORD 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
221NTSTATUS 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
228bool 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