Bug 779821 - safe XHR creation for sandboxes
authorGabor Krizsanits <gkrizsanits@mozilla.com>
Wed, 15 Aug 2012 11:00:21 +0200
changeset 102634 d9092bbda533c110e6abe69defa50718c976db0c
parent 102633 fc8dc06d7592b3423f87eca745cbbb3093200094
child 102635 ea163112807db614628a87994b0ab6448fc278ab
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
bugs779821
milestone17.0a1
Bug 779821 - safe XHR creation for sandboxes
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/tests/unit/test_allowedDomainsXHR.js
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -28,16 +28,17 @@
 #include "jsfriendapi.h"
 #include "AccessCheck.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsPrincipal.h"
 #include "mozilla/Attributes.h"
 #include "nsIScriptContext.h"
 #include "nsJSEnvironment.h"
+#include "nsXMLHttpRequest.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace xpc;
 
 using mozilla::dom::DestroyProtoOrIfaceCache;
 
 /***************************************************************************/
@@ -2940,26 +2941,33 @@ SandboxImport(JSContext *cx, unsigned ar
 
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_SetPropertyById(cx, thisobj, id, &argv[0]);
 }
 
 static JSBool
 CreateXMLHttpRequest(JSContext *cx, unsigned argc, jsval *vp)
 {
+    nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+    if (!ssm)
+        return false;
+
+    nsIPrincipal *subjectPrincipal = ssm->GetCxSubjectPrincipal(cx);
+    if (!subjectPrincipal)
+        return false;
+
+    nsCOMPtr<nsIXMLHttpRequest> xhr = new nsXMLHttpRequest();
+    nsresult rv = xhr->Init(subjectPrincipal, NULL, NULL, NULL);
+    if (NS_FAILED(rv))
+        return false;
+
     JSObject *global = JS_GetGlobalForScopeChain(cx);
     MOZ_ASSERT(global);
 
-    nsCOMPtr<nsISupports> inst;
-    nsresult rv;
-    inst = do_CreateInstance("@mozilla.org/xmlextras/xmlhttprequest;1", &rv);
-    if (NS_FAILED(rv))
-        return false;
-
-    rv = nsContentUtils::WrapNative(cx, global, inst, vp);
+    rv = nsContentUtils::WrapNative(cx, global, xhr, vp);
     if (NS_FAILED(rv))
         return false;
 
     return true;
 }
 
 static JSBool
 sandbox_enumerate(JSContext *cx, JSHandleObject obj)
@@ -3628,17 +3636,17 @@ AssembleSandboxMemoryReporterName(JSCont
     xpc->GetCurrentJSStack(getter_AddRefs(frame));
 
     // Append the caller's location information.
     if (frame) {
         nsCString location;
         PRInt32 lineNumber = 0;
         frame->GetFilename(getter_Copies(location));
         frame->GetLineNumber(&lineNumber);
-        
+
         sandboxName.AppendLiteral(" (from: ");
         sandboxName.Append(location);
         sandboxName.AppendLiteral(":");
         sandboxName.AppendInt(lineNumber);
         sandboxName.AppendLiteral(")");
     }
 
     return NS_OK;
@@ -4429,17 +4437,17 @@ nsXPCComponents_Utils::SetGCZeal(PRInt32
 NS_IMETHODIMP
 nsXPCComponents_Utils::NukeSandbox(const JS::Value &obj, JSContext *cx)
 {
     NS_ENSURE_TRUE(obj.isObject(), NS_ERROR_INVALID_ARG);
     JSObject *wrapper = &obj.toObject();
     NS_ENSURE_TRUE(IsWrapper(wrapper), NS_ERROR_INVALID_ARG);
     JSObject *sb = UnwrapObject(wrapper);
     NS_ENSURE_TRUE(GetObjectJSClass(sb) == &SandboxClass, NS_ERROR_INVALID_ARG);
-    NukeCrossCompartmentWrappers(cx, AllCompartments(), 
+    NukeCrossCompartmentWrappers(cx, AllCompartments(),
                                  SingleCompartment(GetObjectCompartment(sb)),
                                  NukeWindowReferences);
     return NS_OK;
 }
 
 /***************************************************************************/
 /***************************************************************************/
 /***************************************************************************/
--- a/js/xpconnect/tests/unit/test_allowedDomainsXHR.js
+++ b/js/xpconnect/tests/unit/test_allowedDomainsXHR.js
@@ -1,24 +1,26 @@
 
 var cu = Components.utils;
 cu.import("resource://testing-common/httpd.js");
 
 var httpserver = new HttpServer();
+var httpserver2 = new HttpServer();
 var testpath = "/simple";
+var negativetestpath = "/negative";
 var httpbody = "<?xml version='1.0' ?><root>0123456789</root>";
 
 var sb = cu.Sandbox(["http://www.example.com",
                      "http://localhost:4444/simple"],
                      {wantXHRConstructor: true});
 
-function createXHR(async)
+function createXHR(loc, async)
 {
   var xhr = new XMLHttpRequest();
-  xhr.open("GET", "http://localhost:4444/simple", async);
+  xhr.open("GET", "http://localhost:" + loc, async);
   return xhr;
 }
 
 function checkResults(xhr)
 {
   if (xhr.readyState != 4)
     return false;
 
@@ -30,28 +32,41 @@ function checkResults(xhr)
   return true;
 }
 
 function run_test()
 {
   httpserver.registerPathHandler(testpath, serverHandler);
   httpserver.start(4444);
 
+  httpserver2.registerPathHandler(negativetestpath, serverHandler);
+  httpserver2.start(4445);
+
   // Test sync XHR sending
   cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
-  var res = cu.evalInSandbox('var sync = createXHR(); sync.send(null); sync', sb);
+  var res = cu.evalInSandbox('var sync = createXHR("4444/simple"); sync.send(null); sync', sb);
   checkResults(res);
 
   // Test async XHR sending
-  var async = cu.evalInSandbox('var async = createXHR(true); async', sb);
+  var async = cu.evalInSandbox('var async = createXHR("4444/simple", true); async', sb);
   async.addEventListener("readystatechange", function(event) {
     if (checkResults(async))
       httpserver.stop(do_test_finished);
   }, false);
   async.send(null);
+
+  // negative test sync XHR sending (to ensure that the xhr do not have chrome caps, see bug 779821)
+  try {
+    cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
+    var res = cu.evalInSandbox('var sync = createXHR("4445/negative"); sync.send(null); sync', sb);
+    do_check_false(true, "XHR created from sandbox should not have chrome caps");
+  } catch (e) {
+    do_check_true(true);
+  }
+  
   do_test_pending();
 }
 
 function serverHandler(metadata, response)
 {
   response.setHeader("Content-Type", "text/xml", false);
   response.bodyOutputStream.write(httpbody, httpbody.length);
 }