Reviewers: kpreid2,

Description:
https://code.google.com/p/google-caja/issues/detail?id=1947 reports
that SES does not work on FF34. The reason is that FF now (at least
approximately) implements
https://bugs.ecmascript.org/show_bug.cgi?id=3113#c18 , where
Function.prototype has deletable .caller and .argument accessor
properties, but no other functions have these as own properties. In
this situation, the safest thing to do is just delete these from
Function.prototype, and thereafter not treat these names as special.

Please review this at https://codereview.appspot.com/188160043/

Affected files (+50, -5 lines):
  M     src/com/google/caja/ses/repairES5.js
  M     src/com/google/caja/ses/startSES.js


Index: src/com/google/caja/ses/repairES5.js
===================================================================
--- src/com/google/caja/ses/repairES5.js        (revision 5704)
+++ src/com/google/caja/ses/repairES5.js        (working copy)
@@ -31,6 +31,7 @@
  * //provides ses.ok, ses.okToLoad, ses.getMaxSeverity
  * //provides ses.is, ses.makeDelayedTamperProof
  * //provides ses.makeCallerHarmless, ses.makeArgumentsHarmless
+ * //provides ses.noFuncPoison
  * //provides ses.verifyStrictFunctionBody
  *
  * @author Mark S. Miller
@@ -179,6 +180,42 @@
   var builtInForEach = Array.prototype.forEach;

   /**
+   * At https://bugs.ecmascript.org/show_bug.cgi?id=3113#c24 Jason
+   * Orendorff states the best draft for a simpler safe spec for the
+   * .caller and .argument properties on functions, that may or may
+   * not make it into ES6, but is on a track to standardization
+   * regardless. In Firefox 34 and
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=969478 apparently
+   * this was implemented, or a reasonable approximation that we need
+   * to determine can be made SES-safe. Since this is a very different
+   * situation that the ES5 spec for these, we test which regime we
+   * seem to be in up front, so we can switch other logic based on this.
+   *
+   * If we seem to be in the new regime, then we try to delete the
+   * poison properties for simple safety, rather than trying to find
+   * subtle corner cases by which they might lose safety. If any of
+   * this fails, then we proceed under the assumption we're in the old
+   * regime.
+   *
+   * If noFuncPoison, then we're in the new regime made simply safe by
+   * these deletions, and we do not treat the names 'caller' and
+   * 'arguments' on functions as special.
+   */
+  var noFuncPoison =
+     Function.prototype.hasOwnProperty('caller') &&
+     Function.prototype.hasOwnProperty('arguments') &&
+     !strictFnSpecimen.hasOwnProperty('caller') &&
+     !strictFnSpecimen.hasOwnProperty('arguments') &&
+     !builtInMapMethod.hasOwnProperty('caller') &&
+     !builtInMapMethod.hasOwnProperty('arguments') &&
+     delete Function.prototype.caller &&
+     delete Function.prototype.arguments &&
+     !Function.prototype.hasOwnProperty('caller') &&
+     !Function.prototype.hasOwnProperty('arguments');
+  ses.noFuncPoison = noFuncPoison;
+
+
+  /**
    * http://wiki.ecmascript.org/doku.php?id=harmony:egal
    */
   var is = ses.is = Object.is || function(x, y) {
@@ -309,7 +346,7 @@
       if (typeof obj === 'function') {
         for (i = 0, j = 0; i < len; i++) {
           name = list[i];
-          if (name !== 'caller' && name !== 'arguments') {
+ if (noFuncPoison || (name !== 'caller' && name !== 'arguments')) {
             callback(name, j);
             j++;
           }
@@ -730,7 +767,8 @@
    * The function own property names that funcLike doesn't copy
    * in a generic manner from newFunc to the returned standin.
    */
-  var exemptFuncProps = ['name', 'length', 'caller', 'arguments'];
+  var exemptFuncProps = noFuncPoison ? ['name', 'length'] :
+     ['name', 'length', 'caller', 'arguments'];

   /**
    * Given that newFunc represents a desired emulation of oldFunc
@@ -1586,6 +1624,7 @@
       // Seen in IE9. Harmless by itself
       return false;
     }
+    if (desc === void 0 && noFuncPoison) { return false; }
     return 'getOwnPropertyDesciptor returned unexpected caller descriptor';
   }

@@ -1607,6 +1646,7 @@
       return 'hasOwnProperty failed with: ' + err;
     }
     if (answer) { return false; }
+    if (noFuncPoison) { return false; }
     return 'strict_function.hasOwnProperty("caller") was false';
   }

@@ -1701,6 +1741,7 @@
       return '("caller" in strict_func) failed with: ' + err;
     } finally {}
     if (answer) { return false; }
+    if (noFuncPoison) { return false; }
     return '("caller" in strict_func) was false.';
   }

@@ -1722,6 +1763,7 @@
       return '("arguments" in strict_func) failed with: ' + err;
     } finally {}
     if (answer) { return false; }
+    if (noFuncPoison) { return false; }
     return '("arguments" in strict_func) was false.';
   }

@@ -1746,6 +1788,7 @@
       // Seen on IE 9
       return true;
     }
+    if (caller === void 0 && noFuncPoison) { return false; }
     return 'Unexpected "caller": ' + caller;
   }

@@ -1770,6 +1813,7 @@
       // Seen on IE 9
       return true;
     }
+    if (args === void 0 && noFuncPoison) { return false; }
     return 'Unexpected arguments: ' + arguments;
   }

@@ -2639,7 +2683,7 @@
   }

   function getThrowTypeError() {
- return Object.getOwnPropertyDescriptor(getThrowTypeError, 'arguments').get;
+    return Object.getOwnPropertyDescriptor(arguments, 'caller').get;
   }

   /**
Index: src/com/google/caja/ses/startSES.js
===================================================================
--- src/com/google/caja/ses/startSES.js (revision 5704)
+++ src/com/google/caja/ses/startSES.js (working copy)
@@ -19,6 +19,7 @@
  * WeakMap spec. Compatible with ES5-strict or anticipated ES6.
  *
  * //requires ses.makeCallerHarmless, ses.makeArgumentsHarmless
+ * //requires ses.noFuncPoison
  * //requires ses.verifyStrictFunctionBody
  * //optionally requires ses.mitigateSrcGotchas
  * //provides ses.startSES ses.resolveOptions, ses.securableWrapperSrc
@@ -371,7 +372,7 @@
    * Obtain the ES5 singleton [[ThrowTypeError]].
    */
   function getThrowTypeError() {
-    return gopd(getThrowTypeError, "arguments").get;
+    return gopd(arguments, 'caller').get;
   }


@@ -1539,7 +1540,7 @@
     }
     var diagnostic;

-    if (typeof base === 'function') {
+    if (typeof base === 'function' && !ses.noFuncPoison) {
       if (name === 'caller') {
         diagnostic = ses.makeCallerHarmless(base, path);
         // We can use a severity of SAFE here since if this isn't


--

--- You received this message because you are subscribed to the Google Groups "Google Caja Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to