Bug 1042587 - Block scripts when using CPOWs (r=bent)

This commit is contained in:
Bill McCloskey 2014-08-05 21:44:42 -07:00
parent 13debcc241
commit b63cf9051e
4 changed files with 95 additions and 4 deletions

View File

@ -5040,10 +5040,11 @@ nsContentUtils::GetAccessKeyCandidates(WidgetKeyboardEvent* aNativeKeyEvent,
void
nsContentUtils::AddScriptBlocker()
{
MOZ_ASSERT(NS_IsMainThread());
if (!sScriptBlockerCount) {
NS_ASSERTION(sRunnersCountAtFirstBlocker == 0,
"Should not already have a count");
sRunnersCountAtFirstBlocker = sBlockedScriptRunners->Length();
MOZ_ASSERT(sRunnersCountAtFirstBlocker == 0,
"Should not already have a count");
sRunnersCountAtFirstBlocker = sBlockedScriptRunners ? sBlockedScriptRunners->Length() : 0;
}
++sScriptBlockerCount;
}
@ -5056,6 +5057,7 @@ static bool sRemovingScriptBlockers = false;
void
nsContentUtils::RemoveScriptBlocker()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!sRemovingScriptBlockers);
NS_ASSERTION(sScriptBlockerCount != 0, "Negative script blockers");
--sScriptBlockerCount;
@ -5063,6 +5065,10 @@ nsContentUtils::RemoveScriptBlocker()
return;
}
if (!sBlockedScriptRunners) {
return;
}
uint32_t firstBlocker = sRunnersCountAtFirstBlocker;
uint32_t lastBlocker = sBlockedScriptRunners->Length();
uint32_t originalFirstBlocker = firstBlocker;

View File

@ -565,6 +565,10 @@ ContentChild::Init(MessageLoop* aIOLoop,
Open(aChannel, aParentHandle, aIOLoop);
sSingleton = this;
// Make sure there's an nsAutoScriptBlocker on the stack when dispatching
// urgent messages.
GetIPCChannel()->BlockScripts();
#ifdef MOZ_X11
// Send the parent our X socket to act as a proxy reference for our X
// resources.

View File

@ -13,6 +13,7 @@
#include "mozilla/Move.h"
#include "nsDebug.h"
#include "nsISupportsImpl.h"
#include "nsContentUtils.h"
// Undo the damage done by mozzconf.h
#undef compress
@ -188,6 +189,31 @@ private:
CxxStackFrame& operator=(const CxxStackFrame&) MOZ_DELETE;
};
namespace {
class MOZ_STACK_CLASS MaybeScriptBlocker {
public:
MaybeScriptBlocker(MessageChannel *aChannel
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mBlocked(aChannel->ShouldBlockScripts())
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mBlocked) {
nsContentUtils::AddScriptBlocker();
}
}
~MaybeScriptBlocker() {
if (mBlocked) {
nsContentUtils::RemoveScriptBlocker();
}
}
private:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
bool mBlocked;
};
} /* namespace {} */
MessageChannel::MessageChannel(MessageListener *aListener)
: mListener(aListener),
mChannelState(ChannelClosed),
@ -207,7 +233,8 @@ MessageChannel::MessageChannel(MessageListener *aListener)
mDispatchingUrgentMessageCount(0),
mRemoteStackDepthGuess(false),
mSawInterruptOutMsg(false),
mAbortOnError(false)
mAbortOnError(false),
mBlockScripts(false)
{
MOZ_COUNT_CTOR(ipc::MessageChannel);
@ -568,6 +595,9 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
bool
MessageChannel::Send(Message* aMsg, Message* aReply)
{
// See comment in DispatchUrgentMessage.
MaybeScriptBlocker scriptBlocker(this);
// Sanity checks.
AssertWorkerThread();
mMonitor->AssertNotCurrentThreadOwns();
@ -596,6 +626,9 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
bool
MessageChannel::UrgentCall(Message* aMsg, Message* aReply)
{
// See comment in DispatchUrgentMessage.
MaybeScriptBlocker scriptBlocker(this);
AssertWorkerThread();
mMonitor->AssertNotCurrentThreadOwns();
IPC_ASSERT(mSide == ParentSide, "cannot send urgent requests from child");
@ -625,6 +658,9 @@ MessageChannel::UrgentCall(Message* aMsg, Message* aReply)
bool
MessageChannel::RPCCall(Message* aMsg, Message* aReply)
{
// See comment in DispatchUrgentMessage.
MaybeScriptBlocker scriptBlocker(this);
AssertWorkerThread();
mMonitor->AssertNotCurrentThreadOwns();
IPC_ASSERT(mSide == ChildSide, "cannot send rpc messages from parent");
@ -1103,6 +1139,34 @@ MessageChannel::DispatchUrgentMessage(const Message& aMsg)
MOZ_ASSERT(NS_IsMainThread());
// We don't want to run any code that might run a nested event loop here, so
// we avoid running event handlers. Once we've sent the response to the
// urgent message, it's okay to run event handlers again since the parent is
// no longer blocked.
//
// We also put script blockers at the start of every synchronous send
// call. That way we won't run any scripts while waiting for a response to
// another message. Running scripts could cause us to send more sync
// messages, and the other side wouldn't know what to do if it received a
// sync message while dispatching another sync message. (In practice, the
// other side would queue the second sync message, while we would need it to
// dispatch that message before sending the reply to the original sync
// message. Otherwise the replies would come out of order.)
//
// We omit the script blocker for InterruptCall since interrupt messages are
// designed to handle this sort of re-entry. (For example, if the child
// sends an intr message to the parent, the child will process any queued
// async messages from the parent while waiting for the intr response. In
// doing so, the child could trigger sync messages to be sent to the parent
// while the parent is still dispatching the intr message. If the parent
// sends an intr reply while the child is waiting for a sync response, the
// intr reply will be queued in mPending. Once the sync reply is received,
// InterruptCall will find the intr reply in mPending and run it.) The
// situation where we run event handlers while waiting for an intr reply is
// no different than the one where we process async messages while waiting
// for an intr reply.
MaybeScriptBlocker scriptBlocker(this);
gDispatchingUrgentMessageCount++;
mDispatchingUrgentMessageCount++;
Result rv = mListener->OnCallReceived(aMsg, reply);
@ -1646,6 +1710,13 @@ MessageChannel::CloseWithError()
PostErrorNotifyTask();
}
void
MessageChannel::BlockScripts()
{
MOZ_ASSERT(NS_IsMainThread());
mBlockScripts = true;
}
void
MessageChannel::Close()
{

View File

@ -89,6 +89,13 @@ class MessageChannel : HasResultCodes
mAbortOnError = true;
}
void BlockScripts();
bool ShouldBlockScripts() const
{
return mBlockScripts;
}
// Asynchronously send a message to the other side of the channel
bool Send(Message* aMsg);
@ -639,6 +646,9 @@ class MessageChannel : HasResultCodes
// Should the channel abort the process from the I/O thread when
// a channel error occurs?
bool mAbortOnError;
// Should we prevent scripts from running while dispatching urgent messages?
bool mBlockScripts;
};
bool