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:
mrbkap%gmail.com 2005-08-23 01:42:49 +00:00
Родитель c55be881ae
Коммит c9b7989e36
4 изменённых файлов: 76 добавлений и 48 удалений

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

@ -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