Bug 1217238 - Propagate changes of javascript.options.resistFingerprinting to workers. draft
authorJonathan Hao <jhao@mozilla.com>
Wed, 17 May 2017 14:27:05 +0800
changeset 579936 9f2e4aa785e930294b8f087268acc6d2e9f45eac
parent 579935 b8b55ea30d33df513a52f6f30497a33a0c2a18b2
child 579937 60d2d9c69ae7b6ceeec3e889425f32721a86432b
push id59415
push userbmo:jhao@mozilla.com
push dateThu, 18 May 2017 02:27:11 +0000
bugs1217238
milestone55.0a1
Bug 1217238 - Propagate changes of javascript.options.resistFingerprinting to workers. This pref is created for the next patch. Because we need to get this pref in workers, I added this pref to WorkerPrefs.h so RuntimeService will broadcast pref changes for us, and update all the workers recursively. This pref is also added to the js context options because the Date API needs it. MozReview-Commit-ID: JOkOR2Wek5C
dom/workers/RuntimeService.cpp
dom/workers/RuntimeService.h
dom/workers/WorkerPrefs.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
js/src/jsapi.h
js/src/shell/js.cpp
js/xpconnect/src/XPCJSRuntime.cpp
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -1352,16 +1352,29 @@ PlatformOverrideChanged(const char* /* a
     mozilla::Preferences::GetString("general.platform.override");
 
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->UpdatePlatformOverridePreference(override);
   }
 }
 
+void
+ResistFingerprintingChanged(const char* /* aPrefName */, void* /* aClosure */)
+{
+  AssertIsOnMainThread();
+  bool resistFingerprinting = mozilla::Preferences::GetBool(
+    "privacy.resistFingerprinting");
+
+  RuntimeService* runtime = RuntimeService::GetService();
+  if (runtime) {
+    runtime->UpdateResistFingerprintingPreference(resistFingerprinting);
+  }
+}
+
 class BackgroundChildCallback final
   : public nsIIPCBackgroundChildCreateCallback
 {
 public:
   BackgroundChildCallback()
   {
     AssertIsOnMainThread();
   }
@@ -2651,16 +2664,23 @@ RuntimeService::UpdateAppVersionOverride
 void
 RuntimeService::UpdatePlatformOverridePreference(const nsAString& aValue)
 {
   AssertIsOnMainThread();
   mNavigatorProperties.mPlatformOverridden = aValue;
 }
 
 void
+RuntimeService::UpdateResistFingerprintingPreference(bool aResistFingerprinting)
+{
+  AssertIsOnMainThread();
+  BROADCAST_ALL_WORKERS(UpdateResistFingerprinting, aResistFingerprinting);
+}
+
+void
 RuntimeService::UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue)
 {
   BROADCAST_ALL_WORKERS(UpdatePreference, aPref, aValue);
 }
 
 void
 RuntimeService::UpdateAllWorkerLanguages(const nsTArray<nsString>& aLanguages)
 {
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -192,16 +192,19 @@ public:
 
   void
   UpdateAppVersionOverridePreference(const nsAString& aValue);
 
   void
   UpdatePlatformOverridePreference(const nsAString& aValue);
 
   void
+  UpdateResistFingerprintingPreference(bool aResistFingerprinting);
+
+  void
   UpdateAllWorkerContextOptions();
 
   void
   UpdateAllWorkerLanguages(const nsTArray<nsString>& aLanguages);
 
   void
   UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue);
 
--- a/dom/workers/WorkerPrefs.h
+++ b/dom/workers/WorkerPrefs.h
@@ -42,11 +42,12 @@ WORKER_SIMPLE_PREF("gfx.offscreencanvas.
 WORKER_SIMPLE_PREF("dom.webkitBlink.dirPicker.enabled", WebkitBlinkDirectoryPickerEnabled, DOM_WEBKITBLINK_DIRPICKER_WEBKITBLINK)
 WORKER_SIMPLE_PREF("dom.netinfo.enabled", NetworkInformationEnabled, NETWORKINFORMATION_ENABLED)
 WORKER_SIMPLE_PREF("dom.fetchController.enabled", FetchControllerEnabled, FETCHCONTROLLER_ENABLED)
 WORKER_SIMPLE_PREF("dom.fetchObserver.enabled", FetchObserverEnabled, FETCHOBSERVER_ENABLED)
 WORKER_PREF("intl.accept_languages", PrefLanguagesChanged)
 WORKER_PREF("general.appname.override", AppNameOverrideChanged)
 WORKER_PREF("general.appversion.override", AppVersionOverrideChanged)
 WORKER_PREF("general.platform.override", PlatformOverrideChanged)
+WORKER_PREF("privacy.resistFingerprinting", ResistFingerprintingChanged)
 #ifdef JS_GC_ZEAL
 WORKER_PREF("dom.workers.options.gcZeal", LoadGCZealOptions)
 #endif
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1322,16 +1322,36 @@ private:
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     aWorkerPrivate->UpdateContextOptionsInternal(aCx, mContextOptions);
     return true;
   }
 };
 
+class UpdateResistFingerprintingRunnable final : public WorkerControlRunnable
+{
+  bool mResistFingerprinting;
+
+public:
+  UpdateResistFingerprintingRunnable(WorkerPrivate* aWorkerPrivate,
+                                    bool aResistFingerprinting)
+  : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
+    mResistFingerprinting(aResistFingerprinting)
+  { }
+
+private:
+  virtual bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+  {
+    aWorkerPrivate->UpdateResistFingerprintingInternal(mResistFingerprinting);
+    return true;
+  }
+};
+
 class UpdatePreferenceRunnable final : public WorkerControlRunnable
 {
   WorkerPreference mPref;
   bool mValue;
 
 public:
   UpdatePreferenceRunnable(WorkerPrivate* aWorkerPrivate,
                            WorkerPreference aPref,
@@ -3427,16 +3447,30 @@ WorkerPrivateParent<Derived>::UpdateCont
     new UpdateContextOptionsRunnable(ParentAsWorkerPrivate(), aContextOptions);
   if (!runnable->Dispatch()) {
     NS_WARNING("Failed to update worker context options!");
   }
 }
 
 template <class Derived>
 void
+WorkerPrivateParent<Derived>::UpdateResistFingerprinting(bool aResistFingerprinting)
+{
+  AssertIsOnParentThread();
+
+  RefPtr<UpdateResistFingerprintingRunnable> runnable =
+    new UpdateResistFingerprintingRunnable(ParentAsWorkerPrivate(),
+                                          aResistFingerprinting);
+  if (!runnable->Dispatch()) {
+    NS_WARNING("Failed to update worker time precision!");
+  }
+}
+
+template <class Derived>
+void
 WorkerPrivateParent<Derived>::UpdatePreference(WorkerPreference aPref, bool aValue)
 {
   AssertIsOnParentThread();
   MOZ_ASSERT(aPref >= 0 && aPref < WORKERPREF_COUNT);
 
   RefPtr<UpdatePreferenceRunnable> runnable =
     new UpdatePreferenceRunnable(ParentAsWorkerPrivate(), aPref, aValue);
   if (!runnable->Dispatch()) {
@@ -4449,21 +4483,23 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
 {
   MOZ_ASSERT_IF(!IsDedicatedWorker(), !aWorkerName.IsVoid());
   MOZ_ASSERT_IF(IsDedicatedWorker(), aWorkerName.IsEmpty());
 
   if (aParent) {
     aParent->AssertIsOnWorkerThread();
     aParent->GetAllPreferences(mPreferences);
     mOnLine = aParent->OnLine();
+    mResistFingerprinting = aParent->ResistFingerprinting();
   }
   else {
     AssertIsOnMainThread();
     RuntimeService::GetDefaultPreferences(mPreferences);
     mOnLine = !NS_IsOffline();
+    mResistFingerprinting = nsContentUtils::ShouldResistFingerprinting();
   }
 
   nsCOMPtr<nsIEventTarget> target;
 
   // A child worker just inherits the parent workers ThrottledEventQueue
   // and main thread target for now.  This is mainly due to the restriction
   // that ThrottledEventQueue can only be created on the main thread at the
   // moment.
@@ -4970,16 +5006,18 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
   {
     MutexAutoLock lock(mMutex);
     mJSContext = aCx;
 
     MOZ_ASSERT(mStatus == Pending);
     mStatus = Running;
   }
 
+  JS::ContextOptionsRef(mJSContext).setResistFingerprinting(mResistFingerprinting);
+
   // Now that we've done that, we can go ahead and set up our AutoJSAPI.  We
   // can't before this point, because it can't find the right JSContext before
   // then, since it gets it from our mJSContext.
   AutoJSAPI jsapi;
   jsapi.Init();
   MOZ_ASSERT(jsapi.cx() == aCx);
 
   EnableMemoryReporter();
@@ -6656,16 +6694,29 @@ WorkerPrivate::UpdateLanguagesInternal(c
   }
 
   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
     mChildWorkers[index]->UpdateLanguages(aLanguages);
   }
 }
 
 void
+WorkerPrivate::UpdateResistFingerprintingInternal(bool aResistFingerprinting)
+{
+  AssertIsOnWorkerThread();
+
+  JS::ContextOptionsRef(mJSContext).setResistFingerprinting(aResistFingerprinting);
+  mResistFingerprinting = aResistFingerprinting;
+
+  for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
+    mChildWorkers[index]->UpdateResistFingerprinting(aResistFingerprinting);
+  }
+}
+
+void
 WorkerPrivate::UpdatePreferenceInternal(WorkerPreference aPref, bool aValue)
 {
   AssertIsOnWorkerThread();
   MOZ_ASSERT(aPref >= 0 && aPref < WORKERPREF_COUNT);
 
   mPreferences[aPref] = aValue;
 
   for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -402,16 +402,19 @@ public:
 
   void
   UpdateContextOptions(const JS::ContextOptions& aContextOptions);
 
   void
   UpdateLanguages(const nsTArray<nsString>& aLanguages);
 
   void
+  UpdateResistFingerprinting(bool aResistFingerprinting);
+
+  void
   UpdatePreference(WorkerPreference aPref, bool aValue);
 
   void
   UpdateJSWorkerMemoryParameter(JSGCParamKey key, uint32_t value);
 
 #ifdef JS_GC_ZEAL
   void
   UpdateGCZeal(uint8_t aGCZeal, uint32_t aFrequency);
@@ -1041,16 +1044,17 @@ class WorkerPrivate : public WorkerPriva
   bool mPendingEventQueueClearing;
   bool mCancelAllPendingRunnables;
   bool mPeriodicGCTimerRunning;
   bool mIdleGCTimerRunning;
   bool mWorkerScriptExecutedSuccessfully;
   bool mFetchHandlerWasAdded;
   bool mPreferences[WORKERPREF_COUNT];
   bool mOnLine;
+  bool mResistFingerprinting;
 
 protected:
   ~WorkerPrivate();
 
 public:
   static already_AddRefed<WorkerPrivate>
   Constructor(const GlobalObject& aGlobal, const nsAString& aScriptURL,
               ErrorResult& aRv);
@@ -1242,16 +1246,19 @@ public:
 
   void
   UpdateContextOptionsInternal(JSContext* aCx, const JS::ContextOptions& aContextOptions);
 
   void
   UpdateLanguagesInternal(const nsTArray<nsString>& aLanguages);
 
   void
+  UpdateResistFingerprintingInternal(bool aResistFingerprinting);
+
+  void
   UpdatePreferenceInternal(WorkerPreference aPref, bool aValue);
 
   void
   UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, uint32_t aValue);
 
   enum WorkerRanOrNot {
     WorkerNeverRan = 0,
     WorkerRan
@@ -1385,16 +1392,23 @@ public:
 
   bool
   OnLine() const
   {
     AssertIsOnWorkerThread();
     return mOnLine;
   }
 
+  bool
+  ResistFingerprinting() const
+  {
+    AssertIsOnWorkerThread();
+    return mResistFingerprinting;
+  }
+
   void
   StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult);
 
   bool
   AllPendingRunnablesShouldBeCanceled() const
   {
     return mCancelAllPendingRunnables;
   }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1139,16 +1139,17 @@ class JS_PUBLIC_API(ContextOptions) {
     ContextOptions()
       : baseline_(true),
         ion_(true),
         asmJS_(true),
         wasm_(false),
         wasmAlwaysBaseline_(false),
         throwOnAsmJSValidationFailure_(false),
         nativeRegExp_(true),
+        resistFingerprinting_(false),
         unboxedArrays_(false),
         asyncStack_(true),
         throwOnDebuggeeWouldRun_(true),
         dumpStackOnDebuggeeWouldRun_(false),
         werror_(false),
         strictMode_(false),
         extraWarnings_(false),
 #ifdef NIGHTLY_BUILD
@@ -1220,16 +1221,22 @@ class JS_PUBLIC_API(ContextOptions) {
     }
 
     bool nativeRegExp() const { return nativeRegExp_; }
     ContextOptions& setNativeRegExp(bool flag) {
         nativeRegExp_ = flag;
         return *this;
     }
 
+    bool resistFingerprinting() const { return resistFingerprinting_; }
+    ContextOptions& setResistFingerprinting(bool flag) {
+        resistFingerprinting_ = flag;
+        return *this;
+    }
+
     bool unboxedArrays() const { return unboxedArrays_; }
     ContextOptions& setUnboxedArrays(bool flag) {
         unboxedArrays_ = flag;
         return *this;
     }
 
     bool asyncStack() const { return asyncStack_; }
     ContextOptions& setAsyncStack(bool flag) {
@@ -1296,16 +1303,17 @@ class JS_PUBLIC_API(ContextOptions) {
   private:
     bool baseline_ : 1;
     bool ion_ : 1;
     bool asmJS_ : 1;
     bool wasm_ : 1;
     bool wasmAlwaysBaseline_ : 1;
     bool throwOnAsmJSValidationFailure_ : 1;
     bool nativeRegExp_ : 1;
+    bool resistFingerprinting_ : 1;
     bool unboxedArrays_ : 1;
     bool asyncStack_ : 1;
     bool throwOnDebuggeeWouldRun_ : 1;
     bool dumpStackOnDebuggeeWouldRun_ : 1;
     bool werror_ : 1;
     bool strictMode_ : 1;
     bool extraWarnings_ : 1;
     bool forEachStatement_: 1;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -349,16 +349,17 @@ struct MOZ_STACK_CLASS EnvironmentPrepar
 static bool enableCodeCoverage = false;
 static bool enableDisassemblyDumps = false;
 static bool offthreadCompilation = false;
 static bool enableBaseline = false;
 static bool enableIon = false;
 static bool enableAsmJS = false;
 static bool enableWasm = false;
 static bool enableNativeRegExp = false;
+static bool enableResistFingerprinting = false;
 static bool enableUnboxedArrays = false;
 static bool enableSharedMemory = SHARED_MEMORY_DEFAULT;
 static bool enableWasmAlwaysBaseline = false;
 #ifdef JS_GC_ZEAL
 static uint32_t gZealBits = 0;
 static uint32_t gZealFrequency = 0;
 #endif
 static bool printTiming = false;
@@ -7804,25 +7805,27 @@ ProcessArgs(JSContext* cx, OptionParser*
 static bool
 SetContextOptions(JSContext* cx, const OptionParser& op)
 {
     enableBaseline = !op.getBoolOption("no-baseline");
     enableIon = !op.getBoolOption("no-ion");
     enableAsmJS = !op.getBoolOption("no-asmjs");
     enableWasm = !op.getBoolOption("no-wasm");
     enableNativeRegExp = !op.getBoolOption("no-native-regexp");
+    enableResistFingerprinting = op.getBoolOption("resist-fingerprinting");
     enableUnboxedArrays = op.getBoolOption("unboxed-arrays");
     enableWasmAlwaysBaseline = op.getBoolOption("wasm-always-baseline");
 
     JS::ContextOptionsRef(cx).setBaseline(enableBaseline)
                              .setIon(enableIon)
                              .setAsmJS(enableAsmJS)
                              .setWasm(enableWasm)
                              .setWasmAlwaysBaseline(enableWasmAlwaysBaseline)
                              .setNativeRegExp(enableNativeRegExp)
+                             .setResistFingerprinting(enableResistFingerprinting)
                              .setUnboxedArrays(enableUnboxedArrays);
 
     if (op.getBoolOption("wasm-check-bce"))
         jit::JitOptions.wasmAlwaysCheckBounds = true;
 
     if (op.getBoolOption("wasm-test-mode"))
         jit::JitOptions.wasmTestMode = true;
 
@@ -8097,16 +8100,17 @@ SetWorkerContextOptions(JSContext* cx)
 {
     // Copy option values from the main thread.
     JS::ContextOptionsRef(cx).setBaseline(enableBaseline)
                              .setIon(enableIon)
                              .setAsmJS(enableAsmJS)
                              .setWasm(enableWasm)
                              .setWasmAlwaysBaseline(enableWasmAlwaysBaseline)
                              .setNativeRegExp(enableNativeRegExp)
+                             .setResistFingerprinting(enableResistFingerprinting)
                              .setUnboxedArrays(enableUnboxedArrays);
     cx->runtime()->setOffthreadIonCompilationEnabled(offthreadCompilation);
     cx->runtime()->profilingScripts = enableCodeCoverage || enableDisassemblyDumps;
 
 #ifdef JS_GC_ZEAL
     if (gZealBits && gZealFrequency) {
 #define ZEAL_MODE(_, value)                        \
         if (gZealBits & (1 << value))              \
@@ -8291,16 +8295,17 @@ main(int argc, char** argv, char** envp)
                                          "shell's global")
         || !op.addIntOption('\0', "thread-count", "COUNT", "Use COUNT auxiliary threads "
                             "(default: # of cores - 1)", -1)
         || !op.addBoolOption('\0', "ion", "Enable IonMonkey (default)")
         || !op.addBoolOption('\0', "no-ion", "Disable IonMonkey")
         || !op.addBoolOption('\0', "no-asmjs", "Disable asm.js compilation")
         || !op.addBoolOption('\0', "no-wasm", "Disable WebAssembly compilation")
         || !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
+        || !op.addBoolOption('\0', "resist-fingerprinting", "Enable anti-fingerprinting features")
         || !op.addBoolOption('\0', "no-unboxed-objects", "Disable creating unboxed plain objects")
         || !op.addBoolOption('\0', "unboxed-arrays", "Allow creating unboxed arrays")
         || !op.addBoolOption('\0', "wasm-always-baseline", "Enable wasm baseline compiler when possible")
         || !op.addBoolOption('\0', "wasm-check-bce", "Always generate wasm bounds check, even redundant ones.")
         || !op.addBoolOption('\0', "wasm-test-mode", "Enable wasm testing mode, creating synthetic "
                                    "objects for non-canonical NaNs and i64 returned from wasm.")
 #ifdef ENABLE_SHARED_ARRAY_BUFFER
         || !op.addStringOption('\0', "shared-memory", "on/off",
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1073,16 +1073,17 @@ ReloadPrefsCallback(const char* pref, vo
     bool useBaseline = Preferences::GetBool(JS_OPTIONS_DOT_STR "baselinejit") && !safeMode;
     bool useIon = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion") && !safeMode;
     bool useAsmJS = Preferences::GetBool(JS_OPTIONS_DOT_STR "asmjs") && !safeMode;
     bool useWasm = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm") && !safeMode;
     bool useWasmBaseline = Preferences::GetBool(JS_OPTIONS_DOT_STR "wasm_baselinejit") && !safeMode;
     bool throwOnAsmJSValidationFailure = Preferences::GetBool(JS_OPTIONS_DOT_STR
                                                               "throw_on_asmjs_validation_failure");
     bool useNativeRegExp = Preferences::GetBool(JS_OPTIONS_DOT_STR "native_regexp") && !safeMode;
+    bool resistFingerprinting = Preferences::GetBool("privacy.resistFingerprinting") && !safeMode;
 
     bool parallelParsing = Preferences::GetBool(JS_OPTIONS_DOT_STR "parallel_parsing");
     bool offthreadIonCompilation = Preferences::GetBool(JS_OPTIONS_DOT_STR
                                                        "ion.offthread_compilation");
     bool useBaselineEager = Preferences::GetBool(JS_OPTIONS_DOT_STR
                                                  "baselinejit.unsafe_eager_compilation");
     bool useIonEager = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion.unsafe_eager_compilation");
 #ifdef DEBUG
@@ -1128,16 +1129,17 @@ ReloadPrefsCallback(const char* pref, vo
 
     JS::ContextOptionsRef(cx).setBaseline(useBaseline)
                              .setIon(useIon)
                              .setAsmJS(useAsmJS)
                              .setWasm(useWasm)
                              .setWasmAlwaysBaseline(useWasmBaseline)
                              .setThrowOnAsmJSValidationFailure(throwOnAsmJSValidationFailure)
                              .setNativeRegExp(useNativeRegExp)
+                             .setResistFingerprinting(resistFingerprinting)
                              .setAsyncStack(useAsyncStack)
                              .setThrowOnDebuggeeWouldRun(throwOnDebuggeeWouldRun)
                              .setDumpStackOnDebuggeeWouldRun(dumpStackOnDebuggeeWouldRun)
                              .setWerror(werror)
 #ifdef FUZZING
                              .setFuzzing(fuzzingEnabled)
 #endif
                              .setExtraWarnings(extraWarnings);
@@ -3008,16 +3010,18 @@ XPCJSRuntime::Initialize(JSContext* cx)
     RegisterJSMainRuntimeCompartmentsUserDistinguishedAmount(JSMainRuntimeCompartmentsUserDistinguishedAmount);
     mozilla::RegisterJSSizeOfTab(JSSizeOfTab);
 
     // Watch for the JS boolean options.
     ReloadPrefsCallback(nullptr, nullptr);
     Preferences::RegisterPrefixCallback(ReloadPrefsCallback,
                                         JS_OPTIONS_DOT_STR);
 
+    Preferences::RegisterPrefixCallback(ReloadPrefsCallback,
+                                        "privacy.resistFingerprinting");
 #ifdef FUZZING
     Preferences::RegisterCallback(ReloadPrefsCallback, "fuzzing.enabled");
 #endif
 }
 
 bool
 XPCJSRuntime::InitializeStrings(JSContext* cx)
 {