Bug 840488 - Directly mark compartments whose docshells disable script execution. r=bz
This commit is contained in:
@@ -1637,24 +1637,8 @@ nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
|
||||
if (!sgo) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// window can be null here if we're running with a non-DOM window
|
||||
// as the script global (i.e. a XUL prototype document).
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
|
||||
nsCOMPtr<nsIDocShell> docshell;
|
||||
nsresult rv;
|
||||
if (window) {
|
||||
docshell = window->GetDocShell();
|
||||
}
|
||||
|
||||
if (docshell) {
|
||||
rv = docshell->GetCanExecuteScripts(result);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!*result) return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// OK, the docshell doesn't have script execution explicitly disabled.
|
||||
// Check whether our URI is an "about:" URI that allows scripts. If it is,
|
||||
// we need to allow JS to run. In this case, don't apply the JS enabled
|
||||
// pref or policies. On failures, just press on and don't do this special
|
||||
|
||||
@@ -762,6 +762,7 @@ nsDocShell::nsDocShell():
|
||||
mUseGlobalHistory(false),
|
||||
mInPrivateBrowsing(false),
|
||||
mDeviceSizeIsPageSize(false),
|
||||
mCanExecuteScripts(false),
|
||||
mFiredUnloadEvent(false),
|
||||
mEODForCurrentDocument(false),
|
||||
mURIResultedInDocument(false),
|
||||
@@ -2084,6 +2085,7 @@ NS_IMETHODIMP
|
||||
nsDocShell::SetAllowJavascript(bool aAllowJavascript)
|
||||
{
|
||||
mAllowJavascript = aAllowJavascript;
|
||||
RecomputeCanExecuteScripts();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -2817,6 +2819,48 @@ nsDocShell::GetParentDocshell()
|
||||
return docshell.forget().downcast<nsDocShell>();
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::RecomputeCanExecuteScripts()
|
||||
{
|
||||
bool old = mCanExecuteScripts;
|
||||
nsRefPtr<nsDocShell> parent = GetParentDocshell();
|
||||
|
||||
// If we have no tree owner, that means that we've been detached from the
|
||||
// docshell tree (this is distinct from having no parent dochshell, which
|
||||
// is the case for root docshells). In that case, don't allow script.
|
||||
if (!mTreeOwner) {
|
||||
mCanExecuteScripts = false;
|
||||
// If scripting has been explicitly disabled on our docshell, we're done.
|
||||
} else if (!mAllowJavascript) {
|
||||
mCanExecuteScripts = false;
|
||||
// If we have a parent, inherit.
|
||||
} else if (parent) {
|
||||
mCanExecuteScripts = parent->mCanExecuteScripts;
|
||||
// Otherwise, we're the root of the tree, and we haven't explicitly disabled
|
||||
// script. Allow.
|
||||
} else {
|
||||
mCanExecuteScripts = true;
|
||||
}
|
||||
|
||||
// Inform our active DOM window.
|
||||
//
|
||||
// This will pass the outer, which will be in the scope of the active inner.
|
||||
if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) {
|
||||
xpc::Scriptability& scriptability =
|
||||
xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject());
|
||||
scriptability.SetDocShellAllowsScript(mCanExecuteScripts);
|
||||
}
|
||||
|
||||
// If our value has changed, our children might be affected. Recompute their
|
||||
// value as well.
|
||||
if (old != mCanExecuteScripts) {
|
||||
nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
|
||||
while (iter.HasMore()) {
|
||||
static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
|
||||
{
|
||||
@@ -2886,6 +2930,10 @@ nsDocShell::SetDocLoaderParent(nsDocLoader * aParent)
|
||||
nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
|
||||
if (parentURIListener)
|
||||
mContentListener->SetParentContentListener(parentURIListener);
|
||||
|
||||
// Our parent has changed. Recompute scriptability.
|
||||
RecomputeCanExecuteScripts();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -3440,6 +3488,16 @@ nsDocShell::SetTreeOwner(nsIDocShellTreeOwner * aTreeOwner)
|
||||
child->SetTreeOwner(aTreeOwner);
|
||||
}
|
||||
|
||||
// Our tree owner has changed. Recompute scriptability.
|
||||
//
|
||||
// Note that this is near-redundant with the recomputation in
|
||||
// SetDocLoaderParent(), but not so for the root DocShell, where the call to
|
||||
// SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
|
||||
// and we never set another parent. Given that this is neither expensive nor
|
||||
// performance-critical, let's be safe and unconditionally recompute this
|
||||
// state whenever dependent state changes.
|
||||
RecomputeCanExecuteScripts();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -12651,20 +12709,7 @@ unsigned long nsDocShell::gNumberOfDocShells = 0;
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetCanExecuteScripts(bool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
*aResult = false; // disallow by default
|
||||
|
||||
nsRefPtr<nsDocShell> docshell = this;
|
||||
do {
|
||||
nsresult rv = docshell->GetAllowJavascript(aResult);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!*aResult) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
docshell = docshell->GetParentDocshell();
|
||||
} while (docshell);
|
||||
|
||||
*aResult = mCanExecuteScripts;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -813,6 +813,12 @@ protected:
|
||||
bool mInPrivateBrowsing;
|
||||
bool mDeviceSizeIsPageSize;
|
||||
|
||||
// Because scriptability depends on the mAllowJavascript values of our
|
||||
// ancestors, we cache the effective scriptability and recompute it when
|
||||
// it might have changed;
|
||||
bool mCanExecuteScripts;
|
||||
void RecomputeCanExecuteScripts();
|
||||
|
||||
// This boolean is set to true right before we fire pagehide and generally
|
||||
// unset when we embed a new content viewer. While it's true no navigation
|
||||
// is allowed in this docshell.
|
||||
|
||||
@@ -570,7 +570,7 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
* The rule of thumb here is that we disable js if this docshell or any
|
||||
* of its parents disallow scripting.
|
||||
*/
|
||||
readonly attribute boolean canExecuteScripts;
|
||||
[infallible] readonly attribute boolean canExecuteScripts;
|
||||
|
||||
/**
|
||||
* Sets whether a docshell is active. An active docshell is one that is
|
||||
|
||||
@@ -2062,6 +2062,9 @@ WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
|
||||
mInnerWindowHolder = aHolder;
|
||||
|
||||
aWindow->SuspendTimeouts();
|
||||
|
||||
// When a global goes into the bfcache, we disable script.
|
||||
xpc::Scriptability::Get(aWindow->mJSObject).SetDocShellAllowsScript(false);
|
||||
}
|
||||
|
||||
WindowStateHolder::~WindowStateHolder()
|
||||
@@ -2460,6 +2463,10 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
// Enter the new global's compartment.
|
||||
JSAutoCompartment ac(cx, mJSObject);
|
||||
|
||||
// Set scriptability based on the state of the docshell.
|
||||
bool allow = GetDocShell()->GetCanExecuteScripts();
|
||||
xpc::Scriptability::Get(mJSObject).SetDocShellAllowsScript(allow);
|
||||
|
||||
// If we created a new inner window above, we need to do the last little bit
|
||||
// of initialization now that the dust has settled.
|
||||
if (createdInnerWindow) {
|
||||
|
||||
@@ -410,12 +410,14 @@ EnsureCompartmentPrivate(JSCompartment *c)
|
||||
return priv;
|
||||
}
|
||||
|
||||
Scriptability::Scriptability() : mScriptBlocks(0) {}
|
||||
Scriptability::Scriptability() : mScriptBlocks(0)
|
||||
, mDocShellAllowsScript(true)
|
||||
{}
|
||||
|
||||
bool
|
||||
Scriptability::Allowed()
|
||||
{
|
||||
return mScriptBlocks == 0;
|
||||
return mDocShellAllowsScript && mScriptBlocks == 0;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -431,6 +433,12 @@ Scriptability::Unblock()
|
||||
--mScriptBlocks;
|
||||
}
|
||||
|
||||
void
|
||||
Scriptability::SetDocShellAllowsScript(bool aAllowed)
|
||||
{
|
||||
mDocShellAllowsScript = aAllowed;
|
||||
}
|
||||
|
||||
/* static */
|
||||
Scriptability&
|
||||
Scriptability::Get(JSObject *aScope)
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
|
||||
void Block();
|
||||
void Unblock();
|
||||
void SetDocShellAllowsScript(bool aAllowed);
|
||||
|
||||
static Scriptability& Get(JSObject *aScope);
|
||||
|
||||
@@ -51,6 +52,10 @@ private:
|
||||
// re-enable it (if ever), it decrements this value with a call to Unblock().
|
||||
// Script may not run if this value is non-zero.
|
||||
uint32_t mScriptBlocks;
|
||||
|
||||
// Whether the docshell allows javascript in this scope. If this scope
|
||||
// doesn't have a docshell, this value is always true.
|
||||
bool mDocShellAllowsScript;
|
||||
};
|
||||
|
||||
JSObject *
|
||||
|
||||
Reference in New Issue
Block a user