Bug 396851 - Check to see if we're UniversalXPConnect-enabled to allow privileged web pages to unwrap XOWs. r+sr=bzbarsky
authorBlake Kaplan <mrbkap@gmail.com>
Wed, 22 Oct 2008 13:15:22 -0700
changeset 20761 3b0909b12aa55805c74f9d34eb04bafb275f6e2a
parent 20760 6c4bb68efd2c5a393a70df76f5d1b56a46516c52
child 20762 b91e44d05452000bf1b0edaf246c8653c978455b
push idunknown
push userunknown
push dateunknown
bugs396851
milestone1.9.1b2pre
Bug 396851 - Check to see if we're UniversalXPConnect-enabled to allow privileged web pages to unwrap XOWs. r+sr=bzbarsky
caps/idl/nsIScriptSecurityManager.idl
caps/src/nsScriptSecurityManager.cpp
js/src/xpconnect/idl/nsIXPCSecurityManager.idl
js/src/xpconnect/shell/xpcshell.cpp
js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
js/src/xpconnect/tests/mochitest/Makefile.in
js/src/xpconnect/tests/mochitest/inner.html
js/src/xpconnect/tests/mochitest/test_bug396851.html
--- a/caps/idl/nsIScriptSecurityManager.idl
+++ b/caps/idl/nsIScriptSecurityManager.idl
@@ -45,17 +45,17 @@ interface nsIChannel;
  * WARNING!! The JEP needs to call GetSubjectPrincipal()
  * to support JavaScript-to-Java LiveConnect.  So every change to the
  * nsIScriptSecurityManager interface (big enough to change its IID) also
  * breaks JavaScript-to-Java LiveConnect on mac.
  *
  * If you REALLY have to change this interface, please mark your bug as
  * blocking bug 293973.
  */
-[scriptable, uuid(3fffd8e8-3fea-442e-a0ed-2ba81ae197d5)]
+[scriptable, uuid(f8e350b9-9f31-451a-8c8f-d10fea26b780)]
 interface nsIScriptSecurityManager : nsIXPCSecurityManager
 {
     ///////////////// Security Checks //////////////////
     /**
      * Checks whether the running script is allowed to access aProperty.
      */
     [noscript] void checkPropertyAccess(in JSContextPtr aJSContext,
                                         in JSObjectPtr aJSObject,
@@ -321,14 +321,16 @@ interface nsIScriptSecurityManager : nsI
 
     /**
      * Same as getSubjectPrincipal(), only faster. cx must *never* be
      * passed null, and it must be the context on the top of the
      * context stack. Does *not* reference count the returned
      * principal.
      */
     [noscript,notxpcom] nsIPrincipal getCxSubjectPrincipal(in JSContextPtr cx);
+    [noscript,notxpcom] nsIPrincipal getCxSubjectPrincipalAndFrame(in JSContextPtr cx,
+                                                                   out JSStackFramePtr fp);
 };
 
 %{C++
 #define NS_SCRIPTSECURITYMANAGER_CONTRACTID "@mozilla.org/scriptsecuritymanager;1"
 #define NS_SCRIPTSECURITYMANAGER_CLASSNAME "scriptsecuritymanager"
 %}
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -378,16 +378,30 @@ nsScriptSecurityManager::GetCxSubjectPri
     nsresult rv = NS_ERROR_FAILURE;
     nsIPrincipal *principal = GetSubjectPrincipal(cx, &rv);
     if (NS_FAILED(rv))
         return nsnull;
 
     return principal;
 }
 
+NS_IMETHODIMP_(nsIPrincipal *)
+nsScriptSecurityManager::GetCxSubjectPrincipalAndFrame(JSContext *cx, JSStackFrame **fp)
+{
+    NS_ASSERTION(cx == GetCurrentJSContext(),
+                 "Uh, cx is not the current JS context!");
+
+    nsresult rv = NS_ERROR_FAILURE;
+    nsIPrincipal *principal = GetPrincipalAndFrame(cx, fp, &rv);
+    if (NS_FAILED(rv))
+        return nsnull;
+
+    return principal;
+}
+
 ////////////////////
 // Policy Storage //
 ////////////////////
 
 // Table of security levels
 static PRBool
 DeleteCapability(nsHashKey *aKey, void *aData, void* closure)
 {
--- a/js/src/xpconnect/idl/nsIXPCSecurityManager.idl
+++ b/js/src/xpconnect/idl/nsIXPCSecurityManager.idl
@@ -48,16 +48,17 @@
 class nsAXPCNativeCallContext;
 %}
 
 interface nsIClassInfo;
 
 [ptr] native JSContextPtr(JSContext);
 [ptr] native JSObjectPtr(JSObject);
       native JSVal(jsval);
+[ptr] native JSStackFramePtr(JSStackFrame);
 
 [uuid(31431440-f1ce-11d2-985a-006008962422)]
 interface nsIXPCSecurityManager : nsISupports
 {
     /**
     * These flags are used when calling nsIXPConnect::SetSecurityManager
     */
 
--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -1236,16 +1236,23 @@ FullTrustSecMan::IsSystemPrincipal(nsIPr
 }
 
 NS_IMETHODIMP_(nsIPrincipal *)
 FullTrustSecMan::GetCxSubjectPrincipal(JSContext *cx)
 {
     return mSystemPrincipal;
 }
 
+NS_IMETHODIMP_(nsIPrincipal *)
+FullTrustSecMan::GetCxSubjectPrincipalAndFrame(JSContext *cx, JSStackFrame **fp)
+{
+    *fp = nsnull;
+    return mSystemPrincipal;
+}
+
 #endif
 
 /***************************************************************************/
 
 // #define TEST_InitClassesWithNewWrappedGlobal
 
 #ifdef TEST_InitClassesWithNewWrappedGlobal
 // XXX hacky test code...
--- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
+++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
@@ -261,17 +261,18 @@ CanAccessWrapper(JSContext *cx, JSObject
 {
   // Get the subject principal from the execution stack.
   nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
   if (!ssm) {
     ThrowException(NS_ERROR_NOT_INITIALIZED, cx);
     return NS_ERROR_NOT_INITIALIZED;
   }
 
-  nsIPrincipal *subjectPrin = ssm->GetCxSubjectPrincipal(cx);
+  JSStackFrame *fp = nsnull;
+  nsIPrincipal *subjectPrin = ssm->GetCxSubjectPrincipalAndFrame(cx, &fp);
 
   if (!subjectPrin) {
     ThrowException(NS_ERROR_FAILURE, cx);
     return NS_ERROR_FAILURE;
   }
 
   PRBool isSystem = PR_FALSE;
   nsresult rv = ssm->IsSystemPrincipal(subjectPrin, &isSystem);
@@ -280,16 +281,28 @@ CanAccessWrapper(JSContext *cx, JSObject
   // If we somehow end up being called from chrome, just allow full access.
   // This can happen from components with xpcnativewrappers=no.
   // Note that this is just an optimization to avoid getting the
   // object principal in this case, since Subsumes() would return true.
   if (isSystem) {
     return NS_OK;
   }
 
+  // There might be no code running, but if there is, we need to see if it is
+  // UniversalXPConnect enabled code.
+  if (fp) {
+    void *annotation = JS_GetFrameAnnotation(cx, fp);
+    rv = subjectPrin->IsCapabilityEnabled("UniversalXPConnect", annotation,
+                                          &isSystem);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (isSystem) {
+      return NS_OK;
+    }
+  }
+
   nsCOMPtr<nsIPrincipal> objectPrin;
   rv = ssm->GetObjectPrincipal(cx, wrappedObj, getter_AddRefs(objectPrin));
   if (NS_FAILED(rv)) {
     return rv;
   }
   NS_ASSERTION(objectPrin, "Object didn't have principals?");
 
   // Micro-optimization: don't call into caps if we know the answer.
--- a/js/src/xpconnect/tests/mochitest/Makefile.in
+++ b/js/src/xpconnect/tests/mochitest/Makefile.in
@@ -39,19 +39,21 @@ DEPTH		= ../../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = js/src/xpconnect/tests/mochitest
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
-_TEST_FILES =	test_bug361111.xul \
+_TEST_FILES =	inner.html \
+		test_bug361111.xul \
 		test_bug390488.html \
 		test_bug393269.html \
+		test_bug396851.html \
 		test_bug428021.html \
 		test_bug448587.html \
 		test_wrappers.html \
 		test_bug446584.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/js/src/xpconnect/tests/mochitest/inner.html
@@ -0,0 +1,7 @@
+<html>
+    <head>
+        <title>Inner frame for bug 39685 mochitest</title>
+    </head>
+    <body onload="x = 4">
+    </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/js/src/xpconnect/tests/mochitest/test_bug396851.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=396851
+-->
+<head>
+  <title>Test for Bug 396851</title>
+  <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript">
+  function go() {
+    var iframe = $("ifr");
+    var win = iframe.contentWindow;
+    try {
+      var doc = win.document;
+      fail("Allowed cross-origin access to the document");
+    } catch (e) {
+      ok(e.toString().match("Permission denied") != null, "Weird exception thrown");
+    }
+
+    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+    doc = win.document;
+    ok(doc != null, "Able to access the cross-origin document");
+    SimpleTest.finish();
+  }
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=396851">Mozilla Bug 396851</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<script type="text/javascript">
+    SimpleTest.waitForExplicitFinish();
+</script>
+<iframe id="ifr"
+        src="http://example.org/tests/js/src/xpconnect/tests/mochitest/inner.html"
+        onload="go()">
+</iframe>
+</body>
+</html>