Bug 1418535: Block a11y instntiation if no known ATs are present and known bad DLLs are; r=jimm
authorAaron Klotz <aklotz@mozilla.com>
Mon, 20 Nov 2017 14:15:15 -0700
changeset 393103 1516807b05d3f6084b58d54b12032ccce5cbdcfc
parent 393102 ccc752e4699ff25a8a52415e88a922021f3b0350
child 393104 491fbd1c506fd120aec340b1c5a0d98a888fbdd5
push id32954
push usershindli@mozilla.com
push dateWed, 22 Nov 2017 21:30:30 +0000
treeherdermozilla-central@960f50c2e0a9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs1418535
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1418535: Block a11y instntiation if no known ATs are present and known bad DLLs are; r=jimm MozReview-Commit-ID: FtoEamY9P8r
accessible/windows/msaa/Compatibility.cpp
accessible/windows/msaa/Compatibility.h
accessible/windows/msaa/LazyInstantiator.cpp
accessible/windows/msaa/LazyInstantiator.h
--- a/accessible/windows/msaa/Compatibility.cpp
+++ b/accessible/windows/msaa/Compatibility.cpp
@@ -156,21 +156,22 @@ DetectInSendMessageExCompat(PEXCEPTION_P
       sVectoredExceptionHandler = nullptr;
     }
   }
   return EXCEPTION_CONTINUE_SEARCH;
 }
 
 uint32_t Compatibility::sConsumers = Compatibility::UNKNOWN;
 
-void
-Compatibility::Init()
+/**
+ * This function is safe to call multiple times.
+ */
+/* static */ void
+Compatibility::InitConsumers()
 {
-  // Note we collect some AT statistics/telemetry here for convenience.
-
   HMODULE jawsHandle = ::GetModuleHandleW(L"jhook");
   if (jawsHandle)
     sConsumers |= (IsModuleVersionLessThan(jawsHandle, 19, 0)) ?
                    OLDJAWS : JAWS;
 
   if (::GetModuleHandleW(L"gwm32inc"))
     sConsumers |= WE;
 
@@ -197,17 +198,31 @@ Compatibility::Init()
     sConsumers |= YOUDAO;
 
   if (::GetModuleHandleW(L"uiautomation") ||
       ::GetModuleHandleW(L"uiautomationcore"))
     sConsumers |= UIAUTOMATION;
 
   // If we have a known consumer remove the unknown bit.
   if (sConsumers != Compatibility::UNKNOWN)
-    sConsumers ^= Compatibility::UNKNOWN;
+    sConsumers &= ~Compatibility::UNKNOWN;
+}
+
+/* static */ bool
+Compatibility::HasKnownNonUiaConsumer()
+{
+  InitConsumers();
+  return sConsumers & ~(Compatibility::UNKNOWN | UIAUTOMATION);
+}
+
+void
+Compatibility::Init()
+{
+  // Note we collect some AT statistics/telemetry here for convenience.
+  InitConsumers();
 
 #ifdef MOZ_CRASHREPORTER
   CrashReporter::
     AnnotateCrashReport(NS_LITERAL_CSTRING("AccessibilityInProcClient"),
                         nsPrintfCString("0x%X", sConsumers));
 #endif
 
   // Gather telemetry
--- a/accessible/windows/msaa/Compatibility.h
+++ b/accessible/windows/msaa/Compatibility.h
@@ -52,21 +52,28 @@ public:
    */
   static void GetHumanReadableConsumersStr(nsAString &aResult);
 
   /**
    * Initialize compatibility mode information.
    */
   static void Init();
 
+  /**
+   * return true if a known, non-UIA a11y consumer is present
+   */
+  static bool HasKnownNonUiaConsumer();
+
 private:
   Compatibility();
   Compatibility(const Compatibility&);
   Compatibility& operator = (const Compatibility&);
 
+  static void InitConsumers();
+
   /**
    * List of detected consumers of a11y (used for statistics/telemetry and compat)
    */
   enum {
     NVDA = 1 << 0,
     JAWS = 1 << 1,
     OLDJAWS = 1 << 2,
     WE = 1 << 3,
--- a/accessible/windows/msaa/LazyInstantiator.cpp
+++ b/accessible/windows/msaa/LazyInstantiator.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LazyInstantiator.h"
 
 #include "MainThreadUtils.h"
 #include "mozilla/a11y/Accessible.h"
+#include "mozilla/a11y/Compatibility.h"
 #include "mozilla/a11y/Platform.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/mscom/MainThreadRuntime.h"
 #include "mozilla/mscom/Registration.h"
 #include "mozilla/UniquePtr.h"
 #include "nsAccessibilityService.h"
 #include "nsWindowsHelpers.h"
 #include "nsCOMPtr.h"
@@ -226,42 +227,76 @@ LazyInstantiator::GetClientExecutableNam
     return false;
   }
 
   file.forget(aOutClientExe);
   return NS_SUCCEEDED(rv);
 }
 
 /**
+ * This is the blocklist for known "bad" DLLs that instantiate a11y.
+ */
+static const wchar_t* gBlockedInprocDlls[] = {
+  L"dtvhooks.dll",  // RealPlayer, bug 1418535
+  L"dtvhooks64.dll" // RealPlayer, bug 1418535
+};
+
+/**
+ * Check for the presence of any known "bad" injected DLLs that may be trying
+ * to instantiate a11y.
+ *
+ * @return true to block a11y instantiation, otherwise false to continue
+ */
+bool
+LazyInstantiator::IsBlockedInjection()
+{
+  if (Compatibility::HasKnownNonUiaConsumer()) {
+    // If we already see a known AT, don't block a11y instantiation
+    return false;
+  }
+
+  for (size_t index = 0, len = ArrayLength(gBlockedInprocDlls); index < len;
+       ++index) {
+    if (::GetModuleHandleW(gBlockedInprocDlls[index])) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/**
  * Given a remote client's thread ID, determine whether we should proceed with
  * a11y instantiation. This is where telemetry should be gathered and any
  * potential blocking of unwanted a11y clients should occur.
  *
  * @return true if we should instantiate a11y
  */
 bool
 LazyInstantiator::ShouldInstantiate(const DWORD aClientTid)
 {
   if (!aClientTid) {
     // aClientTid == 0 implies that this is either an in-process call, or else
     // we failed to retrieve information about the remote caller.
-    // We should always default to instantiating a11y in this case.
-    return true;
+    // We should always default to instantiating a11y in this case, provided
+    // that we don't see any known bad injected DLLs.
+    return !IsBlockedInjection();
   }
 
   nsCOMPtr<nsIFile> clientExe;
   if (!GetClientExecutableName(aClientTid, getter_AddRefs(clientExe))) {
 #if defined(MOZ_TELEMETRY_REPORTING)
     AccumulateTelemetry(NS_LITERAL_STRING("(Failed to retrieve client image name)"));
 #endif // defined(MOZ_TELEMETRY_REPORTING)
     // We should return true as a failsafe
     return true;
   }
 
-  // Blocklist checks should go here. return false if we should not instantiate.
+  // Blocklist checks for external clients should go here.
+  // return false if we should not instantiate.
   /*
   if (ClientShouldBeBlocked(clientExe)) {
     return false;
   }
   */
 
   // Store full path to executable for support purposes.
   nsAutoString filePath;
--- a/accessible/windows/msaa/LazyInstantiator.h
+++ b/accessible/windows/msaa/LazyInstantiator.h
@@ -78,16 +78,17 @@ public:
 
   // IServiceProvider
   STDMETHODIMP QueryService(REFGUID aServiceId, REFIID aServiceIid, void** aOutInterface) override;
 
 private:
   explicit LazyInstantiator(HWND aHwnd);
   ~LazyInstantiator();
 
+  bool IsBlockedInjection();
   bool ShouldInstantiate(const DWORD aClientTid);
 
   bool GetClientExecutableName(const DWORD aClientTid, nsIFile** aOutClientExe);
 #if defined(MOZ_TELEMETRY_REPORTING) || defined(MOZ_CRASHREPORTER)
   class AccumulateRunnable final : public Runnable
   {
   public:
     explicit AccumulateRunnable(LazyInstantiator* aObj)