Skip to content

Commit 5ef6bee

Browse files
author
Tom Schuster
committed
Bug 1857488 - Add the RTPCallerType to JS realms. r=jandem
Differential Revision: https://phabricator.services.mozilla.com/D190676
1 parent f6676f4 commit 5ef6bee

File tree

7 files changed

+75
-33
lines changed

7 files changed

+75
-33
lines changed

js/public/Date.h

+15-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "mozilla/MathAlgorithms.h" // mozilla::Abs
3434

3535
#include "js/Conversions.h" // JS::ToInteger
36+
#include "js/RealmOptions.h" // JS::RTPCallerTypeToken
3637
#include "js/TypeDecls.h"
3738
#include "js/Value.h" // JS::CanonicalizeNaN, JS::DoubleValue, JS::Value
3839

@@ -187,15 +188,26 @@ JS_PUBLIC_API double DayFromYear(double year);
187188
JS_PUBLIC_API double DayWithinYear(double time, double year);
188189

189190
// The callback will be a wrapper function that accepts a double (the time
190-
// to clamp and jitter). Inside the JS Engine, other parameters that may be
191-
// needed are all constant, so they are handled inside the wrapper function
192-
using ReduceMicrosecondTimePrecisionCallback = double (*)(double, JSContext*);
191+
// to clamp and jitter) and a JS::RTPCallerTypeToken (a wrapper for
192+
// mozilla::RTPCallerType) that can be used to decide the proper clamping
193+
// behavior to use. Inside the JS Engine, other parameters that may be needed
194+
// are all constant, so they are handled inside the wrapper function
195+
using ReduceMicrosecondTimePrecisionCallback =
196+
double (*)(double, JS::RTPCallerTypeToken, JSContext*);
193197

194198
// Set a callback into the toolkit/components/resistfingerprinting function that
195199
// will centralize time resolution and jitter into one place.
200+
// Defining such a callback requires all Realms that are created afterwards
201+
// to have a set JS::RTPCallerTypeToken, via RealmBehaviors or
202+
// JS::SetRealmReduceTimerPrecisionCallerType.
196203
JS_PUBLIC_API void SetReduceMicrosecondTimePrecisionCallback(
197204
ReduceMicrosecondTimePrecisionCallback callback);
198205

206+
// Get the previously set ReduceMicrosecondTimePrecisionCallback callback or
207+
// nullptr.
208+
JS_PUBLIC_API ReduceMicrosecondTimePrecisionCallback
209+
GetReduceMicrosecondTimePrecisionCallback();
210+
199211
// Sets the time resolution for fingerprinting protection, and whether jitter
200212
// should occur. If resolution is set to zero, then no rounding or jitter will
201213
// occur. This is used if the callback above is not specified.

js/public/RealmOptions.h

+24-23
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define js_RealmOptions_h
1515

1616
#include "mozilla/Assertions.h" // MOZ_ASSERT
17+
#include "mozilla/Maybe.h"
1718

1819
#include "jstypes.h" // JS_PUBLIC_API
1920

@@ -320,6 +321,12 @@ class JS_PUBLIC_API RealmCreationOptions {
320321
bool alwaysUseFdlibm_ = false;
321322
};
322323

324+
// This is a wrapper for mozilla::RTPCallerType, that can't easily
325+
// be exposed to the JS engine for layering reasons.
326+
struct RTPCallerTypeToken {
327+
uint8_t value;
328+
};
329+
323330
/**
324331
* RealmBehaviors specifies behaviors of a realm that can be changed after the
325332
* realm's been created.
@@ -328,6 +335,17 @@ class JS_PUBLIC_API RealmBehaviors {
328335
public:
329336
RealmBehaviors() = default;
330337

338+
// When a JS::ReduceMicrosecondTimePrecisionCallback callback is defined via
339+
// JS::SetReduceMicrosecondTimePrecisionCallback, a JS::RTPCallerTypeToken (a
340+
// wrapper for mozilla::RTPCallerType) needs to be set for every Realm.
341+
mozilla::Maybe<RTPCallerTypeToken> reduceTimerPrecisionCallerType() const {
342+
return rtpCallerType;
343+
}
344+
RealmBehaviors& setReduceTimerPrecisionCallerType(RTPCallerTypeToken type) {
345+
rtpCallerType = mozilla::Some(type);
346+
return *this;
347+
}
348+
331349
// For certain globals, we know enough about the code that will run in them
332350
// that we can discard script source entirely.
333351
bool discardSource() const { return discardSource_; }
@@ -342,29 +360,6 @@ class JS_PUBLIC_API RealmBehaviors {
342360
return *this;
343361
}
344362

345-
class Override {
346-
public:
347-
Override() : mode_(Default) {}
348-
349-
bool get(bool defaultValue) const {
350-
if (mode_ == Default) {
351-
return defaultValue;
352-
}
353-
return mode_ == ForceTrue;
354-
}
355-
356-
void set(bool overrideValue) {
357-
mode_ = overrideValue ? ForceTrue : ForceFalse;
358-
}
359-
360-
void reset() { mode_ = Default; }
361-
362-
private:
363-
enum Mode { Default, ForceTrue, ForceFalse };
364-
365-
Mode mode_;
366-
};
367-
368363
// A Realm can stop being "live" in all the ways that matter before its global
369364
// is actually GCed. Consumers that tear down parts of a Realm or its global
370365
// before that point should set isNonLive accordingly.
@@ -375,6 +370,7 @@ class JS_PUBLIC_API RealmBehaviors {
375370
}
376371

377372
private:
373+
mozilla::Maybe<RTPCallerTypeToken> rtpCallerType;
378374
bool discardSource_ = false;
379375
bool clampAndJitterTime_ = true;
380376
bool isNonLive_ = false;
@@ -423,6 +419,11 @@ extern JS_PUBLIC_API const RealmBehaviors& RealmBehaviorsRef(JSContext* cx);
423419

424420
extern JS_PUBLIC_API void SetRealmNonLive(Realm* realm);
425421

422+
// This behaves like RealmBehaviors::setReduceTimerPrecisionCallerType, but
423+
// can be used even after the Realm has already been created.
424+
extern JS_PUBLIC_API void SetRealmReduceTimerPrecisionCallerType(
425+
Realm* realm, RTPCallerTypeToken type);
426+
426427
} // namespace JS
427428

428429
#endif // js_RealmOptions_h

js/src/jsapi.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "js/CompileOptions.h"
4747
#include "js/ContextOptions.h" // JS::ContextOptions{,Ref}
4848
#include "js/Conversions.h"
49+
#include "js/Date.h" // JS::GetReduceMicrosecondTimePrecisionCallback
4950
#include "js/ErrorInterceptor.h"
5051
#include "js/ErrorReport.h" // JSErrorBase
5152
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
@@ -1761,6 +1762,11 @@ const JS::RealmBehaviors& JS::RealmBehaviorsRef(JSContext* cx) {
17611762

17621763
void JS::SetRealmNonLive(Realm* realm) { realm->setNonLive(); }
17631764

1765+
void JS::SetRealmReduceTimerPrecisionCallerType(Realm* realm,
1766+
JS::RTPCallerTypeToken type) {
1767+
realm->setReduceTimerPrecisionCallerType(type);
1768+
}
1769+
17641770
JS_PUBLIC_API JSObject* JS_NewGlobalObject(JSContext* cx, const JSClass* clasp,
17651771
JSPrincipals* principals,
17661772
JS::OnNewGlobalHookOption hookOption,
@@ -1817,7 +1823,18 @@ JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx,
18171823
// This infallibility will eat OOM and slow script, but if that happens
18181824
// we'll likely run up into them again soon in a fallible context.
18191825
cx->check(global);
1826+
18201827
Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>());
1828+
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1829+
if (JS::GetReduceMicrosecondTimePrecisionCallback()) {
1830+
MOZ_DIAGNOSTIC_ASSERT(globalObject->realm()
1831+
->behaviors()
1832+
.reduceTimerPrecisionCallerType()
1833+
.isSome(),
1834+
"Trying to create a global without setting an "
1835+
"explicit RTPCallerType!");
1836+
}
1837+
#endif
18211838
DebugAPI::onNewGlobalObject(cx, globalObject);
18221839
cx->runtime()->ensureRealmIsRecordingAllocations(globalObject);
18231840
}

js/src/jsdate.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,11 @@ JS_PUBLIC_API void JS::SetReduceMicrosecondTimePrecisionCallback(
498498
sReduceMicrosecondTimePrecisionCallback = callback;
499499
}
500500

501+
JS_PUBLIC_API JS::ReduceMicrosecondTimePrecisionCallback
502+
JS::GetReduceMicrosecondTimePrecisionCallback() {
503+
return sReduceMicrosecondTimePrecisionCallback;
504+
}
505+
501506
JS_PUBLIC_API void JS::SetTimeResolutionUsec(uint32_t resolution, bool jitter) {
502507
sResolutionUsec = resolution;
503508
sJitter = jitter;
@@ -1856,7 +1861,9 @@ static ClippedTime NowAsMillis(JSContext* cx) {
18561861
double now = PRMJ_Now();
18571862
bool clampAndJitter = cx->realm()->behaviors().clampAndJitterTime();
18581863
if (clampAndJitter && sReduceMicrosecondTimePrecisionCallback) {
1859-
now = sReduceMicrosecondTimePrecisionCallback(now, cx);
1864+
now = sReduceMicrosecondTimePrecisionCallback(
1865+
now, cx->realm()->behaviors().reduceTimerPrecisionCallerType().value(),
1866+
cx);
18601867
} else if (clampAndJitter && sResolutionUsec) {
18611868
double clamped = floor(now / sResolutionUsec) * sResolutionUsec;
18621869

js/src/vm/Realm.h

+3
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,9 @@ class JS::Realm : public JS::shadow::Realm {
471471
const JS::RealmBehaviors& behaviors() const { return behaviors_; }
472472

473473
void setNonLive() { behaviors_.setNonLive(); }
474+
void setReduceTimerPrecisionCallerType(JS::RTPCallerTypeToken type) {
475+
behaviors_.setReduceTimerPrecisionCallerType(type);
476+
}
474477

475478
/* Whether to preserve JIT code on non-shrinking GCs. */
476479
bool preserveJitCode() { return creationOptions_.preserveJitCode(); }

toolkit/components/resistfingerprinting/nsRFPService.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -661,13 +661,14 @@ double nsRFPService::ReduceTimePrecisionAsSecsRFPOnly(
661661
}
662662

663663
/* static */
664-
double nsRFPService::ReduceTimePrecisionAsUSecsWrapper(double aTime,
665-
JSContext* aCx) {
664+
double nsRFPService::ReduceTimePrecisionAsUSecsWrapper(
665+
double aTime, JS::RTPCallerTypeToken aCallerType, JSContext* aCx) {
666666
MOZ_ASSERT(aCx);
667667

668668
nsCOMPtr<nsIGlobalObject> global = xpc::CurrentNativeGlobal(aCx);
669669
MOZ_ASSERT(global);
670670
RTPCallerType callerType = global->GetRTPCallerType();
671+
671672
return nsRFPService::ReduceTimePrecisionImpl(
672673
aTime, MicroSeconds, TimerResolution(callerType),
673674
0, /* For absolute timestamps (all the JS engine does), supply zero

toolkit/components/resistfingerprinting/nsRFPService.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "mozilla/BasicEvents.h"
1414
#include "mozilla/gfx/Types.h"
1515
#include "mozilla/TypedEnumBits.h"
16+
#include "js/RealmOptions.h"
1617
#include "nsHashtablesFwd.h"
1718
#include "nsICookieJarSettings.h"
1819
#include "nsIFingerprintingWebCompatService.h"
@@ -197,10 +198,6 @@ class nsRFPService final : public nsIObserver, public nsIRFPService {
197198
static double ReduceTimePrecisionAsSecsRFPOnly(double aTime,
198199
int64_t aContextMixin,
199200
RTPCallerType aRTPCallerType);
200-
201-
// Used by the JS Engine, as it doesn't know about the TimerPrecisionType enum
202-
static double ReduceTimePrecisionAsUSecsWrapper(double aTime, JSContext* aCx);
203-
204201
// Public only for testing purposes
205202
static double ReduceTimePrecisionImpl(double aTime, TimeScale aTimeScale,
206203
double aResolutionUSec,
@@ -348,6 +345,10 @@ class nsRFPService final : public nsIObserver, public nsIRFPService {
348345

349346
// --------------------------------------------------------------------------
350347

348+
// Used by the JS Engine
349+
static double ReduceTimePrecisionAsUSecsWrapper(
350+
double aTime, JS::RTPCallerTypeToken aCallerType, JSContext* aCx);
351+
351352
static TimerPrecisionType GetTimerPrecisionType(RTPCallerType aRTPCallerType);
352353

353354
static TimerPrecisionType GetTimerPrecisionTypeRFPOnly(

0 commit comments

Comments
 (0)