Bug 1363508 - Part 1: Spoofing pen/touch pointer events into mouse pointer events when fingerprinting resistance is on r=arthuredelstein,masayuki,smaug
authorTim Huang <tihuang@mozilla.com>
Tue, 09 Oct 2018 11:55:43 +0000
changeset 498970 3e9933f36e458a44212e316b554fbaaaacbfd72b
parent 498969 33692f367564122728279498617718bbc235e542
child 498971 24afd8e04316ca29c5906c3119a94cfec2cc2292
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarthuredelstein, masayuki, smaug
bugs1363508
milestone64.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 1363508 - Part 1: Spoofing pen/touch pointer events into mouse pointer events when fingerprinting resistance is on r=arthuredelstein,masayuki,smaug The pointerType field in the pointer event will reveal the details of users' hardware; this is a fingerprinting vector. So, we would spoof all types of pointer events into mouse type pointer events for protecting users from browser fingerprinting when fingerprinting resistance is on. In this patch, we would spoof the pointerType as well as other fields that mouse pointer events don't support, like pressure, tiltX/Y and so on when fingerprinting resistance is on. Differential Revision: https://phabricator.services.mozilla.com/D6003
dom/events/Event.cpp
dom/events/Event.h
dom/events/KeyboardEvent.cpp
dom/events/KeyboardEvent.h
dom/events/PointerEvent.cpp
dom/events/PointerEvent.h
dom/webidl/PointerEvent.webidl
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -230,16 +230,38 @@ Event::GetType(nsAString& aType) const
 }
 
 EventTarget*
 Event::GetTarget() const
 {
   return mEvent->GetDOMEventTarget();
 }
 
+already_AddRefed<nsIDocument>
+Event::GetDocument() const
+{
+  nsCOMPtr<EventTarget> eventTarget = GetTarget();
+
+  if (!eventTarget) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsPIDOMWindowInner> win =
+    do_QueryInterface(eventTarget->GetOwnerGlobal());
+
+  if (!win) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIDocument> doc;
+  doc = win->GetExtantDoc();
+
+  return doc.forget();
+}
+
 EventTarget*
 Event::GetCurrentTarget() const
 {
   return mEvent->GetCurrentDOMEventTarget();
 }
 
 void
 Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath)
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -209,16 +209,20 @@ public:
                                              const EventInit& aParam,
                                              ErrorResult& aRv);
 
   void GetType(nsAString& aType) const;
 
   EventTarget* GetTarget() const;
   EventTarget* GetCurrentTarget() const;
 
+  // This method returns the nsIDocument which is associated with the event
+  // target.
+  already_AddRefed<nsIDocument> GetDocument() const;
+
   void ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath);
 
   uint16_t EventPhase() const;
 
   void StopPropagation();
 
   void StopImmediatePropagation();
 
--- a/dom/events/KeyboardEvent.cpp
+++ b/dom/events/KeyboardEvent.cpp
@@ -386,34 +386,16 @@ KeyboardEvent::InitKeyboardEventJS(const
 
   WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
   keyEvent->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
   keyEvent->mLocation = aLocation;
   keyEvent->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
   keyEvent->mKeyValue = aKey;
 }
 
-already_AddRefed<nsIDocument>
-KeyboardEvent::GetDocument()
-{
-  nsCOMPtr<nsIDocument> doc;
-  nsCOMPtr<EventTarget> eventTarget = GetTarget();
-
-  if (eventTarget) {
-    nsCOMPtr<nsPIDOMWindowInner> win =
-      do_QueryInterface(eventTarget->GetOwnerGlobal());
-
-    if (win) {
-      doc = win->GetExtantDoc();
-    }
-  }
-
-  return doc.forget();
-}
-
 bool
 KeyboardEvent::ShouldResistFingerprinting(CallerType aCallerType)
 {
   // There are five situations we don't need to spoof this keyboard event.
   //   1. This event is initialized by scripts.
   //   2. This event is from Numpad.
   //   3. This event is in the system group.
   //   4. The caller type is system.
--- a/dom/events/KeyboardEvent.h
+++ b/dom/events/KeyboardEvent.h
@@ -102,20 +102,16 @@ private:
   uint32_t mInitializedWhichValue;
 
   // This method returns the boolean to indicate whether spoofing keyboard
   // event for fingerprinting resistance. It will return true when pref
   // 'privacy.resistFingerprinting' is true and the event target is content.
   // Otherwise, it will return false.
   bool ShouldResistFingerprinting(CallerType aCallerType);
 
-  // This method returns the nsIDocument which is associated with the event
-  // target.
-  already_AddRefed<nsIDocument> GetDocument();
-
   // This method returns the spoofed modifier state of the given modifier key
   // for fingerprinting resistance.
   bool GetSpoofedModifierStates(const Modifiers aModifierKey,
                                 const bool aRawModifierState);
 
   /**
    * ComputeTraditionalKeyCode() computes traditional keyCode value.  I.e.,
    * returns 0 if this event should return non-zero from CharCode().
--- a/dom/events/PointerEvent.cpp
+++ b/dom/events/PointerEvent.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * Portions Copyright 2013 Microsoft Open Technologies, Inc. */
 
 #include "mozilla/dom/MouseEventBinding.h"
 #include "mozilla/dom/PointerEvent.h"
 #include "mozilla/dom/PointerEventBinding.h"
 #include "mozilla/MouseEvents.h"
+#include "nsContentUtils.h"
 #include "prtime.h"
 
 namespace mozilla {
 namespace dom {
 
 PointerEvent::PointerEvent(EventTarget* aOwner,
                            nsPresContext* aPresContext,
                            WidgetPointerEvent* aEvent)
@@ -141,67 +142,93 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PointerEvent)
 NS_INTERFACE_MAP_END_INHERITING(MouseEvent)
 
 NS_IMPL_ADDREF_INHERITED(PointerEvent, MouseEvent)
 NS_IMPL_RELEASE_INHERITED(PointerEvent, MouseEvent)
 
 void
-PointerEvent::GetPointerType(nsAString& aPointerType)
+PointerEvent::GetPointerType(nsAString& aPointerType, CallerType aCallerType)
 {
+  if (ShouldResistFingerprinting(aCallerType)) {
+    aPointerType.AssignLiteral("mouse");
+    return;
+  }
+
   ConvertPointerTypeToString(mEvent->AsPointerEvent()->inputSource, aPointerType);
 }
 
 int32_t
 PointerEvent::PointerId()
 {
   return mEvent->AsPointerEvent()->pointerId;
 }
 
 int32_t
-PointerEvent::Width()
+PointerEvent::Width(CallerType aCallerType)
 {
-  return mEvent->AsPointerEvent()->mWidth;
+  return ShouldResistFingerprinting(aCallerType) ?
+           1 : mEvent->AsPointerEvent()->mWidth;
 }
 
 int32_t
-PointerEvent::Height()
+PointerEvent::Height(CallerType aCallerType)
 {
-  return mEvent->AsPointerEvent()->mHeight;
-}
-
-float
-PointerEvent::Pressure()
-{
-  return mEvent->AsPointerEvent()->pressure;
+  return ShouldResistFingerprinting(aCallerType) ?
+           1 : mEvent->AsPointerEvent()->mHeight;
 }
 
 float
-PointerEvent::TangentialPressure()
+PointerEvent::Pressure(CallerType aCallerType)
 {
-  return mEvent->AsPointerEvent()->tangentialPressure;
+  if (mEvent->mMessage == ePointerUp ||
+      !ShouldResistFingerprinting(aCallerType)) {
+    return mEvent->AsPointerEvent()->pressure;
+  }
+
+  // According to [1], we should use 0.5 when it is in active buttons state and
+  // 0 otherwise for devices that don't support pressure. And a pointerup event
+  // always reports 0, so we don't need to spoof that.
+  //
+  // [1] https://www.w3.org/TR/pointerevents/#dom-pointerevent-pressure
+  float spoofedPressure = 0.0;
+  if (mEvent->AsPointerEvent()->buttons) {
+    spoofedPressure = 0.5;
+  }
+
+  return spoofedPressure;
+}
+
+float
+PointerEvent::TangentialPressure(CallerType aCallerType)
+{
+  return ShouldResistFingerprinting(aCallerType) ?
+           0 : mEvent->AsPointerEvent()->tangentialPressure;
 }
 
 int32_t
-PointerEvent::TiltX()
+PointerEvent::TiltX(CallerType aCallerType)
 {
-  return mEvent->AsPointerEvent()->tiltX;
+  return ShouldResistFingerprinting(aCallerType) ?
+           0 : mEvent->AsPointerEvent()->tiltX;
 }
 
 int32_t
-PointerEvent::TiltY()
+PointerEvent::TiltY(CallerType aCallerType)
 {
-  return mEvent->AsPointerEvent()->tiltY;
+  return ShouldResistFingerprinting(aCallerType) ?
+           0 : mEvent->AsPointerEvent()->tiltY;
 }
 
 int32_t
-PointerEvent::Twist()
+PointerEvent::Twist(CallerType aCallerType)
 {
-  return mEvent->AsPointerEvent()->twist;
+  return ShouldResistFingerprinting(aCallerType) ?
+           0 : mEvent->AsPointerEvent()->twist;
 }
 
 bool
 PointerEvent::IsPrimary()
 {
   return mEvent->AsPointerEvent()->mIsPrimary;
 }
 
@@ -244,16 +271,40 @@ PointerEvent::GetCoalescedEvents(nsTArra
       if (!pointerEvent->mEvent->mTarget) {
         pointerEvent->mEvent->mTarget = mEvent->mTarget;
       }
     }
   }
   aPointerEvents.AppendElements(mCoalescedEvents);
 }
 
+bool
+PointerEvent::ShouldResistFingerprinting(CallerType aCallerType)
+{
+  // There are four situations we don't need to spoof this pointer event.
+  //   1. This event is generated by scripts.
+  //   2. This event is a mouse pointer event.
+  //   3. The caller type is system.
+  //   4. The pref privcy.resistFingerprinting' is false, we fast return here
+  //      since we don't need to do any QI of following codes.
+  //  We don't need to check for the system group since pointer events won't be
+  //  dispatched to the system group.
+  if (!mEvent->IsTrusted() ||
+      aCallerType == CallerType::System ||
+      !nsContentUtils::ShouldResistFingerprinting() ||
+      mEvent->AsPointerEvent()->inputSource ==
+        MouseEvent_Binding::MOZ_SOURCE_MOUSE) {
+    return false;
+  }
+
+  nsCOMPtr<nsIDocument> doc = GetDocument();
+
+  return doc && !nsContentUtils::IsChromeDoc(doc);
+}
+
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 already_AddRefed<PointerEvent>
 NS_NewDOMPointerEvent(EventTarget* aOwner,
--- a/dom/events/PointerEvent.h
+++ b/dom/events/PointerEvent.h
@@ -40,31 +40,35 @@ public:
               ErrorResult& aRv);
 
   static already_AddRefed<PointerEvent>
   Constructor(EventTarget* aOwner,
               const nsAString& aType,
               const PointerEventInit& aParam);
 
   int32_t PointerId();
-  int32_t Width();
-  int32_t Height();
-  float Pressure();
-  float TangentialPressure();
-  int32_t TiltX();
-  int32_t TiltY();
-  int32_t Twist();
+  int32_t Width(CallerType aCallerType);
+  int32_t Height(CallerType aCallerType);
+  float Pressure(CallerType aCallerType);
+  float TangentialPressure(CallerType aCallerType);
+  int32_t TiltX(CallerType aCallerType);
+  int32_t TiltY(CallerType aCallerType);
+  int32_t Twist(CallerType aCallerType);
   bool IsPrimary();
-  void GetPointerType(nsAString& aPointerType);
+  void GetPointerType(nsAString& aPointerType, CallerType aCallerType);
   void GetCoalescedEvents(nsTArray<RefPtr<PointerEvent>>& aPointerEvents);
 
 protected:
   ~PointerEvent() {}
 
 private:
+  // This method returns the boolean to indicate whether spoofing pointer
+  // event for fingerprinting resistance.
+  bool ShouldResistFingerprinting(CallerType aCallerType);
+
   nsTArray<RefPtr<PointerEvent>> mCoalescedEvents;
 };
 
 void ConvertPointerTypeToString(uint16_t aPointerTypeSrc, nsAString& aPointerTypeDest);
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/webidl/PointerEvent.webidl
+++ b/dom/webidl/PointerEvent.webidl
@@ -9,23 +9,33 @@
 
 interface WindowProxy;
 
 [Pref="dom.w3c_pointer_events.enabled",
  Constructor(DOMString type, optional PointerEventInit eventInitDict)]
 interface PointerEvent : MouseEvent
 {
   readonly attribute long pointerId;
+
+  [NeedsCallerType]
   readonly attribute long width;
+  [NeedsCallerType]
   readonly attribute long height;
+  [NeedsCallerType]
   readonly attribute float pressure;
+  [NeedsCallerType]
   readonly attribute float tangentialPressure;
+  [NeedsCallerType]
   readonly attribute long tiltX;
+  [NeedsCallerType]
   readonly attribute long tiltY;
+  [NeedsCallerType]
   readonly attribute long twist;
+
+  [NeedsCallerType]
   readonly attribute DOMString pointerType;
   readonly attribute boolean isPrimary;
   sequence<PointerEvent> getCoalescedEvents();
 };
 
 dictionary PointerEventInit : MouseEventInit
 {
   long pointerId = 0;