зеркало из https://github.com/mozilla/pjs.git
bug 304882: Store the location object on the outer window instead of the inner window so that security checks do the Right Thing. Also change some if statements into assertions so we catch bad states. r+sr=jst
This commit is contained in:
Родитель
c55be881ae
Коммит
c9b7989e36
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -496,7 +497,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
|||
|
||||
// Don't allow modifications to Location.prototype
|
||||
NS_DEFINE_CLASSINFO_DATA(Location, nsLocationSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS &
|
||||
(DOM_DEFAULT_SCRIPTABLE_FLAGS |
|
||||
nsIXPCScriptable::WANT_PRECREATE) &
|
||||
~nsIXPCScriptable::ALLOW_PROP_MODS_TO_PROTOTYPE)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(Navigator, nsNavigatorSH,
|
||||
|
@ -5845,6 +5847,35 @@ nsLocationSH::CheckAccess(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|||
return nsDOMGenericSH::CheckAccess(wrapper, cx, obj, id, mode, vp, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLocationSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj)
|
||||
{
|
||||
// window.location can be held onto by both evil pages that want to track the
|
||||
// user's progress on the web and bookmarklets that want to use the location
|
||||
// object. Parent it to the outer window so that access checks do the Right
|
||||
// Thing.
|
||||
*parentObj = globalObj;
|
||||
|
||||
nsLocation *loc = (nsLocation *)(nsIDOMLocation *)nativeObj;
|
||||
nsIDocShell *ds = loc->GetDocShell();
|
||||
if (!ds) {
|
||||
NS_WARNING("Refusing to create a location in the wrong scope");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(ds);
|
||||
|
||||
if (sgo) {
|
||||
JSObject *global = sgo->GetGlobalJSObject();
|
||||
|
||||
if (global) {
|
||||
*parentObj = global;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// DOM Navigator helper
|
||||
nsresult
|
||||
|
@ -5862,7 +5893,7 @@ nsNavigatorSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
|
|||
nsIDocShell *ds = nav->GetDocShell();
|
||||
if (!ds) {
|
||||
NS_WARNING("Refusing to create a navigator in the wrong scope");
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(ds);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -479,6 +480,9 @@ public:
|
|||
JSObject *obj, jsval id, PRUint32 mode,
|
||||
jsval *vp, PRBool *_retval);
|
||||
|
||||
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj);
|
||||
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsLocationSH(aData);
|
||||
|
|
|
@ -426,15 +426,6 @@ nsGlobalWindow::FreeInnerObjects(JSContext *cx)
|
|||
|
||||
mChromeEventHandler = nsnull;
|
||||
|
||||
if (mLocation) {
|
||||
// Invalidate the inner window's location object now that
|
||||
// the inner window is being torn down. We need to do this
|
||||
// to prevent people from holding on to an old inner
|
||||
// window's location object somehow and tracking the
|
||||
// location of the docshell...
|
||||
mLocation->SetDocShell(nsnull);
|
||||
}
|
||||
|
||||
if (mListenerManager) {
|
||||
mListenerManager->RemoveAllListeners(PR_FALSE);
|
||||
mListenerManager = nsnull;
|
||||
|
@ -665,7 +656,7 @@ nsGlobalWindow::GetPopupControlState() const
|
|||
}
|
||||
|
||||
#define WINDOWSTATEHOLDER_IID \
|
||||
{0x2aa29291, 0x3ac9, 0x4d37, {0xa4, 0x3d, 0x45, 0x15, 0x2f, 0x16, 0x23, 0x04 }}
|
||||
{0x6fb7a1b5, 0x2dfe, 0x40a7, {0xbc, 0xee, 0x1f, 0xac, 0xd2, 0x8d, 0x47, 0x62}}
|
||||
|
||||
class WindowStateHolder : public nsISupports
|
||||
{
|
||||
|
@ -675,7 +666,8 @@ public:
|
|||
|
||||
WindowStateHolder(nsGlobalWindow *aWindow,
|
||||
nsIXPConnectJSObjectHolder *aHolder,
|
||||
nsNavigator *aNavigator);
|
||||
nsNavigator *aNavigator,
|
||||
nsLocation *aLocation);
|
||||
|
||||
// Get the contents of focus memory when the state was saved
|
||||
// (if the focus was inside of this window).
|
||||
|
@ -687,12 +679,14 @@ public:
|
|||
{ return mInnerWindowHolder; }
|
||||
|
||||
nsNavigator* GetNavigator() { return mNavigator; }
|
||||
nsLocation* GetLocation() { return mLocation; }
|
||||
|
||||
void DidRestoreWindow()
|
||||
{
|
||||
mInnerWindow = nsnull;
|
||||
mInnerWindowHolder = nsnull;
|
||||
mNavigator = nsnull;
|
||||
mLocation = nsnull;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -703,16 +697,19 @@ protected:
|
|||
// window ends up recalculating it anyway.
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
|
||||
nsRefPtr<nsNavigator> mNavigator;
|
||||
nsRefPtr<nsLocation> mLocation;
|
||||
nsCOMPtr<nsIDOMElement> mFocusedElement;
|
||||
nsCOMPtr<nsIDOMWindowInternal> mFocusedWindow;
|
||||
};
|
||||
|
||||
WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
|
||||
nsIXPConnectJSObjectHolder *aHolder,
|
||||
nsNavigator *aNavigator)
|
||||
nsNavigator *aNavigator,
|
||||
nsLocation *aLocation)
|
||||
: mInnerWindow(aWindow),
|
||||
mInnerWindowHolder(aHolder),
|
||||
mNavigator(aNavigator)
|
||||
mNavigator(aNavigator),
|
||||
mLocation(aLocation)
|
||||
{
|
||||
NS_PRECONDITION(aWindow, "null window");
|
||||
NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
|
||||
|
@ -765,6 +762,11 @@ WindowStateHolder::~WindowStateHolder()
|
|||
}
|
||||
|
||||
mInnerWindow->FreeInnerObjects(cx);
|
||||
|
||||
if (mLocation) {
|
||||
// Don't leave the weak reference to the docshell lying around.
|
||||
mLocation->SetDocShell(nsnull);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -938,15 +940,6 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
|
|||
currentInner->ClearAllTimeouts();
|
||||
|
||||
currentInner->mChromeEventHandler = nsnull;
|
||||
|
||||
if (currentInner->mLocation) {
|
||||
// Invalidate the inner window's location object now that
|
||||
// the inner window is being torn down. We need to do this
|
||||
// to prevent people from holding on to an old inner
|
||||
// window's location object somehow and tracking the
|
||||
// location of the docshell...
|
||||
currentInner->mLocation->SetDocShell(nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
if (aRemoveEventListeners && currentInner->mListenerManager) {
|
||||
|
@ -976,8 +969,10 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
|
|||
// XXX They don't get restored on the inner window when we go back.
|
||||
::JS_ClearRegExpStatics(cx);
|
||||
|
||||
if (reUseInnerWindow && !currentInner->IsFrozen()) {
|
||||
if (reUseInnerWindow) {
|
||||
// We're reusing the current inner window.
|
||||
NS_ASSERTION(!currentInner->IsFrozen(),
|
||||
"We should never be reusing a shared inner window");
|
||||
newInnerWindow = currentInner;
|
||||
} else {
|
||||
if (aState) {
|
||||
|
@ -986,7 +981,10 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
|
|||
|
||||
newInnerWindow = wsh->GetInnerWindow();
|
||||
mInnerWindowHolder = wsh->GetInnerWindowHolder();
|
||||
mNavigator = wsh->GetNavigator(); // This assignment addrefs.
|
||||
|
||||
// These assignments addref.
|
||||
mNavigator = wsh->GetNavigator();
|
||||
mLocation = wsh->GetLocation();
|
||||
|
||||
if (mNavigator) {
|
||||
// Update mNavigator's docshell pointer now.
|
||||
|
@ -1001,6 +999,8 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
|
|||
} else {
|
||||
newInnerWindow = new nsGlobalWindow(this);
|
||||
}
|
||||
|
||||
mLocation = nsnull;
|
||||
}
|
||||
|
||||
if (!newInnerWindow) {
|
||||
|
@ -1063,12 +1063,13 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
|
|||
}
|
||||
|
||||
nsIScriptContext *callerScx;
|
||||
if (cx && (callerScx = GetScriptContextFromJSContext(cx)) &&
|
||||
!currentInner->IsFrozen()) {
|
||||
if (cx && (callerScx = GetScriptContextFromJSContext(cx))) {
|
||||
// We're called from document.open() (and document.open() is
|
||||
// called from JS), clear the scope etc in a termination
|
||||
// function on the calling context to prevent clearing the
|
||||
// calling scope.
|
||||
NS_ASSERTION(!currentInner->IsFrozen(),
|
||||
"How does this opened window get into session history");
|
||||
callerScx->SetTerminationFunction(ClearWindowScope,
|
||||
NS_STATIC_CAST(nsIDOMWindow *,
|
||||
currentInner));
|
||||
|
@ -1257,10 +1258,10 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
|
|||
|
||||
mDocShell = aDocShell; // Weak Reference
|
||||
|
||||
NS_ASSERTION(!mLocation, "Uh, outer window has location object!");
|
||||
|
||||
if (mNavigator)
|
||||
mNavigator->SetDocShell(aDocShell);
|
||||
if (mLocation)
|
||||
mLocation->SetDocShell(aDocShell);
|
||||
if (mHistory)
|
||||
mHistory->SetDocShell(aDocShell);
|
||||
if (mFrames)
|
||||
|
@ -5124,12 +5125,12 @@ nsGlobalWindow::GetPrivateRoot()
|
|||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
|
||||
{
|
||||
FORWARD_TO_INNER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED);
|
||||
FORWARD_TO_OUTER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
*aLocation = nsnull;
|
||||
|
||||
if (!mLocation && GetDocShellInternal()) {
|
||||
mLocation = new nsLocation(GetDocShellInternal());
|
||||
if (!mLocation && mDocShell) {
|
||||
mLocation = new nsLocation(mDocShell);
|
||||
if (!mLocation) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -6664,23 +6665,14 @@ nsGlobalWindow::SaveWindowState(nsISupports **aState)
|
|||
|
||||
nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
|
||||
mInnerWindowHolder,
|
||||
mNavigator);
|
||||
mNavigator,
|
||||
mLocation);
|
||||
NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
#ifdef DEBUG_PAGE_CACHE
|
||||
printf("saving window state, state = %p\n", (void*)state);
|
||||
#endif
|
||||
|
||||
if (inner->mLocation) {
|
||||
// Invalidate the inner window's location object now that the inner window
|
||||
// is being put into the bfcache. We need to do this to prevent people from
|
||||
// holding on to an old inner window's location object somehow and tracking
|
||||
// the location of the docshell. The docshell is restored when the window is
|
||||
// taken out of the bfcache (meaning that any stale references to it will
|
||||
// only see that particular document).
|
||||
inner->mLocation->SetDocShell(nsnull);
|
||||
}
|
||||
|
||||
// Don't do anything else to this inner window!
|
||||
inner->Freeze();
|
||||
|
||||
|
@ -6749,9 +6741,6 @@ nsGlobalWindow::RestoreWindowState(nsISupports *aState)
|
|||
// And we're ready to go!
|
||||
inner->Thaw();
|
||||
|
||||
if (inner->mLocation)
|
||||
inner->mLocation->SetDocShell(mDocShell);
|
||||
|
||||
holder->DidRestoreWindow();
|
||||
|
||||
return inner->ResumeTimeouts();
|
||||
|
|
|
@ -444,6 +444,7 @@ protected:
|
|||
nsRefPtr<nsBarProp> mStatusbar;
|
||||
nsRefPtr<nsBarProp> mScrollbars;
|
||||
nsCOMPtr<nsIWeakReference> mWindowUtils;
|
||||
nsRefPtr<nsLocation> mLocation;
|
||||
nsString mStatus;
|
||||
nsString mDefaultStatus;
|
||||
|
||||
|
@ -460,7 +461,6 @@ protected:
|
|||
nsTimeout** mTimeoutInsertionPoint;
|
||||
PRUint32 mTimeoutPublicIdCounter;
|
||||
PRUint32 mTimeoutFiringDepth;
|
||||
nsRefPtr<nsLocation> mLocation;
|
||||
|
||||
// These member variables are used on both inner and the outer windows.
|
||||
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
|
||||
|
@ -634,6 +634,10 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
|
||||
void SetDocShell(nsIDocShell *aDocShell);
|
||||
nsIDocShell *GetDocShell()
|
||||
{
|
||||
return mDocShell;
|
||||
}
|
||||
|
||||
// nsIDOMLocation
|
||||
NS_DECL_NSIDOMLOCATION
|
||||
|
|
Загрузка…
Ссылка в новой задаче