1// Copyright (c) 2006-2010 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/sandbox_poc/pocdll/exports.h"
6#include "sandbox/win/sandbox_poc/pocdll/utils.h"
7#include "sandbox/win/tools/finder/ntundoc.h"
8
9// This file contains the tests used to verify the security of handles in
10// the process
11
12NTQUERYOBJECT NtQueryObject;
13NTQUERYINFORMATIONFILE NtQueryInformationFile;
14NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;
15
16void POCDLL_API TestGetHandle(HANDLE log) {
17  HandleToFile handle2file;
18  FILE *output = handle2file.Translate(log, "w");
19
20  // Initialize the NTAPI functions we need
21  HMODULE ntdll_handle = ::GetModuleHandle(L"ntdll.dll");
22  if (!ntdll_handle) {
23    fprintf(output, "[ERROR] Cannot load ntdll.dll. Error %ld\r\n",
24            ::GetLastError());
25    return;
26  }
27
28  NtQueryObject = reinterpret_cast<NTQUERYOBJECT>(
29                      GetProcAddress(ntdll_handle, "NtQueryObject"));
30  NtQueryInformationFile = reinterpret_cast<NTQUERYINFORMATIONFILE>(
31                      GetProcAddress(ntdll_handle, "NtQueryInformationFile"));
32  NtQuerySystemInformation = reinterpret_cast<NTQUERYSYSTEMINFORMATION>(
33                      GetProcAddress(ntdll_handle, "NtQuerySystemInformation"));
34
35  if (!NtQueryObject || !NtQueryInformationFile || !NtQuerySystemInformation) {
36    fprintf(output, "[ERROR] Cannot load all NT functions. Error %ld\r\n",
37                    ::GetLastError());
38    return;
39  }
40
41  // Get the number of handles on the system
42  DWORD buffer_size = 0;
43  SYSTEM_HANDLE_INFORMATION_EX temp_info;
44  NTSTATUS status = NtQuerySystemInformation(
45      SystemHandleInformation, &temp_info, sizeof(temp_info),
46      &buffer_size);
47  if (!buffer_size) {
48    fprintf(output, "[ERROR] Get the number of handles. Error 0x%lX\r\n",
49                    status);
50    return;
51  }
52
53  SYSTEM_HANDLE_INFORMATION_EX *system_handles =
54      reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(new BYTE[buffer_size]);
55
56  status = NtQuerySystemInformation(SystemHandleInformation, system_handles,
57                                    buffer_size, &buffer_size);
58  if (STATUS_SUCCESS != status) {
59    fprintf(output, "[ERROR] Failed to get the handle list. Error 0x%lX\r\n",
60                    status);
61    delete [] system_handles;
62    return;
63  }
64
65  for (ULONG i = 0; i < system_handles->NumberOfHandles; ++i) {
66    USHORT h = system_handles->Information[i].Handle;
67    if (system_handles->Information[i].ProcessId != ::GetCurrentProcessId())
68      continue;
69
70    OBJECT_NAME_INFORMATION *name = NULL;
71    ULONG name_size = 0;
72    // Query the name information a first time to get the size of the name.
73    status = NtQueryObject(reinterpret_cast<HANDLE>(h),
74                           ObjectNameInformation,
75                           name,
76                           name_size,
77                           &name_size);
78
79    if (name_size) {
80      name = reinterpret_cast<OBJECT_NAME_INFORMATION *>(new BYTE[name_size]);
81
82      // Query the name information a second time to get the name of the
83      // object referenced by the handle.
84      status = NtQueryObject(reinterpret_cast<HANDLE>(h),
85                             ObjectNameInformation,
86                             name,
87                             name_size,
88                             &name_size);
89    }
90
91    PUBLIC_OBJECT_TYPE_INFORMATION *type = NULL;
92    ULONG type_size = 0;
93
94    // Query the object to get the size of the object type name.
95    status = NtQueryObject(reinterpret_cast<HANDLE>(h),
96                           ObjectTypeInformation,
97                           type,
98                           type_size,
99                           &type_size);
100    if (type_size) {
101      type = reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION *>(
102          new BYTE[type_size]);
103
104      // Query the type information a second time to get the object type
105      // name.
106      status = NtQueryObject(reinterpret_cast<HANDLE>(h),
107                             ObjectTypeInformation,
108                             type,
109                             type_size,
110                             &type_size);
111    }
112
113    // NtQueryObject cannot return the name for a file. In this case we
114    // need to ask NtQueryInformationFile
115    FILE_NAME_INFORMATION *file_name = NULL;
116    if (type && wcsncmp(L"File", type->TypeName.Buffer,
117                        (type->TypeName.Length /
118                        sizeof(type->TypeName.Buffer[0]))) == 0)  {
119      // This function does not return the size of the buffer. We need to
120      // iterate and always increase the buffer size until the function
121      // succeeds. (Or at least does not fail with STATUS_BUFFER_OVERFLOW)
122      ULONG size_file = MAX_PATH;
123      IO_STATUS_BLOCK status_block = {0};
124      do {
125        // Delete the previous buffer create. The buffer was too small
126        if (file_name) {
127          delete[] reinterpret_cast<BYTE*>(file_name);
128          file_name = NULL;
129        }
130
131        // Increase the buffer and do the call agan
132        size_file += MAX_PATH;
133        file_name = reinterpret_cast<FILE_NAME_INFORMATION *>(
134            new BYTE[size_file]);
135        status = NtQueryInformationFile(reinterpret_cast<HANDLE>(h),
136                                        &status_block,
137                                        file_name,
138                                        size_file,
139                                        FileNameInformation);
140      } while (status == STATUS_BUFFER_OVERFLOW);
141
142      if (STATUS_SUCCESS != status) {
143        if (file_name) {
144          delete[] file_name;
145          file_name = NULL;
146        }
147      }
148    }
149
150    if (file_name) {
151      UNICODE_STRING file_name_string;
152      file_name_string.Buffer = file_name->FileName;
153      file_name_string.Length = (USHORT)file_name->FileNameLength;
154      file_name_string.MaximumLength = (USHORT)file_name->FileNameLength;
155      fprintf(output, "[GRANTED] Handle 0x%4.4X Access: 0x%8.8lX "
156                      "Type: %-13wZ Path: %wZ\r\n",
157                      h,
158                      system_handles->Information[i].GrantedAccess,
159                      type ? &type->TypeName : NULL,
160                      &file_name_string);
161    } else {
162      fprintf(output, "[GRANTED] Handle 0x%4.4X Access: 0x%8.8lX "
163                      "Type: %-13wZ Path: %wZ\r\n",
164                      h,
165                      system_handles->Information[i].GrantedAccess,
166                      type ? &type->TypeName : NULL,
167                      name ? &name->ObjectName : NULL);
168    }
169
170    if (type) {
171      delete[] type;
172    }
173
174    if (file_name) {
175      delete[] file_name;
176    }
177
178    if (name) {
179      delete [] name;
180    }
181  }
182
183  if (system_handles) {
184    delete [] system_handles;
185  }
186}
187