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/win/src/handle_table.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "sandbox/win/src/win_utils.h"
16 bool CompareHandleEntries(const SYSTEM_HANDLE_INFORMATION
& a
,
17 const SYSTEM_HANDLE_INFORMATION
& b
) {
18 return a
.ProcessId
< b
.ProcessId
;
25 const base::char16
* HandleTable::kTypeProcess
= L
"Process";
26 const base::char16
* HandleTable::kTypeThread
= L
"Thread";
27 const base::char16
* HandleTable::kTypeFile
= L
"File";
28 const base::char16
* HandleTable::kTypeDirectory
= L
"Directory";
29 const base::char16
* HandleTable::kTypeKey
= L
"Key";
30 const base::char16
* HandleTable::kTypeWindowStation
= L
"WindowStation";
31 const base::char16
* HandleTable::kTypeDesktop
= L
"Desktop";
32 const base::char16
* HandleTable::kTypeService
= L
"Service";
33 const base::char16
* HandleTable::kTypeMutex
= L
"Mutex";
34 const base::char16
* HandleTable::kTypeSemaphore
= L
"Semaphore";
35 const base::char16
* HandleTable::kTypeEvent
= L
"Event";
36 const base::char16
* HandleTable::kTypeTimer
= L
"Timer";
37 const base::char16
* HandleTable::kTypeNamedPipe
= L
"NamedPipe";
38 const base::char16
* HandleTable::kTypeJobObject
= L
"JobObject";
39 const base::char16
* HandleTable::kTypeFileMap
= L
"FileMap";
40 const base::char16
* HandleTable::kTypeAlpcPort
= L
"ALPC Port";
42 HandleTable::HandleTable() {
43 static NtQuerySystemInformation QuerySystemInformation
= NULL
;
44 if (!QuerySystemInformation
)
45 ResolveNTFunctionPtr("NtQuerySystemInformation", &QuerySystemInformation
);
50 handle_info_buffer_
.resize(size
);
51 result
= QuerySystemInformation(SystemHandleInformation
,
52 handle_info_internal(), size
, &size
);
53 } while (result
== STATUS_INFO_LENGTH_MISMATCH
);
55 // We failed, so make an empty table.
56 if (!NT_SUCCESS(result
)) {
57 handle_info_buffer_
.resize(0);
61 // Sort it to make process lookups faster.
62 std::sort(handle_info_internal()->Information
,
63 handle_info_internal()->Information
+
64 handle_info_internal()->NumberOfHandles
, CompareHandleEntries
);
67 HandleTable::Iterator
HandleTable::HandlesForProcess(ULONG process_id
) const {
68 SYSTEM_HANDLE_INFORMATION key
;
69 key
.ProcessId
= process_id
;
71 const SYSTEM_HANDLE_INFORMATION
* start
= handle_info()->Information
;
72 const SYSTEM_HANDLE_INFORMATION
* finish
=
73 &handle_info()->Information
[handle_info()->NumberOfHandles
];
75 start
= std::lower_bound(start
, finish
, key
, CompareHandleEntries
);
76 if (start
->ProcessId
!= process_id
)
77 return Iterator(*this, finish
, finish
);
78 finish
= std::upper_bound(start
, finish
, key
, CompareHandleEntries
);
79 return Iterator(*this, start
, finish
);
82 HandleTable::HandleEntry::HandleEntry(
83 const SYSTEM_HANDLE_INFORMATION
* handle_info_entry
)
84 : handle_entry_(handle_info_entry
), last_entry_(0) {
87 void HandleTable::HandleEntry::UpdateInfo(UpdateType flag
) {
88 static NtQueryObject QueryObject
= NULL
;
90 ResolveNTFunctionPtr("NtQueryObject", &QueryObject
);
94 // Always update the basic type info, but grab the names as needed.
95 if (needs_info_update()) {
98 last_entry_
= handle_entry_
;
100 // Most handle names are very short, so start small and reuse this buffer.
101 if (type_info_buffer_
.empty())
102 type_info_buffer_
.resize(sizeof(OBJECT_TYPE_INFORMATION
)
103 + (32 * sizeof(wchar_t)));
104 ULONG size
= static_cast<ULONG
>(type_info_buffer_
.size());
105 result
= QueryObject(reinterpret_cast<HANDLE
>(handle_entry_
->Handle
),
106 ObjectTypeInformation
, type_info_internal(), size
, &size
);
107 while (result
== STATUS_INFO_LENGTH_MISMATCH
) {
108 type_info_buffer_
.resize(size
);
109 result
= QueryObject(reinterpret_cast<HANDLE
>(handle_entry_
->Handle
),
110 ObjectTypeInformation
, type_info_internal(), size
, &size
);
113 if (!NT_SUCCESS(result
)) {
114 type_info_buffer_
.clear();
119 // Don't bother copying out names until we ask for them, and then cache them.
121 case UPDATE_INFO_AND_NAME
:
122 if (type_info_buffer_
.size() && handle_name_
.empty()) {
123 ULONG size
= MAX_PATH
;
124 scoped_ptr
<UNICODE_STRING
, base::FreeDeleter
> name
;
126 name
.reset(static_cast<UNICODE_STRING
*>(malloc(size
)));
128 result
= QueryObject(reinterpret_cast<HANDLE
>(
129 handle_entry_
->Handle
), ObjectNameInformation
, name
.get(),
131 } while (result
== STATUS_INFO_LENGTH_MISMATCH
);
133 if (NT_SUCCESS(result
)) {
134 handle_name_
.assign(name
->Buffer
, name
->Length
/ sizeof(wchar_t));
139 case UPDATE_INFO_AND_TYPE_NAME
:
140 if (!type_info_buffer_
.empty() && type_info_internal()->Name
.Buffer
&&
141 type_name_
.empty()) {
142 type_name_
.assign(type_info_internal()->Name
.Buffer
,
143 type_info_internal()->Name
.Length
/ sizeof(wchar_t));
149 const OBJECT_TYPE_INFORMATION
* HandleTable::HandleEntry::TypeInfo() {
150 UpdateInfo(UPDATE_INFO_ONLY
);
151 return type_info_buffer_
.empty() ? NULL
: type_info_internal();
154 const base::string16
& HandleTable::HandleEntry::Name() {
155 UpdateInfo(UPDATE_INFO_AND_NAME
);
159 const base::string16
& HandleTable::HandleEntry::Type() {
160 UpdateInfo(UPDATE_INFO_AND_TYPE_NAME
);
164 bool HandleTable::HandleEntry::IsType(const base::string16
& type_string
) {
165 UpdateInfo(UPDATE_INFO_ONLY
);
166 if (type_info_buffer_
.empty())
168 return type_string
.compare(0,
169 type_info_internal()->Name
.Length
/ sizeof(wchar_t),
170 type_info_internal()->Name
.Buffer
) == 0;
173 HandleTable::Iterator::Iterator(const HandleTable
& table
,
174 const SYSTEM_HANDLE_INFORMATION
* start
,
175 const SYSTEM_HANDLE_INFORMATION
* end
)
176 : table_(table
), current_(start
), end_(end
) {
179 HandleTable::Iterator::Iterator(const Iterator
& it
)
180 : table_(it
.table_
), current_(it
.current_
.handle_entry_
), end_(it
.end_
) {
183 } // namespace sandbox