Bug 1443943 Do not clamp/jitter in the JS Engine if it's system context r?jorendorff
MozReview-Commit-ID: LqL7xaYoHCT
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -1639,16 +1639,17 @@ CreateNativeGlobalForInner(JSContext* aC
SelectZoneGroup(aNewInner, options.creationOptions());
// Sometimes add-ons load their own XUL windows, either as separate top-level
// windows or inside a browser element. In such cases we want to tag the
// window's compartment with the add-on ID. See bug 1092156.
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
options.creationOptions().setAddonId(MapURIToAddonID(aURI));
+ options.creationOptions().setClampAndJitterTime(false);
}
options.creationOptions().setSecureContext(aIsSecureContext);
xpc::InitGlobalObjectOptions(options, aPrincipal);
// Determine if we need the Components object.
bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2655,18 +2655,22 @@ WorkerPrivate::WorkerPrivate(WorkerPriva
} else {
MOZ_ASSERT_UNREACHABLE("non-chrome worker that is not a service worker "
"that has no parent and no associated window");
}
if (mIsSecureContext) {
mJSSettings.chrome.compartmentOptions
.creationOptions().setSecureContext(true);
+ mJSSettings.chrome.compartmentOptions
+ .creationOptions().setClampAndJitterTime(false);
mJSSettings.content.compartmentOptions
.creationOptions().setSecureContext(true);
+ mJSSettings.content.compartmentOptions
+ .creationOptions().setClampAndJitterTime(false);
}
mIsInAutomation = xpc::IsInAutomation();
// Our parent can get suspended after it initiates the async creation
// of a new worker thread. In this case suspend the new worker as well.
if (mLoadInfo.mWindow && mLoadInfo.mWindow->IsSuspended()) {
ParentWindowPaused();
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1990,17 +1990,18 @@ class JS_PUBLIC_API(CompartmentCreationO
traceGlobal_(nullptr),
zoneSpec_(NewZoneInSystemZoneGroup),
zonePointer_(nullptr),
invisibleToDebugger_(false),
mergeable_(false),
preserveJitCode_(false),
cloneSingletons_(false),
sharedMemoryAndAtomics_(false),
- secureContext_(false)
+ secureContext_(false),
+ clampAndJitterTime_(true)
{}
// A null add-on ID means that the compartment is not associated with an
// add-on.
JSAddonId* addonIdOrNull() const { return addonId_; }
CompartmentCreationOptions& setAddonId(JSAddonId* id) {
addonId_ = id;
return *this;
@@ -2066,27 +2067,34 @@ class JS_PUBLIC_API(CompartmentCreationO
// https://w3c.github.io/webappsec-secure-contexts/
// https://bugzilla.mozilla.org/show_bug.cgi?id=1162772#c34
bool secureContext() const { return secureContext_; }
CompartmentCreationOptions& setSecureContext(bool flag) {
secureContext_ = flag;
return *this;
}
+ bool clampAndJitterTime() const { return clampAndJitterTime_; }
+ CompartmentCreationOptions& setClampAndJitterTime(bool flag) {
+ clampAndJitterTime_ = flag;
+ return *this;
+ }
+
private:
JSAddonId* addonId_;
JSTraceOp traceGlobal_;
ZoneSpecifier zoneSpec_;
void* zonePointer_; // Per zoneSpec_, either a Zone, ZoneGroup, or null.
bool invisibleToDebugger_;
bool mergeable_;
bool preserveJitCode_;
bool cloneSingletons_;
bool sharedMemoryAndAtomics_;
bool secureContext_;
+ bool clampAndJitterTime_;
};
/**
* CompartmentBehaviors specifies behaviors of a compartment that can be
* changed after the compartment's been created.
*/
class JS_PUBLIC_API(CompartmentBehaviors)
{
old mode 100755
new mode 100644
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -1300,22 +1300,23 @@ date_parse(JSContext* cx, unsigned argc,
return true;
}
args.rval().set(TimeValue(result));
return true;
}
static ClippedTime
-NowAsMillis()
+NowAsMillis(JSContext* cx)
{
double now = PRMJ_Now();
- if (sReduceMicrosecondTimePrecisionCallback)
+ bool clampAndJitter = JS::CompartmentCreationOptionsRef(js::GetContextCompartment(cx)).clampAndJitterTime();
+ if (clampAndJitter && sReduceMicrosecondTimePrecisionCallback)
now = sReduceMicrosecondTimePrecisionCallback(now);
- else if (sResolutionUsec) {
+ else if (clampAndJitter && sResolutionUsec) {
double clamped = floor(now / sResolutionUsec) * sResolutionUsec;
if (sJitter) {
// Calculate a random midpoint for jittering. In the browser, we are adversarial:
// Web Content may try to calculate the midpoint themselves and use that to bypass
// it's security. In the JS Shell, we are not adversarial, we want to jitter the
// time to recreate the operating environment, but we do not concern ourselves
// with trying to prevent an attacker from calculating the midpoint themselves.
@@ -1344,17 +1345,17 @@ NowAsMillis()
return TimeClip(now / PRMJ_USEC_PER_MSEC);
}
bool
js::date_now(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- args.rval().set(TimeValue(NowAsMillis()));
+ args.rval().set(TimeValue(NowAsMillis(cx)));
return true;
}
void
DateObject::setUTCTime(ClippedTime t)
{
for (size_t ind = COMPONENTS_START_SLOT; ind < RESERVED_SLOTS; ind++)
setReservedSlot(ind, UndefinedValue());
@@ -3115,17 +3116,17 @@ ToDateString(JSContext* cx, const CallAr
return FormatDate(cx, t.toDouble(), FormatSpec::DateTime, args.rval());
}
static bool
DateNoArguments(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(args.length() == 0);
- ClippedTime now = NowAsMillis();
+ ClippedTime now = NowAsMillis(cx);
if (args.isConstructing())
return NewDateObject(cx, args, now);
return ToDateString(cx, args, now);
}
static bool
@@ -3166,17 +3167,17 @@ DateOneArgument(JSContext* cx, const Cal
if (!ToNumber(cx, args[0], &d))
return false;
t = TimeClip(d);
}
return NewDateObject(cx, args, t);
}
- return ToDateString(cx, args, NowAsMillis());
+ return ToDateString(cx, args, NowAsMillis(cx));
}
static bool
DateMultipleArguments(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(args.length() >= 2);
// Step 3.
@@ -3246,17 +3247,17 @@ DateMultipleArguments(JSContext* cx, con
// Step 3p.
double finalDate = MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli));
// Steps 3q-t.
return NewDateObject(cx, args, TimeClip(UTC(finalDate)));
}
- return ToDateString(cx, args, NowAsMillis());
+ return ToDateString(cx, args, NowAsMillis(cx));
}
bool
js::DateConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() == 0)
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1119,16 +1119,19 @@ xpc::CreateSandboxObject(JSContext* cx,
JS::CompartmentOptions compartmentOptions;
auto& creationOptions = compartmentOptions.creationOptions();
// XXXjwatt: Consider whether/when sandboxes should be able to see
// [SecureContext] API (bug 1273687). In that case we'd call
// creationOptions.setSecureContext(true).
+ if (principal == nsXPConnect::SystemPrincipal())
+ creationOptions.setClampAndJitterTime(false);
+
if (xpc::SharedMemoryEnabled())
creationOptions.setSharedMemoryAndAtomicsEnabled(true);
if (options.sameZoneAs)
creationOptions.setExistingZone(js::UncheckedUnwrap(options.sameZoneAs));
else if (options.freshZone)
creationOptions.setNewZoneInSystemZoneGroup();
else
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -503,16 +503,17 @@ InitGlobalObjectOptions(JS::CompartmentO
bool shouldDiscardSystemSource = ShouldDiscardSystemSource();
bool extraWarningsForSystemJS = ExtraWarningsForSystemJS();
bool isSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
if (isSystem) {
// Make sure [SecureContext] APIs are visible:
aOptions.creationOptions().setSecureContext(true);
+ aOptions.creationOptions().setClampAndJitterTime(false);
}
if (shouldDiscardSystemSource) {
bool discardSource = isSystem;
aOptions.behaviors().setDiscardSource(discardSource);
}