Bug 949940 - Only enter the uncheckedObj compartment in a crossOriginGetter/Setter/Method around the UnwrapArg call that needs us to be in that compartment. r=peterv, a=lsblakk
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 17 Dec 2013 17:09:05 -0500
changeset 175416 62d366143e50f1e3c9053b2e6286e1c7a34d13ce
parent 175415 64770afb23135cf362dea699eb1a5afe815ec97a
child 175417 88a797bd34ded8998f8685b6aaf7400d50322093
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv, lsblakk
bugs949940
milestone28.0a2
Bug 949940 - Only enter the uncheckedObj compartment in a crossOriginGetter/Setter/Method around the UnwrapArg call that needs us to be in that compartment. r=peterv, a=lsblakk
dom/bindings/Codegen.py
dom/bindings/crashtests/949940.html
dom/bindings/crashtests/crashtests.list
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2611,36 +2611,55 @@ class CastableObjectUnwrapper():
     based on the passed-in descriptor and storing it in a variable
     called by the name in the "target" argument.
 
     codeOnFailure is the code to run if unwrapping fails.
 
     If isCallbackReturnValue is "JSImpl" and our descriptor is also
     JS-implemented, fall back to just creating the right object if what we
     have isn't one already.
+
+    If allowCrossOriginObj is True, then we'll first do an
+    UncheckedUnwrap and then operate on the result.
     """
     def __init__(self, descriptor, source, target, codeOnFailure,
-                 exceptionCode=None, isCallbackReturnValue=False):
+                 exceptionCode=None, isCallbackReturnValue=False,
+                 allowCrossOriginObj=False):
         if not exceptionCode:
             exceptionCode = codeOnFailure
         self.substitution = { "type" : descriptor.nativeType,
                               "protoID" : "prototypes::id::" + descriptor.name,
-                              "source" : source,
                               "target" : target,
                               "codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure)).define(),
                               "exceptionCode" : CGIndenter(CGGeneric(exceptionCode), 4).define() }
+        if allowCrossOriginObj:
+            self.substitution["uncheckedObjDecl"] = (
+                "\n  JS::Rooted<JSObject*> uncheckedObj(cx, js::UncheckedUnwrap(%s));" % source)
+            self.substitution["source"] = "uncheckedObj"
+            xpconnectUnwrap = (
+                "nsresult rv;\n"
+                "{ // Scope for the JSAutoCompartment, because we only\n"
+                "  // want to be in that compartment for the UnwrapArg call.\n"
+                "  JSAutoCompartment ac(cx, ${source});\n"
+                "  rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n"
+                "}\n")
+        else:
+            self.substitution["uncheckedObjDecl"] = ""
+            self.substitution["source"] = source
+            xpconnectUnwrap = "nsresult rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n"
+
         if descriptor.hasXPConnectImpls:
             # We don't use xpc_qsUnwrapThis because it will always throw on
             # unwrap failure, whereas we want to control whether we throw or
             # not.
             self.substitution["codeOnFailure"] = CGIndenter(CGGeneric(string.Template(
                 "${type} *objPtr;\n"
                 "SelfRef objRef;\n"
-                "JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*${source}));\n"
-                "nsresult rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n"
+                "JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*${source}));\n" +
+                xpconnectUnwrap +
                 "if (NS_FAILED(rv)) {\n"
                 "${codeOnFailure}\n"
                 "}\n"
                 "// We should be castable!\n"
                 "MOZ_ASSERT(!objRef.ptr);\n"
                 "// We should have an object, too!\n"
                 "MOZ_ASSERT(objPtr);\n"
                 "${target} = objPtr;").substitute(self.substitution)), 4).define()
@@ -2663,17 +2682,17 @@ class CastableObjectUnwrapper():
                 "}").substitute(self.substitution)), 4).define()
         else:
             self.substitution["codeOnFailure"] = CGIndenter(
                 CGGeneric(self.substitution["codeOnFailure"])).define()
 
     def __str__(self):
         codeOnFailure = self.substitution["codeOnFailure"] % {'securityError': 'rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO'}
         return string.Template(
-"""{
+"""{${uncheckedObjDecl}
   nsresult rv = UnwrapObject<${protoID}, ${type}>(${source}, ${target});
   if (NS_FAILED(rv)) {
 ${codeOnFailure}
   }
 }""").substitute(self.substitution, codeOnFailure=codeOnFailure)
 
 class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
     """
@@ -5731,28 +5750,21 @@ class CGAbstractBindingMethod(CGAbstract
         # know that we're the real deal.  So fake a descriptor here for
         # consumption by CastableObjectUnwrapper.
         getThis = CGList([
                 CGGeneric(self.callArgs) if self.callArgs != "" else None,
                 self.getThisObj,
                 CGGeneric("%s* self;" % self.descriptor.nativeType)
                 ], "\n")
 
-        objName = "uncheckedObj" if self.allowCrossOriginThis else "obj"
         unwrapThis = CGGeneric(
             str(CastableObjectUnwrapper(
                         self.descriptor,
-                        objName, "self", self.unwrapFailureCode)))
-        if self.allowCrossOriginThis:
-            unwrapThis = CGWrapper(
-                CGIndenter(unwrapThis),
-                pre=("{ // Scope for the uncheckedObj JSAutoCompartment\n"
-                     "  JS::Rooted<JSObject*> uncheckedObj(cx, js::UncheckedUnwrap(obj));\n"
-                     "  JSAutoCompartment ac(cx, uncheckedObj);\n"),
-                post="\n}")
+                        "obj", "self", self.unwrapFailureCode,
+                        allowCrossOriginObj=self.allowCrossOriginThis)))
         return CGList([ CGIndenter(getThis), CGIndenter(unwrapThis),
                         self.generate_code() ], "\n").define()
 
     def generate_code(self):
         assert(False) # Override me
 
 class CGAbstractStaticBindingMethod(CGAbstractStaticMethod):
     """
new file mode 100644
--- /dev/null
+++ b/dom/bindings/crashtests/949940.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+function boom()
+{
+  var frameWin =  document.getElementById("f").contentWindow;
+  Object.create(frameWin).self;
+}
+</script>
+</head>
+<body onload="boom()">
+<iframe id="f" src="data:text/html,3"></iframe>
+</body>
+</html>
--- a/dom/bindings/crashtests/crashtests.list
+++ b/dom/bindings/crashtests/crashtests.list
@@ -2,8 +2,9 @@ skip-if(1) load 769464.html # bug 823822
 load 822340-1.html
 load 822340-2.html
 load 832899.html
 load 860591.html
 load 860551.html
 load 862610.html
 load 862092.html
 load 869038.html
+load 949940.html