Bug 1290966 - Permit introspection into arguments; r?automatedtester draft
authorAndreas Tolfsen <ato@mozilla.com>
Tue, 02 Aug 2016 14:50:59 +0100
changeset 396823 54c34df1702c71cee21bce6d2dc67dbbee3e6959
parent 396804 0ba72e8027cfcbcbf3426770ac264a7ade2af090
child 396824 e5b5df1b2519b3d876368c00727990a3b966c9a1
push id25122
push userbmo:ato@mozilla.com
push dateThu, 04 Aug 2016 17:29:53 +0000
reviewersautomatedtester
bugs1290966
milestone51.0a1
Bug 1290966 - Permit introspection into arguments; r?automatedtester The callback function available to asynchronously evaluated scripts is defined in a privileged content frame script, and is thus not readable or introspectable in a sandboxed content script. Attempting this will yield a "Permission denied to access property" error. To circumvent this problem we "hide" the callback function by wrapping it before pushing it on the arguments object that is applied to the injected script. This allows introspection into the _immediate_ elements on the arguments object available to executed scripts. MozReview-Commit-ID: 9ZigPNYcYpf
testing/marionette/evaluate.js
testing/marionette/harness/marionette/tests/unit/test_execute_async_script.py
--- a/testing/marionette/evaluate.js
+++ b/testing/marionette/evaluate.js
@@ -107,17 +107,20 @@ evaluate.sandbox = function(sb, script, 
     unloadHandler = () => reject(
         new JavaScriptError("Document was unloaded during execution"));
 
     // wrap in function
     if (!opts.directInject) {
       sb[CALLBACK] = sb[COMPLETE];
       sb[ARGUMENTS] = Cu.cloneInto(args, sb, {wrapReflectors: true});
 
-      script = `${ARGUMENTS}.push(${CALLBACK});` +
+      // callback function made private
+      // so that introspection is possible
+      // on the arguments object
+      script = `${ARGUMENTS}.push(rv => ${CALLBACK}(rv));` +
           `(function() { ${script} }).apply(null, ${ARGUMENTS})`;
 
       // marionetteScriptFinished is not WebDriver conformant,
       // hence it is only exposed to immutable sandboxes
       if (opts.sandboxName) {
         sb[MARIONETTE_SCRIPT_FINISHED] = sb[CALLBACK];
       }
     }
--- a/testing/marionette/harness/marionette/tests/unit/test_execute_async_script.py
+++ b/testing/marionette/harness/marionette/tests/unit/test_execute_async_script.py
@@ -106,16 +106,29 @@ marionetteScriptFinished(4);
 
         self.marionette.execute_async_script("global.barfoo = [arguments[0], arguments[1]];"
                                              "marionetteScriptFinished()",
                                              script_args=[42, 23], new_sandbox=False)
         self.assertEqual(self.marionette.execute_async_script(
             "marionetteScriptFinished(global.barfoo);", new_sandbox=False),
                          [42, 23])
 
+    # Functions defined in higher privilege scopes, such as the privileged
+    # content frame script listener.js runs in, cannot be accessed from
+    # content.  This tests that it is possible to introspect the objects on
+    # `arguments` without getting permission defined errors.  This is made
+    # possible because the last argument is always the callback/complete
+    # function.
+    #
+    # See bug 1290966.
+    def test_introspection_of_arguments(self):
+        self.marionette.execute_async_script(
+            "arguments[0].cheese; __webDriverCallback();",
+            script_args=[], sandbox=None)
+
 
 class TestExecuteAsyncChrome(TestExecuteAsyncContent):
     def setUp(self):
         super(TestExecuteAsyncChrome, self).setUp()
         self.marionette.set_context("chrome")
 
     def test_execute_async_unload(self):
         pass