Skip to content

Commit 71dd57b

Browse files
committed
Merge mozilla central to autoland. r=merge a=merge on a CLOSED TREE
2 parents 21a9757 + 8e96105 commit 71dd57b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1123
-672
lines changed

accessible/base/Platform.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ bool IsHandlerRegistered();
5252
/*
5353
* Name of platform service that instantiated accessibility
5454
*/
55-
void SetInstantiator(const nsAString& aInstantiator);
56-
bool GetInstantiator(nsAString& aInstantiator);
55+
void SetInstantiator(const uint32_t aInstantiatorPid);
56+
bool GetInstantiator(nsIFile** aOutInstantiator);
5757
#endif
5858

5959
/**

accessible/windows/msaa/Compatibility.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#ifndef COMPATIBILITY_MANAGER_H
88
#define COMPATIBILITY_MANAGER_H
99

10+
#include "mozilla/Maybe.h"
1011
#include "nsString.h"
1112
#include <stdint.h>
1213

@@ -57,6 +58,10 @@ class Compatibility
5758
*/
5859
static void Init();
5960

61+
static Maybe<bool> OnUIAMessage(WPARAM aWParam, LPARAM aLParam);
62+
63+
static Maybe<DWORD> GetUiaRemotePid() { return sUiaRemotePid; }
64+
6065
/**
6166
* return true if a known, non-UIA a11y consumer is present
6267
*/
@@ -90,6 +95,7 @@ class Compatibility
9095

9196
private:
9297
static uint32_t sConsumers;
98+
static Maybe<DWORD> sUiaRemotePid;
9399
};
94100

95101
} // a11y namespace
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#include "Compatibility.h"
8+
9+
#include "mozilla/Telemetry.h"
10+
11+
#include "nsPrintfCString.h"
12+
#include "nsReadableUtils.h"
13+
#include "nsString.h"
14+
#include "nsUnicharUtils.h"
15+
#include "nsWinUtils.h"
16+
17+
#include "NtUndoc.h"
18+
19+
#if defined(UIA_LOGGING)
20+
21+
#define LOG_ERROR(FuncName) \
22+
{ \
23+
DWORD err = ::GetLastError(); \
24+
nsPrintfCString msg(#FuncName " failed with code %u\n", err); \
25+
::OutputDebugStringA(msg.get()); \
26+
}
27+
28+
#else
29+
30+
#define LOG_ERROR(FuncName)
31+
32+
#endif // defined(UIA_LOGGING)
33+
34+
static bool
35+
GetLocalObjectHandle(DWORD aSrcPid, HANDLE aSrcHandle, nsAutoHandle& aProcess,
36+
nsAutoHandle& aLocal)
37+
{
38+
aLocal.reset();
39+
40+
if (!aProcess) {
41+
HANDLE rawProcess = ::OpenProcess(PROCESS_DUP_HANDLE, FALSE, aSrcPid);
42+
if (!rawProcess) {
43+
LOG_ERROR(OpenProcess);
44+
return false;
45+
}
46+
47+
aProcess.own(rawProcess);
48+
}
49+
50+
HANDLE rawDuped;
51+
if (!::DuplicateHandle(aProcess.get(), aSrcHandle, ::GetCurrentProcess(),
52+
&rawDuped, GENERIC_READ, FALSE, 0)) {
53+
LOG_ERROR(DuplicateHandle);
54+
return false;
55+
}
56+
57+
aLocal.own(rawDuped);
58+
59+
return true;
60+
}
61+
62+
namespace mozilla {
63+
namespace a11y {
64+
65+
Maybe<DWORD> Compatibility::sUiaRemotePid;
66+
67+
Maybe<bool>
68+
Compatibility::OnUIAMessage(WPARAM aWParam, LPARAM aLParam)
69+
{
70+
Maybe<DWORD>& remotePid = sUiaRemotePid;
71+
auto clearUiaRemotePid = MakeScopeExit([&remotePid]() {
72+
remotePid = Nothing();
73+
});
74+
75+
static auto pNtQuerySystemInformation =
76+
reinterpret_cast<decltype(&::NtQuerySystemInformation)>(
77+
::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"),
78+
"NtQuerySystemInformation"));
79+
80+
static auto pNtQueryObject =
81+
reinterpret_cast<decltype(&::NtQueryObject)>(
82+
::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"), "NtQueryObject"));
83+
84+
// UIA creates a section containing the substring "HOOK_SHMEM_"
85+
NS_NAMED_LITERAL_STRING(kStrHookShmem, "HOOK_SHMEM_");
86+
87+
// The section name always ends with this suffix, which is derived from the
88+
// current thread id and the UIA message's WPARAM and LPARAM.
89+
nsAutoString partialSectionSuffix;
90+
partialSectionSuffix.AppendPrintf("_%08x_%08x_%08x", ::GetCurrentThreadId(),
91+
aLParam, aWParam);
92+
93+
NTSTATUS ntStatus;
94+
95+
// First we must query for a list of all the open handles in the system.
96+
UniquePtr<char[]> handleInfoBuf;
97+
ULONG handleInfoBufLen = sizeof(SYSTEM_HANDLE_INFORMATION_EX) +
98+
1024 * sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
99+
100+
// We must query for handle information in a loop, since we are effectively
101+
// asking the kernel to take a snapshot of all the handles on the system;
102+
// the size of the required buffer may fluctuate between successive calls.
103+
while (true) {
104+
handleInfoBuf = MakeUnique<char[]>(handleInfoBufLen);
105+
106+
ntStatus = pNtQuerySystemInformation(
107+
(SYSTEM_INFORMATION_CLASS) SystemExtendedHandleInformation,
108+
handleInfoBuf.get(), handleInfoBufLen, &handleInfoBufLen);
109+
if (ntStatus == STATUS_INFO_LENGTH_MISMATCH) {
110+
continue;
111+
}
112+
113+
if (!NT_SUCCESS(ntStatus)) {
114+
return Nothing();
115+
}
116+
117+
break;
118+
}
119+
120+
// Now we iterate through the system handle list, searching for a section
121+
// handle whose name matches the section name used by UIA.
122+
123+
static Maybe<USHORT> sSectionObjTypeIndex;
124+
125+
const DWORD ourPid = ::GetCurrentProcessId();
126+
127+
Maybe<PVOID> kernelObject;
128+
129+
ULONG lastPid = 0;
130+
nsAutoHandle process;
131+
132+
auto handleInfo = reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(handleInfoBuf.get());
133+
134+
for (ULONG index = 0; index < handleInfo->mHandleCount; ++index) {
135+
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX& curHandle = handleInfo->mHandles[index];
136+
137+
if (lastPid && lastPid == curHandle.mPid && !process) {
138+
// During the previous iteration, we could not obtain a handle for this
139+
// pid. Skip any remaining handles belonging to that pid.
140+
continue;
141+
}
142+
143+
// As a perf optimization, we reuse the same process handle as long as we're
144+
// still looking at the same pid. Once the pid changes, we need to reset
145+
// process so that we open a new handle to the newly-seen process.
146+
if (lastPid != curHandle.mPid) {
147+
process.reset();
148+
}
149+
150+
nsAutoHandle handle;
151+
152+
if (kernelObject.isSome() && kernelObject.value() == curHandle.mObject) {
153+
// If we know the value of the underlying kernel object, we can immediately
154+
// check for equality by comparing against curHandle.mObject
155+
remotePid = Some(static_cast<DWORD>(curHandle.mPid));
156+
break;
157+
} else if (sSectionObjTypeIndex.isSome()) {
158+
// Otherwise, if we know which object type value corresponds to a Section
159+
// object, we can use that to eliminate any handles that are not sections.
160+
if (curHandle.mObjectTypeIndex != sSectionObjTypeIndex.value()) {
161+
// Not a section handle
162+
continue;
163+
}
164+
} else {
165+
// Otherwise we need to query the handle to determine its type. Note that
166+
// each handle in the system list is relative to its owning process, so
167+
// we cannot do anything with it until we duplicate the handle into our
168+
// own process.
169+
170+
lastPid = curHandle.mPid;
171+
172+
if (!GetLocalObjectHandle((DWORD) curHandle.mPid,
173+
(HANDLE) curHandle.mHandle,
174+
process, handle)) {
175+
// We don't have access to do this, assume this handle isn't relevant
176+
continue;
177+
}
178+
179+
// Now we have our own handle to the object, lets find out what type of
180+
// object this handle represents. Any handle whose type is not "Section"
181+
// is of no interest to us.
182+
ULONG objTypeBufLen;
183+
ntStatus = pNtQueryObject(handle, ObjectTypeInformation, nullptr,
184+
0, &objTypeBufLen);
185+
if (ntStatus != STATUS_INFO_LENGTH_MISMATCH) {
186+
continue;
187+
}
188+
189+
auto objTypeBuf = MakeUnique<char[]>(objTypeBufLen);
190+
ntStatus = pNtQueryObject(handle, ObjectTypeInformation, objTypeBuf.get(),
191+
objTypeBufLen, &objTypeBufLen);
192+
if (!NT_SUCCESS(ntStatus)) {
193+
// We don't have access to do this, assume this handle isn't relevant
194+
continue;
195+
}
196+
197+
auto objType =
198+
reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION*>(objTypeBuf.get());
199+
200+
nsDependentString objTypeName(objType->TypeName.Buffer,
201+
objType->TypeName.Length / sizeof(wchar_t));
202+
if (!objTypeName.Equals(NS_LITERAL_STRING("Section"))) {
203+
// Not a section, so we don't care about this handle anymore.
204+
continue;
205+
}
206+
207+
// We have a section, save this handle's type code so that we can go
208+
// faster in future iterations.
209+
sSectionObjTypeIndex = Some(curHandle.mObjectTypeIndex);
210+
}
211+
212+
// If we reached this point without needing to query the handle, then we
213+
// need to open it here so that we can query its name.
214+
lastPid = curHandle.mPid;
215+
216+
if ((!process || !handle) &&
217+
!GetLocalObjectHandle((DWORD) curHandle.mPid, (HANDLE) curHandle.mHandle,
218+
process, handle)) {
219+
// We don't have access to do this, assume this handle isn't relevant
220+
continue;
221+
}
222+
223+
// At this point, |handle| is a valid section handle. Let's try to find
224+
// out the name of its underlying object.
225+
ULONG objNameBufLen;
226+
ntStatus = pNtQueryObject(handle,
227+
(OBJECT_INFORMATION_CLASS)ObjectNameInformation,
228+
nullptr, 0, &objNameBufLen);
229+
if (ntStatus != STATUS_INFO_LENGTH_MISMATCH) {
230+
continue;
231+
}
232+
233+
auto objNameBuf = MakeUnique<char[]>(objNameBufLen);
234+
ntStatus = pNtQueryObject(handle,
235+
(OBJECT_INFORMATION_CLASS)ObjectNameInformation,
236+
objNameBuf.get(), objNameBufLen, &objNameBufLen);
237+
if (!NT_SUCCESS(ntStatus)) {
238+
continue;
239+
}
240+
241+
auto objNameInfo = reinterpret_cast<OBJECT_NAME_INFORMATION*>(objNameBuf.get());
242+
if (!objNameInfo->mName.Length) {
243+
// This section is unnamed. We don't care about those.
244+
continue;
245+
}
246+
247+
nsDependentString objName(objNameInfo->mName.Buffer,
248+
objNameInfo->mName.Length / sizeof(wchar_t));
249+
250+
// Check to see if the section's name matches our expected name.
251+
if (!FindInReadable(kStrHookShmem, objName) ||
252+
!StringEndsWith(objName, partialSectionSuffix)) {
253+
// The names don't match, continue searching.
254+
continue;
255+
}
256+
257+
// At this point we have a section handle whose name matches the one that
258+
// we're looking for.
259+
260+
if (curHandle.mPid == ourPid) {
261+
// Our own process also has a handle to the section of interest. While we
262+
// don't want our own pid, this *does* give us an opportunity to speed up
263+
// future iterations by examining each handle for its kernel object (which
264+
// is the same for all processes) instead of searching by name.
265+
kernelObject = Some(curHandle.mObject);
266+
continue;
267+
}
268+
269+
// Bingo! We want this pid!
270+
remotePid = Some(static_cast<DWORD>(curHandle.mPid));
271+
272+
break;
273+
}
274+
275+
if (!remotePid) {
276+
return Nothing();
277+
}
278+
279+
a11y::SetInstantiator(remotePid.value());
280+
281+
/* This is where we could block UIA stuff
282+
nsCOMPtr<nsIFile> instantiator;
283+
if (a11y::GetInstantiator(getter_AddRefs(instantiator)) &&
284+
ShouldBlockUIAClient(instantiator)) {
285+
return Some(false);
286+
}
287+
*/
288+
289+
return Some(true);
290+
}
291+
292+
} // namespace a11y
293+
} // namespace mozilla

0 commit comments

Comments
 (0)