Bug 802557 - Do more direct comparisons with the outer window. r=bz a=akeybl GECKO1009_2012101115_RELBRANCH
authorBobby Holley <bobbyholley@gmail.com>
Fri, 19 Oct 2012 01:37:14 +0200
branchGECKO1009_2012101115_RELBRANCH
changeset 82049 6564d2216240ff6c1742cb4a3b7436800135d9dc
parent 82048 246c665f50d32cc064ba4c5b91997df21c796342
child 82050 481667090414fcd0fb7513fa1d3149e438dfc06d
push id311
push userbobbyholley@gmail.com
push dateWed, 24 Oct 2012 10:26:28 +0000
reviewersbz, akeybl
bugs802557
milestone10.0.9
Bug 802557 - Do more direct comparisons with the outer window. r=bz a=akeybl
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
dom/base/nsLocation.cpp
dom/base/nsLocation.h
dom/tests/mochitest/storageevent/interOriginFrame.js
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -489,16 +489,20 @@ public:
    * Get the cache security manager service. Can return null if the layout
    * module has been shut down.
    */
   static nsIScriptSecurityManager* GetSecurityManager()
   {
     return sSecurityManager;
   }
 
+  // Returns the subject principal. Guaranteed to return non-null. May only
+  // be called when nsContentUtils is initialized.
+  static nsIPrincipal* GetSubjectPrincipal();
+
   static nsresult GenerateStateKey(nsIContent* aContent,
                                    const nsIDocument* aDocument,
                                    nsIStatefulFrame::SpecialStateID aID,
                                    nsACString& aKey);
 
   /**
    * Create a new nsIURI from aSpec, using aBaseURI as the base.  The
    * origin charset of the new nsIURI will be the document charset of
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -1991,16 +1991,30 @@ nsContentUtils::GenerateStateKey(nsICont
       parent = content->GetNodeParent();
     }
   }
 
   return NS_OK;
 }
 
 // static
+nsIPrincipal*
+nsContentUtils::GetSubjectPrincipal()
+{
+  nsCOMPtr<nsIPrincipal> subject;
+  sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subject));
+
+  // When the ssm says the subject is null, that means system principal.
+  if (!subject)
+    sSecurityManager->GetSystemPrincipal(getter_AddRefs(subject));
+
+  return subject;
+}
+
+// static
 nsresult
 nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult,
                                           const nsAString& aSpec,
                                           nsIDocument* aDocument,
                                           nsIURI* aBaseURI)
 {
   return NS_NewURI(aResult, aSpec,
                    aDocument ? aDocument->GetDocumentCharacterSet().get() : nsnull,
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -35,16 +35,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsLocation.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsIWebNavigation.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsIURIFixup.h"
 #include "nsIURL.h"
 #include "nsIJARURI.h"
@@ -136,16 +137,18 @@ GetDocumentCharacterSetForURI(const nsAS
   }
 
   return NS_OK;
 }
 
 nsLocation::nsLocation(nsIDocShell *aDocShell)
 {
   mDocShell = do_GetWeakReference(aDocShell);
+  nsCOMPtr<nsIDOMWindow> outer = do_GetInterface(aDocShell);
+  mOuter = do_GetWeakReference(outer);
 }
 
 nsLocation::~nsLocation()
 {
 }
 
 DOMCI_DATA(Location, nsLocation)
 
@@ -372,16 +375,19 @@ nsLocation::SetURI(nsIURI* aURI, bool aR
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsLocation::GetHash(nsAString& aHash)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   aHash.SetLength(0);
 
   nsCOMPtr<nsIURI> uri;
   nsresult rv = GetURI(getter_AddRefs(uri));
   if (NS_FAILED(rv) || !uri) {
     return rv;
   }
 
@@ -444,16 +450,19 @@ nsLocation::SetHash(const nsAString& aHa
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsLocation::GetHost(nsAString& aHost)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   aHost.Truncate();
 
   nsCOMPtr<nsIURI> uri;
   nsresult result;
 
   result = GetURI(getter_AddRefs(uri), true);
 
   if (uri) {
@@ -467,32 +476,38 @@ nsLocation::GetHost(nsAString& aHost)
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsLocation::SetHost(const nsAString& aHost)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsCOMPtr<nsIURI> uri;
   nsresult rv = GetWritableURI(getter_AddRefs(uri));
 
   if (uri) {
     rv = uri->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
     if (NS_SUCCEEDED(rv)) {
       SetURI(uri);
     }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsLocation::GetHostname(nsAString& aHostname)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   aHostname.Truncate();
 
   nsCOMPtr<nsIURI> uri;
   nsresult result;
 
   result = GetURI(getter_AddRefs(uri), true);
 
   if (uri) {
@@ -506,32 +521,38 @@ nsLocation::GetHostname(nsAString& aHost
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsLocation::SetHostname(const nsAString& aHostname)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsCOMPtr<nsIURI> uri;
   nsresult rv = GetWritableURI(getter_AddRefs(uri));
 
   if (uri) {
     rv = uri->SetHost(NS_ConvertUTF16toUTF8(aHostname));
     if (NS_SUCCEEDED(rv)) {
       SetURI(uri);
     }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsLocation::GetHref(nsAString& aHref)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   aHref.Truncate();
 
   nsCOMPtr<nsIURI> uri;
   nsresult result;
 
   result = GetURI(getter_AddRefs(uri));
 
   if (uri) {
@@ -654,16 +675,19 @@ nsLocation::SetHrefWithBase(const nsAStr
   }
 
   return result;
 }
 
 NS_IMETHODIMP
 nsLocation::GetPathname(nsAString& aPathname)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   aPathname.Truncate();
 
   nsCOMPtr<nsIURI> uri;
   nsresult result = NS_OK;
 
   result = GetURI(getter_AddRefs(uri));
 
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
@@ -678,32 +702,38 @@ nsLocation::GetPathname(nsAString& aPath
   }
 
   return result;
 }
 
 NS_IMETHODIMP
 nsLocation::SetPathname(const nsAString& aPathname)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsCOMPtr<nsIURI> uri;
   nsresult rv = GetWritableURI(getter_AddRefs(uri));
 
   if (uri) {
     rv = uri->SetPath(NS_ConvertUTF16toUTF8(aPathname));
     if (NS_SUCCEEDED(rv)) {
       SetURI(uri);
     }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsLocation::GetPort(nsAString& aPort)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   aPort.SetLength(0);
 
   nsCOMPtr<nsIURI> uri;
   nsresult result = NS_OK;
 
   result = GetURI(getter_AddRefs(uri), true);
 
   if (uri) {
@@ -721,16 +751,19 @@ nsLocation::GetPort(nsAString& aPort)
   }
 
   return result;
 }
 
 NS_IMETHODIMP
 nsLocation::SetPort(const nsAString& aPort)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsCOMPtr<nsIURI> uri;
   nsresult rv = GetWritableURI(getter_AddRefs(uri));
 
   if (uri) {
     // perhaps use nsReadingIterators at some point?
     NS_ConvertUTF16toUTF8 portStr(aPort);
     const char *buf = portStr.get();
     PRInt32 port = -1;
@@ -751,16 +784,19 @@ nsLocation::SetPort(const nsAString& aPo
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsLocation::GetProtocol(nsAString& aProtocol)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   aProtocol.SetLength(0);
 
   nsCOMPtr<nsIURI> uri;
   nsresult result = NS_OK;
 
   result = GetURI(getter_AddRefs(uri));
 
   if (uri) {
@@ -775,32 +811,38 @@ nsLocation::GetProtocol(nsAString& aProt
   }
 
   return result;
 }
 
 NS_IMETHODIMP
 nsLocation::SetProtocol(const nsAString& aProtocol)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsCOMPtr<nsIURI> uri;
   nsresult rv = GetWritableURI(getter_AddRefs(uri));
 
   if (uri) {
     rv = uri->SetScheme(NS_ConvertUTF16toUTF8(aProtocol));
     if (NS_SUCCEEDED(rv)) {
       SetURI(uri);
     }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsLocation::GetSearch(nsAString& aSearch)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   aSearch.SetLength(0);
 
   nsCOMPtr<nsIURI> uri;
   nsresult result = NS_OK;
 
   result = GetURI(getter_AddRefs(uri));
 
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
@@ -817,16 +859,19 @@ nsLocation::GetSearch(nsAString& aSearch
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsLocation::SetSearch(const nsAString& aSearch)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsCOMPtr<nsIURI> uri;
   nsresult rv = GetWritableURI(getter_AddRefs(uri));
 
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   if (url) {
     rv = url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
     if (NS_SUCCEEDED(rv)) {
       SetURI(uri);
@@ -834,16 +879,19 @@ nsLocation::SetSearch(const nsAString& a
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsLocation::Reload(bool aForceget)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsresult rv;
   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
   nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(docShell));
 
   if (window && window->IsHandlingResizeEvent()) {
     // location.reload() was called on a window that is handling a
     // resize event. Sites do this since Netscape 4.x needed it, but
@@ -914,16 +962,19 @@ nsLocation::Replace(const nsAString& aUr
   NS_ENSURE_SUCCESS(rv, rv);
 
   return SetHrefWithBase(aUrl, oldUri, true);
 }
 
 NS_IMETHODIMP
 nsLocation::Assign(const nsAString& aUrl)
 {
+  if (!CallerSubsumes())
+    return NS_ERROR_DOM_SECURITY_ERR;
+
   nsAutoString oldHref;
   nsresult result = NS_OK;
 
   result = GetHref(oldHref);
 
   if (NS_SUCCEEDED(result)) {
     nsCOMPtr<nsIURI> oldUri;
 
@@ -935,16 +986,17 @@ nsLocation::Assign(const nsAString& aUrl
   }
 
   return result;
 }
 
 NS_IMETHODIMP
 nsLocation::ToString(nsAString& aReturn)
 {
+  // NB: GetHref checks CallerSubsumes().
   return GetHref(aReturn);
 }
 
 nsresult
 nsLocation::GetSourceDocument(JSContext* cx, nsIDocument** aDocument)
 {
   // XXX Code duplicated from nsHTMLDocument
   // XXX Tom said this reminded him of the "Six Degrees of
@@ -984,8 +1036,22 @@ nsLocation::GetSourceBaseURL(JSContext* 
   if (doc) {
     *sourceURL = doc->GetBaseURI().get();
   } else {
     *sourceURL = nsnull;
   }
 
   return rv;
 }
+
+bool
+nsLocation::CallerSubsumes()
+{
+  // Get the principal associated with the location object.
+  nsCOMPtr<nsIDOMWindow> outer = do_QueryReferent(mOuter);
+  if (NS_UNLIKELY(!outer))
+    return false;
+  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(outer);
+  bool subsumes = false;
+  nsresult rv = nsContentUtils::GetSubjectPrincipal()->Subsumes(sop->GetPrincipal(), &subsumes);
+  NS_ENSURE_SUCCESS(rv, false);
+  return subsumes || nsContentUtils::IsCallerTrustedForCapability("UniversalXPConnect");
+}
--- a/dom/base/nsLocation.h
+++ b/dom/base/nsLocation.h
@@ -83,15 +83,17 @@ protected:
                            bool aReplace);
   nsresult SetHrefWithContext(JSContext* cx, const nsAString& aHref,
                               bool aReplace);
 
   nsresult GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL);
   nsresult GetSourceDocument(JSContext* cx, nsIDocument** aDocument);
 
   nsresult CheckURL(nsIURI *url, nsIDocShellLoadInfo** aLoadInfo);
+  bool CallerSubsumes();
 
   nsString mCachedHash;
   nsWeakPtr mDocShell;
+  nsWeakPtr mOuter;
 };
 
 #endif // nsLocation_h__
 
--- a/dom/tests/mochitest/storageevent/interOriginFrame.js
+++ b/dom/tests/mochitest/storageevent/interOriginFrame.js
@@ -1,11 +1,11 @@
 function postMsg(message)
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   var l = parent.window.location;
   parent.postMessage(message, l.protocol + "//" + l.host);
 }
 
 window.addEventListener("message", onMessageReceived, false);
 
 function onMessageReceived(event)
 {