Bug 1356334: Part 3 - Enforce a stricter slow script timeout for extension content scripts. r=billm

MozReview-Commit-ID: LLvPQn1x1Xj

--HG--
extra : source : 805c568069301ae91ead5780cdc118af73907229
extra : histedit_source : b188836d1dc3ad8021bf2d0b1c89aebedf2db185%2C8c7b51c9f4af4eb5ad67811c29b56c72b43fa31d
This commit is contained in:
Kris Maglione 2017-08-18 11:04:55 -07:00
parent 5e014eb540
commit faa8815613
5 changed files with 66 additions and 15 deletions

View File

@ -54,6 +54,7 @@ const char* mozilla::dom::ContentPrefs::gInitPrefs[] = {
"dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS",
"dom.ipc.useNativeEventProcessing.content",
"dom.max_chrome_script_run_time",
"dom.max_ext_content_script_run_time",
"dom.max_script_run_time",
"dom.mozBrowserFramesEnabled",
"dom.performance.enable_notify_performance_timing",

View File

@ -61,6 +61,8 @@
#include "nsIInputStream.h"
#include "nsIXULRuntime.h"
#include "nsJSPrincipals.h"
#include "ExpandedPrincipal.h"
#include "SystemPrincipal.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
@ -227,6 +229,7 @@ class Watchdog
#define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
#define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
#define PREF_MAX_SCRIPT_RUN_TIME_EXT_CONTENT "dom.max_ext_content_script_run_time"
class WatchdogManager : public nsIObserver
{
@ -247,6 +250,7 @@ class WatchdogManager : public nsIObserver
mozilla::Preferences::AddStrongObserver(this, "dom.use_watchdog");
mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
mozilla::Preferences::AddStrongObserver(this, PREF_MAX_SCRIPT_RUN_TIME_EXT_CONTENT);
}
protected:
@ -266,6 +270,7 @@ class WatchdogManager : public nsIObserver
mozilla::Preferences::RemoveObserver(this, "dom.use_watchdog");
mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CONTENT);
mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_CHROME);
mozilla::Preferences::RemoveObserver(this, PREF_MAX_SCRIPT_RUN_TIME_EXT_CONTENT);
}
NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
@ -341,7 +346,10 @@ class WatchdogManager : public nsIObserver
int32_t chromeTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_CHROME, 20);
if (chromeTime <= 0)
chromeTime = INT32_MAX;
mWatchdog->SetMinScriptRunTimeSeconds(std::min(contentTime, chromeTime));
int32_t extTime = Preferences::GetInt(PREF_MAX_SCRIPT_RUN_TIME_EXT_CONTENT, 5);
if (extTime <= 0)
extTime = INT32_MAX;
mWatchdog->SetMinScriptRunTimeSeconds(std::min({contentTime, chromeTime, extTime}));
}
}
@ -463,6 +471,33 @@ XPCJSContext::ActivityCallback(void* arg, bool active)
self->mWatchdogManager->RecordContextActivity(active);
}
static inline bool
IsWebExtensionPrincipal(nsIPrincipal* principal, nsAString& addonId)
{
return (NS_SUCCEEDED(principal->GetAddonId(addonId)) &&
!addonId.IsEmpty());
}
static bool
IsWebExtensionContentScript(BasePrincipal* principal, nsAString& addonId)
{
if (!principal->Is<ExpandedPrincipal>()) {
return false;
}
auto expanded = principal->As<ExpandedPrincipal>();
nsTArray<nsCOMPtr<nsIPrincipal>>* principals;
expanded->GetWhiteList(&principals);
for (auto prin : *principals) {
if (IsWebExtensionPrincipal(prin, addonId)) {
return true;
}
}
return false;
}
// static
bool
XPCJSContext::InterruptCallback(JSContext* cx)
@ -492,10 +527,23 @@ XPCJSContext::InterruptCallback(JSContext* cx)
// returning to the event loop. See how long it's been, and what the limit
// is.
TimeDuration duration = TimeStamp::NowLoRes() - self->mSlowScriptCheckpoint;
bool chrome = nsContentUtils::IsSystemCaller(cx);
const char* prefName = chrome ? PREF_MAX_SCRIPT_RUN_TIME_CHROME
: PREF_MAX_SCRIPT_RUN_TIME_CONTENT;
int32_t limit = Preferences::GetInt(prefName, chrome ? 20 : 10);
int32_t limit;
nsString addonId;
const char* prefName;
auto principal = BasePrincipal::Cast(nsContentUtils::SubjectPrincipal(cx));
bool chrome = principal->Is<SystemPrincipal>();
if (chrome) {
prefName = PREF_MAX_SCRIPT_RUN_TIME_CHROME;
limit = Preferences::GetInt(prefName, 20);
} else if (IsWebExtensionContentScript(principal, addonId)) {
prefName = PREF_MAX_SCRIPT_RUN_TIME_EXT_CONTENT;
limit = Preferences::GetInt(prefName, 5);
} else {
prefName = PREF_MAX_SCRIPT_RUN_TIME_CONTENT;
limit = Preferences::GetInt(prefName, 10);
}
// If there's no limit, or we're within the limit, let it go.
if (limit == 0 || duration.ToSeconds() < limit / 2.0)

View File

@ -324,10 +324,18 @@ PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal)
if (nsXPConnect::SecurityManager()->IsSystemPrincipal(aPrincipal))
return true;
auto principal = BasePrincipal::Cast(aPrincipal);
// ExpandedPrincipal gets a free pass.
nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal);
if (ep)
if (principal->Is<ExpandedPrincipal>()) {
return true;
}
// WebExtension principals get a free pass.
nsString addonId;
if (IsWebExtensionPrincipal(principal, addonId)) {
return true;
}
// Check whether our URI is an "about:" URI that allows scripts. If it is,
// we need to allow JS to run.
@ -335,14 +343,6 @@ PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal)
aPrincipal->GetURI(getter_AddRefs(principalURI));
MOZ_ASSERT(principalURI);
// WebExtension principals gets a free pass.
nsString addonId;
aPrincipal->GetAddonId(addonId);
bool isWebExtension = !addonId.IsEmpty();
if (isWebExtension) {
return true;
}
bool isAbout;
nsresult rv = principalURI->SchemeIs("about", &isAbout);
if (NS_SUCCEEDED(rv) && isAbout) {

View File

@ -3167,6 +3167,7 @@ pref("editor.positioning.offset", 0);
pref("dom.use_watchdog", true);
pref("dom.max_chrome_script_run_time", 20);
pref("dom.max_script_run_time", 10);
pref("dom.max_ext_content_script_run_time", 5);
// Stop all scripts in a compartment when the "stop script" dialog is used.
pref("dom.global_stop_script", true);

View File

@ -61,6 +61,7 @@ skip-if = os == 'android' # Android does not support multiple windows.
[test_ext_content_security_policy.html]
[test_ext_contentscript_api_injection.html]
[test_ext_contentscript_async_loading.html]
skip-if = os == 'android' && debug # The generated script takes too long to load on Android debug
[test_ext_contentscript_cache.html]
skip-if = (os == 'linux' && debug) || (toolkit == 'android' && debug) # bug 1348241
[test_ext_contentscript_canvas.html]