Fix 18553 [DOGFOOD] addEventListener allows sniffing keystrokes

Add checks to nsScriptSecurityManager::CheckCanListenTo that take
a principal and ensure that the currently executing script code
either is from the same origin as that principal or has the
UniversalBrowserRead privilege enabled. (chrome code has all
privileges enabled by default.) It's okay for the principal passed in
to be null. That just signifies a privileged window/document that only
can be listened to with privileges.

I added GetPrincipal/SetPrincipal methods to nsIEventListenerManager.
nsDocument::GetNewListenerManager sets a principal on the listener
manager when it creates one. Obviously there are other places that
create listener managers, but scripts seem to go through this one.

Another change is to save some memory usage. Currently I allocate an
array of PolicyType that is NS_DOM_PROP_MAX elements long.
Unfortunately, compilers appear to allocate four bytes for each
PolicyType, so the array takes around 2400 bytes. I've added changes
to use two bit vectors that should consume about 1/16 that space.

r=joki

There are also changes that push nsnull onto the JSContext stack when
entering a nested event loop.

r=jband
This commit is contained in:
norris%netscape.com 1999-11-25 05:28:18 +00:00
Родитель a20778e024
Коммит 51842ef45e
15 изменённых файлов: 236 добавлений и 58 удалений

Просмотреть файл

@ -58,6 +58,8 @@ interface nsIScriptSecurityManager : nsISupports
*/
void CheckLoadURI(in nsIURI from, in nsIURI uri);
void CheckCanListenTo(in nsIPrincipal principal);
boolean HasSubjectPrincipal();
nsIPrincipal GetSubjectPrincipal();

Просмотреть файл

@ -49,12 +49,6 @@ public:
static nsScriptSecurityManager *
GetScriptSecurityManager();
enum PolicyType {
POLICY_TYPE_NONE = 0,
POLICY_TYPE_DEFAULT = 1,
POLICY_TYPE_PERDOMAIN = 2
};
nsObjectHashtable *mOriginToPolicyMap;
private:
@ -68,12 +62,11 @@ private:
CheckPermissions(JSContext *aCx, JSObject *aObj, const char *aCapability,
PRBool* result);
PRInt32
GetSecurityLevel(JSContext *cx, nsDOMProp domProp, PolicyType type,
PRBool isWrite, char **capability);
GetSecurityLevel(JSContext *cx, nsDOMProp domProp, PRBool isWrite,
char **capability);
NS_IMETHOD
GetPrefName(JSContext *cx, nsDOMProp domProp, PolicyType type,
char **result);
GetPrefName(JSContext *cx, nsDOMProp domProp, char **result);
NS_IMETHOD
CheckXPCPermissions(JSContext *cx);
@ -81,9 +74,13 @@ private:
NS_IMETHOD
InitFromPrefs();
static void
enumeratePolicyCallback(const char *prefName, void *data);
nsIPrincipal *mSystemPrincipal;
nsSupportsHashtable *mPrincipals;
PolicyType domPropertyPolicyTypes[NS_DOM_PROP_MAX];
unsigned char hasPolicyVector[(NS_DOM_PROP_MAX >> 3) + 1];
unsigned char hasDomainPolicyVector[(NS_DOM_PROP_MAX >> 3) + 1];
};
#endif /*_NS_SCRIPT_SECURITY_MANAGER_H_*/

Просмотреть файл

@ -147,6 +147,10 @@ nsCodebasePrincipal::SameOrigin(nsIPrincipal *other, PRBool *result)
*result = PR_TRUE;
return NS_OK;
}
if (other == nsnull) {
*result = PR_FALSE;
return NS_OK;
}
nsCOMPtr<nsICodebasePrincipal> otherCodebase;
if (NS_FAILED(other->QueryInterface(
NS_GET_IID(nsICodebasePrincipal),

Просмотреть файл

@ -325,6 +325,20 @@ nsScriptSecurityManager::QueryInterface(REFNSIID aIID, void** aInstancePtr)
NS_IMPL_ADDREF(nsScriptSecurityManager);
NS_IMPL_RELEASE(nsScriptSecurityManager);
inline PRBool
GetBit(unsigned char *bitVector, PRInt32 index)
{
unsigned char c = bitVector[index >> 3];
c &= (1 << (index & 7));
return c != 0;
}
inline void
SetBit(unsigned char *bitVector, PRInt32 index)
{
bitVector[index >> 3] |= (1 << (index & 7));
}
///////////////////////////////////////////////////
// Methods implementing nsIScriptSecurityManager //
@ -337,14 +351,14 @@ nsScriptSecurityManager::CheckScriptAccess(nsIScriptContext *aContext,
{
nsDOMProp domProp = (nsDOMProp) domPropInt;
*aResult = PR_FALSE;
PolicyType type = domPropertyPolicyTypes[domProp];
if (type == POLICY_TYPE_NONE) {
if (!GetBit(hasPolicyVector, domPropInt)) {
// No policy for this DOM property, so just allow access.
*aResult = PR_TRUE;
return NS_OK;
}
JSContext *cx = (JSContext *)aContext->GetNativeContext();
nsXPIDLCString capability;
PRInt32 secLevel = GetSecurityLevel(cx, domProp, type, isWrite,
PRInt32 secLevel = GetSecurityLevel(cx, domProp, isWrite,
getter_Copies(capability));
switch (secLevel) {
case SCRIPT_SECURITY_ALL_ACCESS:
@ -463,6 +477,37 @@ nsScriptSecurityManager::CheckLoadURI(nsIURI *aFromURI,
return NS_ERROR_DOM_BAD_URI;
}
NS_IMETHODIMP
nsScriptSecurityManager::CheckCanListenTo(nsIPrincipal *principal)
{
nsCOMPtr<nsIPrincipal> subject;
nsresult rv;
PRBool hasSubject;
if (NS_FAILED(rv = HasSubjectPrincipal(&hasSubject)))
return rv;
if (!hasSubject)
return NS_OK; // No script code, so native code has access.
if (NS_FAILED(rv = GetSubjectPrincipal(getter_AddRefs(subject))))
return rv;
nsCOMPtr<nsICodebasePrincipal> codebase = do_QueryInterface(subject);
PRBool equals;
if (codebase && NS_SUCCEEDED(codebase->SameOrigin(principal, &equals))) {
if (equals)
return NS_OK; // Listener and Listened-to have same origin
}
PRBool enabled;
if (NS_SUCCEEDED(IsCapabilityEnabled("UniversalBrowserRead", &enabled))) {
if (enabled)
return NS_OK; // Capability allows access
}
// Report error
JSContext *cx = GetCurrentContext();
JS_ReportError(cx, "Access denied to listen to events across origins");
return NS_ERROR_DOM_PROP_ACCESS_DENIED;
}
NS_IMETHODIMP
nsScriptSecurityManager::HasSubjectPrincipal(PRBool *result)
{
@ -810,7 +855,8 @@ nsScriptSecurityManager::nsScriptSecurityManager(void)
mPrincipals(nsnull)
{
NS_INIT_REFCNT();
memset(domPropertyPolicyTypes, 0, sizeof(domPropertyPolicyTypes));
memset(hasPolicyVector, 0, sizeof(hasPolicyVector));
memset(hasDomainPolicyVector, 0, sizeof(hasDomainPolicyVector));
InitFromPrefs();
}
@ -948,11 +994,10 @@ nsScriptSecurityManager::CheckPermissions(JSContext *aCx, JSObject *aObj,
PRInt32
nsScriptSecurityManager::GetSecurityLevel(JSContext *cx, nsDOMProp domProp,
PolicyType type, PRBool isWrite,
char **capability)
PRBool isWrite, char **capability)
{
nsXPIDLCString prefName;
if (NS_FAILED(GetPrefName(cx, domProp, type, getter_Copies(prefName))))
if (NS_FAILED(GetPrefName(cx, domProp, getter_Copies(prefName))))
return SCRIPT_SECURITY_NO_ACCESS;
PRInt32 secLevel;
char *secLevelString;
@ -1893,14 +1938,14 @@ static char *domPropNames[NS_DOM_PROP_MAX] = {
NS_IMETHODIMP
nsScriptSecurityManager::GetPrefName(JSContext *cx, nsDOMProp domProp,
PolicyType type, char **result)
char **result)
{
nsresult rv;
static const char *defaultStr = "default";
nsAutoString s = "security.policy.";
if (type == POLICY_TYPE_DEFAULT) {
if (!GetBit(hasDomainPolicyVector, domProp)) {
s += defaultStr;
} else if (type == POLICY_TYPE_PERDOMAIN) {
} else {
nsCOMPtr<nsIPrincipal> principal;
if (NS_FAILED(GetSubjectPrincipal(cx, getter_AddRefs(principal)))) {
return NS_ERROR_FAILURE;
@ -1963,13 +2008,14 @@ DeleteEntry(nsHashKey *aKey, void *aData, void* closure)
}
struct PolicyEnumeratorInfo {
nsScriptSecurityManager::PolicyType *policies;
nsIPref *prefs;
nsScriptSecurityManager *secMan;
};
PR_STATIC_CALLBACK(void)
enumeratePolicy(const char *prefName, void *data) {
void
nsScriptSecurityManager::enumeratePolicyCallback(const char *prefName,
void *data)
{
if (!prefName || !*prefName)
return;
PolicyEnumeratorInfo *info = (PolicyEnumeratorInfo *) data;
@ -2029,12 +2075,9 @@ enumeratePolicy(const char *prefName, void *data) {
int domPropLength = dots[4] - domPropName;
nsDOMProp domProp = findDomProp(domPropName, domPropLength);
if (domProp < NS_DOM_PROP_MAX) {
nsScriptSecurityManager::PolicyType *policyType =
info->policies + domProp;
SetBit(info->secMan->hasPolicyVector, domProp);
if (!isDefault)
*policyType = nsScriptSecurityManager::POLICY_TYPE_PERDOMAIN;
else if (*policyType == nsScriptSecurityManager::POLICY_TYPE_NONE)
*policyType = nsScriptSecurityManager::POLICY_TYPE_DEFAULT;
SetBit(info->secMan->hasDomainPolicyVector, domProp);
return;
}
}
@ -2049,10 +2092,10 @@ nsScriptSecurityManager::InitFromPrefs()
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
PolicyEnumeratorInfo info;
info.policies = domPropertyPolicyTypes;
info.prefs = prefs;
info.secMan = this;
prefs->EnumerateChildren("security.policy", enumeratePolicy,
prefs->EnumerateChildren("security.policy",
nsScriptSecurityManager::enumeratePolicyCallback,
(void *) &info);
return NS_OK;
}

Просмотреть файл

@ -2334,9 +2334,9 @@ nsDocument::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
nsresult nsDocument::GetListenerManager(nsIEventListenerManager **aInstancePtrResult)
{
if (nsnull != mListenerManager) {
return mListenerManager->QueryInterface(kIEventListenerManagerIID, (void**) aInstancePtrResult);;
return mListenerManager->QueryInterface(kIEventListenerManagerIID, (void**) aInstancePtrResult);
}
if (NS_OK == NS_NewEventListenerManager(aInstancePtrResult)) {
if (NS_OK == GetNewListenerManager(aInstancePtrResult)) {
mListenerManager = *aInstancePtrResult;
NS_ADDREF(mListenerManager);
return NS_OK;
@ -2346,7 +2346,15 @@ nsresult nsDocument::GetListenerManager(nsIEventListenerManager **aInstancePtrRe
nsresult nsDocument::GetNewListenerManager(nsIEventListenerManager **aInstancePtrResult)
{
return NS_NewEventListenerManager(aInstancePtrResult);
nsresult rv = NS_NewEventListenerManager(aInstancePtrResult);
if (NS_FAILED(rv))
return rv;
nsIPrincipal *principal = GetDocumentPrincipal();
if (principal) {
(*aInstancePtrResult)->SetPrincipal(principal);
NS_RELEASE(principal);
}
return NS_OK;
}
nsresult nsDocument::HandleDOMEvent(nsIPresContext* aPresContext,

Просмотреть файл

@ -138,11 +138,26 @@ public:
virtual nsresult ReleaseEvent(nsIDOMEventListener *aListener) = 0;
/**
* Removes all events listeners registered by this instance of the listener
* Removes all event listeners registered by this instance of the listener
* manager.
*/
virtual nsresult RemoveAllListeners(PRBool aScriptOnly) = 0;
/**
* Sets the principal of the entity being listened to.
*
* Used for security checks that ensure that events can't propagate past
* trust boundaries.
*/
virtual nsresult SetPrincipal(nsIPrincipal *aListenedToPrincipal) = 0;
/**
* Gets the principal of the entity being listened to.
*/
virtual nsresult GetPrincipal(nsIPrincipal **aListenedToPrincipal) = 0;
};
extern NS_HTML nsresult NS_NewEventListenerManager(nsIEventListenerManager** aInstancePtrResult);

Просмотреть файл

@ -50,6 +50,8 @@
#include "nsINameSpaceManager.h"
#include "nsIContent.h"
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "nsIScriptSecurityManager.h"
static NS_DEFINE_IID(kIEventListenerManagerIID, NS_IEVENTLISTENERMANAGER_IID);
static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID);
@ -235,6 +237,15 @@ nsresult nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener
NS_IF_RELEASE(sel);
if (!found) {
// Check to see if we can add a new listener.
nsresult rv;
NS_WITH_SERVICE(nsIScriptSecurityManager, securityManager,
NS_SCRIPTSECURITYMANAGER_PROGID, &rv);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
rv = securityManager->CheckCanListenTo(mPrincipal);
if (NS_FAILED(rv))
return rv;
ls = PR_NEW(nsListenerStruct);
if (ls) {
ls->mListener = aListener;
@ -1416,6 +1427,20 @@ nsresult nsEventListenerManager::RemoveAllListeners(PRBool aScriptOnly)
return NS_OK;
}
nsresult nsEventListenerManager::GetPrincipal(nsIPrincipal **aListenedToPrincipal)
{
*aListenedToPrincipal = mPrincipal;
if (*aListenedToPrincipal)
NS_ADDREF(*aListenedToPrincipal);
return NS_OK;
}
nsresult nsEventListenerManager::SetPrincipal(nsIPrincipal *aListenedToPrincipal)
{
mPrincipal = aListenedToPrincipal;
return NS_OK;
}
NS_HTML nsresult NS_NewEventListenerManager(nsIEventListenerManager** aInstancePtrResult)
{
nsIEventListenerManager* l = new nsEventListenerManager();

Просмотреть файл

@ -25,6 +25,8 @@
#include "nsIEventListenerManager.h"
#include "jsapi.h"
#include "nsCOMPtr.h"
#include "nsIPrincipal.h"
class nsIDOMEvent;
class nsIAtom;
@ -97,6 +99,9 @@ public:
virtual nsresult RemoveAllListeners(PRBool aScriptOnly);
virtual nsresult SetPrincipal(nsIPrincipal *aListenedToPrincipal);
virtual nsresult GetPrincipal(nsIPrincipal **aListenedToPrincipal);
static nsresult GetIdentifiersForType(nsIAtom* aType, nsIID& aIID, PRInt32* aSubType);
protected:
@ -121,10 +126,11 @@ protected:
nsVoidArray* mTextListeners;
nsVoidArray* mCompositionListeners;
nsVoidArray* mMenuListeners;
nsCOMPtr<nsIPrincipal> mPrincipal;
};
//Set of defines for distinguishing event hanlders within listener groupings
//Set of defines for distinguishing event handlers within listener groupings
//XXX Current usage allows no more than 7 types per listener grouping
#define NS_EVENT_BITS_NONE 0x00

Просмотреть файл

@ -1009,7 +1009,7 @@ static const char kMethodBodyBeginStr[] = "\n"
" }\n"
" {\n"
" PRBool ok;\n"
" secMan->CheckScriptAccess(scriptCX, obj, NS_DOM_PROP_%s_%s,PR_FALSE , &ok);\n"
" secMan->CheckScriptAccess(scriptCX, obj, NS_DOM_PROP_%s_%s, PR_FALSE, &ok);\n"
" if (!ok) {\n"
" return nsJSUtils::nsReportError(cx, NS_ERROR_DOM_SECURITY_ERR);\n"
" }\n"

Просмотреть файл

@ -2334,9 +2334,9 @@ nsDocument::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
nsresult nsDocument::GetListenerManager(nsIEventListenerManager **aInstancePtrResult)
{
if (nsnull != mListenerManager) {
return mListenerManager->QueryInterface(kIEventListenerManagerIID, (void**) aInstancePtrResult);;
return mListenerManager->QueryInterface(kIEventListenerManagerIID, (void**) aInstancePtrResult);
}
if (NS_OK == NS_NewEventListenerManager(aInstancePtrResult)) {
if (NS_OK == GetNewListenerManager(aInstancePtrResult)) {
mListenerManager = *aInstancePtrResult;
NS_ADDREF(mListenerManager);
return NS_OK;
@ -2346,7 +2346,15 @@ nsresult nsDocument::GetListenerManager(nsIEventListenerManager **aInstancePtrRe
nsresult nsDocument::GetNewListenerManager(nsIEventListenerManager **aInstancePtrResult)
{
return NS_NewEventListenerManager(aInstancePtrResult);
nsresult rv = NS_NewEventListenerManager(aInstancePtrResult);
if (NS_FAILED(rv))
return rv;
nsIPrincipal *principal = GetDocumentPrincipal();
if (principal) {
(*aInstancePtrResult)->SetPrincipal(principal);
NS_RELEASE(principal);
}
return NS_OK;
}
nsresult nsDocument::HandleDOMEvent(nsIPresContext* aPresContext,

Просмотреть файл

@ -138,11 +138,26 @@ public:
virtual nsresult ReleaseEvent(nsIDOMEventListener *aListener) = 0;
/**
* Removes all events listeners registered by this instance of the listener
* Removes all event listeners registered by this instance of the listener
* manager.
*/
virtual nsresult RemoveAllListeners(PRBool aScriptOnly) = 0;
/**
* Sets the principal of the entity being listened to.
*
* Used for security checks that ensure that events can't propagate past
* trust boundaries.
*/
virtual nsresult SetPrincipal(nsIPrincipal *aListenedToPrincipal) = 0;
/**
* Gets the principal of the entity being listened to.
*/
virtual nsresult GetPrincipal(nsIPrincipal **aListenedToPrincipal) = 0;
};
extern NS_HTML nsresult NS_NewEventListenerManager(nsIEventListenerManager** aInstancePtrResult);

Просмотреть файл

@ -50,6 +50,8 @@
#include "nsINameSpaceManager.h"
#include "nsIContent.h"
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "nsIScriptSecurityManager.h"
static NS_DEFINE_IID(kIEventListenerManagerIID, NS_IEVENTLISTENERMANAGER_IID);
static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID);
@ -235,6 +237,15 @@ nsresult nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener
NS_IF_RELEASE(sel);
if (!found) {
// Check to see if we can add a new listener.
nsresult rv;
NS_WITH_SERVICE(nsIScriptSecurityManager, securityManager,
NS_SCRIPTSECURITYMANAGER_PROGID, &rv);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
rv = securityManager->CheckCanListenTo(mPrincipal);
if (NS_FAILED(rv))
return rv;
ls = PR_NEW(nsListenerStruct);
if (ls) {
ls->mListener = aListener;
@ -1416,6 +1427,20 @@ nsresult nsEventListenerManager::RemoveAllListeners(PRBool aScriptOnly)
return NS_OK;
}
nsresult nsEventListenerManager::GetPrincipal(nsIPrincipal **aListenedToPrincipal)
{
*aListenedToPrincipal = mPrincipal;
if (*aListenedToPrincipal)
NS_ADDREF(*aListenedToPrincipal);
return NS_OK;
}
nsresult nsEventListenerManager::SetPrincipal(nsIPrincipal *aListenedToPrincipal)
{
mPrincipal = aListenedToPrincipal;
return NS_OK;
}
NS_HTML nsresult NS_NewEventListenerManager(nsIEventListenerManager** aInstancePtrResult)
{
nsIEventListenerManager* l = new nsEventListenerManager();

Просмотреть файл

@ -25,6 +25,8 @@
#include "nsIEventListenerManager.h"
#include "jsapi.h"
#include "nsCOMPtr.h"
#include "nsIPrincipal.h"
class nsIDOMEvent;
class nsIAtom;
@ -97,6 +99,9 @@ public:
virtual nsresult RemoveAllListeners(PRBool aScriptOnly);
virtual nsresult SetPrincipal(nsIPrincipal *aListenedToPrincipal);
virtual nsresult GetPrincipal(nsIPrincipal **aListenedToPrincipal);
static nsresult GetIdentifiersForType(nsIAtom* aType, nsIID& aIID, PRInt32* aSubType);
protected:
@ -121,10 +126,11 @@ protected:
nsVoidArray* mTextListeners;
nsVoidArray* mCompositionListeners;
nsVoidArray* mMenuListeners;
nsCOMPtr<nsIPrincipal> mPrincipal;
};
//Set of defines for distinguishing event hanlders within listener groupings
//Set of defines for distinguishing event handlers within listener groupings
//XXX Current usage allows no more than 7 types per listener grouping
#define NS_EVENT_BITS_NONE 0x00

Просмотреть файл

@ -35,6 +35,7 @@ DEPTH=..\..\..
IDLSRCS= \
AppCoresManager.idl \
BaseAppCore.idl \
BrowserAppCore.idl \
ToolkitCore.idl
!endif

Просмотреть файл

@ -68,6 +68,7 @@ static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
// For JS Execution
#include "nsIScriptContextOwner.h"
#include "nsIJSContextStack.h"
#include "nsIEventQueueService.h"
#include "plevent.h"
@ -1554,14 +1555,25 @@ nsWebShellWindow::NewWebShell(PRUint32 aChromeMask, PRBool aVisible,
PRBool locked = PR_FALSE;
nsresult looprv = NS_OK;
newWindow->GetLockedState(locked);
while (NS_SUCCEEDED(looprv) && locked) {
void *data;
PRBool isRealEvent;
looprv = subshell->GetNativeEvent(isRealEvent, data);
subshell->DispatchNativeEvent(isRealEvent, data);
newWindow->GetLockedState(locked);
// Push nsnull onto the JSContext stack before we dispatch a native event.
NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack",
&rv);
if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(stack->Push(nsnull))) {
while (NS_SUCCEEDED(looprv) && locked) {
void *data;
PRBool isRealEvent;
looprv = subshell->GetNativeEvent(isRealEvent, data);
subshell->DispatchNativeEvent(isRealEvent, data);
newWindow->GetLockedState(locked);
}
JSContext *cx;
stack->Pop(&cx);
NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
}
subshell->Spindown();
@ -1737,17 +1749,28 @@ nsWebShellWindow::ShowModalInternal()
window->SetModal(PR_TRUE);
NS_ADDREF(window);
mContinueModalLoop = PR_TRUE;
while (NS_SUCCEEDED(rv) && mContinueModalLoop) {
void *data;
PRBool isRealEvent,
processEvent;
rv = subshell->GetNativeEvent(isRealEvent, data);
if (NS_SUCCEEDED(rv)) {
window->ModalEventFilter(isRealEvent, data, &processEvent);
if (processEvent)
subshell->DispatchNativeEvent(isRealEvent, data);
// Push nsnull onto the JSContext stack before we dispatch a native event.
NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack",
&rv);
if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(stack->Push(nsnull))) {
while (NS_SUCCEEDED(rv) && mContinueModalLoop) {
void *data;
PRBool isRealEvent,
processEvent;
rv = subshell->GetNativeEvent(isRealEvent, data);
if (NS_SUCCEEDED(rv)) {
window->ModalEventFilter(isRealEvent, data, &processEvent);
if (processEvent)
subshell->DispatchNativeEvent(isRealEvent, data);
}
}
JSContext *cx;
stack->Pop(&cx);
NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
}
window->SetModal(PR_FALSE);