1 // Copyright (c) 2011 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.
5 #include "sandbox/src/handle_table.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "sandbox/src/win_utils.h"
15 bool CompareHandleEntries(const SYSTEM_HANDLE_INFORMATION
& a
,
16 const SYSTEM_HANDLE_INFORMATION
& b
) {
17 return a
.ProcessId
< b
.ProcessId
;
24 const char16
* HandleTable::kTypeProcess
= L
"Process";
25 const char16
* HandleTable::kTypeThread
= L
"Thread";
26 const char16
* HandleTable::kTypeFile
= L
"File";
27 const char16
* HandleTable::kTypeDirectory
= L
"Directory";
28 const char16
* HandleTable::kTypeKey
= L
"Key";
29 const char16
* HandleTable::kTypeWindowStation
= L
"WindowStation";
30 const char16
* HandleTable::kTypeDesktop
= L
"Desktop";
31 const char16
* HandleTable::kTypeService
= L
"Service";
32 const char16
* HandleTable::kTypeMutex
= L
"Mutex";
33 const char16
* HandleTable::kTypeSemaphore
= L
"Semaphore";
34 const char16
* HandleTable::kTypeEvent
= L
"Event";
35 const char16
* HandleTable::kTypeTimer
= L
"Timer";
36 const char16
* HandleTable::kTypeNamedPipe
= L
"NamedPipe";
37 const char16
* HandleTable::kTypeJobObject
= L
"JobObject";
38 const char16
* HandleTable::kTypeFileMap
= L
"FileMap";
39 const char16
* HandleTable::kTypeAlpcPort
= L
"ALPC Port";
41 HandleTable::HandleTable() {
42 static NtQuerySystemInformation QuerySystemInformation
= NULL
;
43 if (!QuerySystemInformation
)
44 ResolveNTFunctionPtr("NtQuerySystemInformation", &QuerySystemInformation
);
49 handle_info_buffer_
.resize(size
);
50 result
= QuerySystemInformation(SystemHandleInformation
,
51 handle_info_internal(), size
, &size
);
52 } while (result
== STATUS_INFO_LENGTH_MISMATCH
);
54 // We failed, so make an empty table.
55 if (!NT_SUCCESS(result
)) {
56 handle_info_buffer_
.resize(0);
60 // Sort it to make process lookups faster.
61 std::sort(handle_info_internal()->Information
,
62 handle_info_internal()->Information
+
63 handle_info_internal()->NumberOfHandles
, CompareHandleEntries
);
66 HandleTable::Iterator
HandleTable::HandlesForProcess(ULONG process_id
) const {
67 SYSTEM_HANDLE_INFORMATION key
;
68 key
.ProcessId
= process_id
;
70 const SYSTEM_HANDLE_INFORMATION
* start
= handle_info()->Information
;
71 const SYSTEM_HANDLE_INFORMATION
* finish
=
72 &handle_info()->Information
[handle_info()->NumberOfHandles
];
74 start
= std::lower_bound(start
, finish
, key
, CompareHandleEntries
);
75 if (start
->ProcessId
!= process_id
)
76 return Iterator(*this, finish
, finish
);
77 finish
= std::upper_bound(start
, finish
, key
, CompareHandleEntries
);
78 return Iterator(*this, start
, finish
);
81 HandleTable::HandleEntry::HandleEntry(
82 const SYSTEM_HANDLE_INFORMATION
* handle_info_entry
)
83 : handle_entry_(handle_info_entry
), last_entry_(0) {
86 void HandleTable::HandleEntry::UpdateInfo(UpdateType flag
) {
87 static NtQueryObject QueryObject
= NULL
;
89 ResolveNTFunctionPtr("NtQueryObject", &QueryObject
);
93 // Always update the basic type info, but grab the names as needed.
94 if (needs_info_update()) {
97 last_entry_
= handle_entry_
;
99 // Most handle names are very short, so start small and reuse this buffer.
100 if (type_info_buffer_
.empty())
101 type_info_buffer_
.resize(sizeof(OBJECT_TYPE_INFORMATION
)
102 + (32 * sizeof(wchar_t)));
103 ULONG size
= static_cast<ULONG
>(type_info_buffer_
.size());
104 result
= QueryObject(reinterpret_cast<HANDLE
>(handle_entry_
->Handle
),
105 ObjectTypeInformation
, type_info_internal(), size
, &size
);
106 while (result
== STATUS_INFO_LENGTH_MISMATCH
) {
107 type_info_buffer_
.resize(size
);
108 result
= QueryObject(reinterpret_cast<HANDLE
>(handle_entry_
->Handle
),
109 ObjectTypeInformation
, type_info_internal(), size
, &size
);
112 if (!NT_SUCCESS(result
)) {
113 type_info_buffer_
.clear();
118 // Don't bother copying out names until we ask for them, and then cache them.
120 case UPDATE_INFO_AND_NAME
:
121 if (type_info_buffer_
.size() && handle_name_
.empty()) {
122 ULONG size
= MAX_PATH
;
123 scoped_ptr
<UNICODE_STRING
> name
;
125 name
.reset(reinterpret_cast<UNICODE_STRING
*>(new BYTE
[size
]));
126 result
= QueryObject(reinterpret_cast<HANDLE
>(
127 handle_entry_
->Handle
), ObjectNameInformation
, name
.get(),
129 } while (result
== STATUS_INFO_LENGTH_MISMATCH
);
131 if (NT_SUCCESS(result
)) {
132 handle_name_
.assign(name
->Buffer
, name
->Length
/ sizeof(wchar_t));
137 case UPDATE_INFO_AND_TYPE_NAME
:
138 if (!type_info_buffer_
.empty() && type_info_internal()->Name
.Buffer
&&
139 type_name_
.empty()) {
140 type_name_
.assign(type_info_internal()->Name
.Buffer
,
141 type_info_internal()->Name
.Length
/ sizeof(wchar_t));
147 const OBJECT_TYPE_INFORMATION
* HandleTable::HandleEntry::TypeInfo() {
148 UpdateInfo(UPDATE_INFO_ONLY
);
149 return type_info_buffer_
.empty() ? NULL
: type_info_internal();
152 const string16
& HandleTable::HandleEntry::Name() {
153 UpdateInfo(UPDATE_INFO_AND_NAME
);
157 const string16
& HandleTable::HandleEntry::Type() {
158 UpdateInfo(UPDATE_INFO_AND_TYPE_NAME
);
162 bool HandleTable::HandleEntry::IsType(const string16
& type_string
) {
163 UpdateInfo(UPDATE_INFO_ONLY
);
164 if (type_info_buffer_
.empty())
166 return type_string
.compare(0,
167 type_info_internal()->Name
.Length
/ sizeof(wchar_t),
168 type_info_internal()->Name
.Buffer
) == 0;
171 HandleTable::Iterator::Iterator(const HandleTable
& table
,
172 const SYSTEM_HANDLE_INFORMATION
* start
,
173 const SYSTEM_HANDLE_INFORMATION
* end
)
174 : table_(table
), current_(start
), end_(end
) {
177 HandleTable::Iterator::Iterator(const Iterator
& it
)
178 : table_(it
.table_
), current_(it
.current_
.handle_entry_
), end_(it
.end_
) {
181 } // namespace sandbox