Bug 1418535 - Block a11y instantiation if no known ATs are present and known bad DLLs are. r=jimm, a=ritu
authorAaron Klotz <aklotz@mozilla.com>
Mon, 20 Nov 2017 14:15:15 -0700
changeset 444992 0b758da65a9568c619a652ac04c7aa0b15ee6432
parent 444991 480953f8ac70b0fcefee73f5c201e87d4ad98d74
child 444993 a34fb2beb5f389057ea35ec120401a2d28bd46a4
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, ritu
bugs1418535
milestone58.0
Bug 1418535 - Block a11y instantiation if no known ATs are present and known bad DLLs are. r=jimm, a=ritu 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)