LEFT | RIGHT |
1 // Copyright (C) 2011 Google Inc. | 1 // Copyright (C) 2011 Google Inc. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // https://www.apache.org/licenses/LICENSE-2.0 | 7 // https://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 * A known sloppy function which returns its arguments object. | 628 * A known sloppy function which returns its arguments object. |
629 * | 629 * |
630 * Defined using Function so it'll be sloppy (not strict and not | 630 * Defined using Function so it'll be sloppy (not strict and not |
631 * builtin). | 631 * builtin). |
632 */ | 632 */ |
633 var sloppyArguments = Function('return arguments;'); | 633 var sloppyArguments = Function('return arguments;'); |
634 | 634 |
635 /** | 635 /** |
636 * If present, a known strict generator function which yields its | 636 * If present, a known strict generator function which yields its |
637 * arguments object. | 637 * arguments object. |
| 638 * |
| 639 * <p>TODO: once all supported browsers implement ES6 generators, we |
| 640 * can drop the "try"s below, drop the check for old Mozilla |
| 641 * generator syntax, and treat strictArgumentsGenerator as |
| 642 * unconditional in the test of the code. |
638 */ | 643 */ |
639 var strictArgumentsGenerator = void 0; | 644 var strictArgumentsGenerator = void 0; |
640 try { | 645 try { |
641 // ES6 syntax | 646 // ES6 syntax |
642 strictArgumentsGenerator = | 647 strictArgumentsGenerator = |
643 eval('(function*() { "use strict"; yield arguments; })'); | 648 eval('(function*() { "use strict"; yield arguments; })'); |
644 } catch (_) { | 649 } catch (ex) { |
| 650 if (!(ex instanceof SyntaxError)) { throw ex; } |
645 try { | 651 try { |
646 // Old Firefox syntax | 652 // Old Firefox syntax |
647 strictArgumentsGenerator = | 653 strictArgumentsGenerator = |
648 eval('(function() { "use strict"; yield arguments; })'); | 654 eval('(function() { "use strict"; yield arguments; })'); |
649 } catch (_2) { | 655 } catch (ex2) { |
650 // ignore | 656 if (!(ex2 instanceof SyntaxError)) { throw ex2; } |
651 } | 657 } |
652 } | 658 } |
653 | 659 |
654 | 660 /** |
655 /** | 661 * The undeniables are the primordial objects which are ambiently |
656 * The undeniable are the primordial objects are ambiently reachable | 662 * reachable via compositions of strict syntax, primitive wrapping |
657 * via compositions of strict syntax, primitive wrapping (new | 663 * (new Object(x)), and prototype navigation (the equivalent of |
658 * Object(x)), and prototype navigation (the equivalent of | |
659 * Object.getPrototypeOf(x) or x.__proto__). Although we could in | 664 * Object.getPrototypeOf(x) or x.__proto__). Although we could in |
660 * theory monkey patch primitive wrapping or prototype navigation, | 665 * theory monkey patch primitive wrapping or prototype navigation, |
661 * we won't. Hence, without parsing, the following are undeniable no | 666 * we won't. Hence, without parsing, the following are undeniable no |
662 * matter what <i>other</i> monkey patching we do to the primordial | 667 * matter what <i>other</i> monkey patching we do to the primordial |
663 * environment. | 668 * environment. |
664 */ | 669 */ |
665 function getUndeniables() { | 670 function getUndeniables() { |
666 var gopd = Object.getOwnPropertyDescriptor; | 671 var gopd = Object.getOwnPropertyDescriptor; |
667 var getProto = Object.getPrototypeOf; | 672 var getProto = Object.getPrototypeOf; |
| 673 |
| 674 // The first element of each undeniableTuple is a string used to |
| 675 // name the undeniable object for reporting purposes. It has no |
| 676 // other programmatic use. |
| 677 // |
| 678 // The second element of each undeniableTuple should be the |
| 679 // undeniable itself. |
| 680 // |
| 681 // The optional third element of the undeniableTuple, if present, |
| 682 // should be an example of syntax, rather than use of a monkey |
| 683 // patchable API, evaluating to a value from which the undeniable |
| 684 // object in the second element can be reached by only the |
| 685 // following steps: |
| 686 // If the value is primitve, convert to an Object wrapper. |
| 687 // Is the resulting object either the undeniable object, or does |
| 688 // it inherit directly from the undeniable object? |
668 | 689 |
669 var undeniableTuples = [ | 690 var undeniableTuples = [ |
670 ['Object.prototype', Object.prototype, {}], | 691 ['Object.prototype', Object.prototype, {}], |
671 ['Function.prototype', Function.prototype, function(){}], | 692 ['Function.prototype', Function.prototype, function(){}], |
672 ['Array.prototype', Array.prototype, []], | 693 ['Array.prototype', Array.prototype, []], |
673 ['RegExp.prototype', RegExp.prototype, /x/], | 694 ['RegExp.prototype', RegExp.prototype, /x/], |
674 ['Boolean.prototype', Boolean.prototype, true], | 695 ['Boolean.prototype', Boolean.prototype, true], |
675 ['Number.prototype', Number.prototype, 1], | 696 ['Number.prototype', Number.prototype, 1], |
676 ['String.prototype', String.prototype, 'x'], | 697 ['String.prototype', String.prototype, 'x'], |
677 ]; | 698 ]; |
678 var result = {}; | 699 var result = {}; |
679 | 700 |
680 // Get the ES6 %Generator% intrinsic, if present. | 701 // Get the ES6 %Generator% intrinsic, if present. |
681 // It is undeniable because individual generator functions inherit | 702 // It is undeniable because individual generator functions inherit |
682 // from it. | 703 // from it. |
683 (function() { | 704 (function() { |
684 // See http://people.mozilla.org/~jorendorff/figure-2.png | 705 // See http://people.mozilla.org/~jorendorff/figure-2.png |
| 706 // i.e., Figure 2 of section 25.2 "Generator Functions" of the |
| 707 // ES6 spec. |
| 708 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorfunc
tion-objects |
685 if (!strictArgumentsGenerator) { return; } | 709 if (!strictArgumentsGenerator) { return; } |
686 var Generator = getProto(strictArgumentsGenerator); | 710 var Generator = getProto(strictArgumentsGenerator); |
687 undeniableTuples.push(['%Generator%', Generator, | 711 undeniableTuples.push(['%Generator%', Generator, |
688 strictArgumentsGenerator]); | 712 strictArgumentsGenerator]); |
689 strictArgumentsGenerator = strictArgumentsGenerator; | 713 strictArgumentsGenerator = strictArgumentsGenerator; |
690 }()); | 714 }()); |
691 | 715 |
692 strictForEachFn(undeniableTuples, function(tuple) { | 716 strictForEachFn(undeniableTuples, function(tuple) { |
693 var name = tuple[0]; | 717 var name = tuple[0]; |
694 var undeniable = tuple[1]; | 718 var undeniable = tuple[1]; |
695 var start = tuple[2]; | 719 var start = tuple[2]; |
696 result[name] = undeniable; | 720 result[name] = undeniable; |
697 if (start === void 0) { return; } | 721 if (start === void 0) { return; } |
698 start = Object(start); | 722 start = Object(start); |
699 if (undeniable === start) { return; } | 723 if (undeniable === start) { return; } |
700 if (undeniable === getProto(start)) { return; } | 724 if (undeniable === getProto(start)) { return; } |
701 throw new Error('Unexpected undeniable: ' + undeniable); | 725 throw new Error('Unexpected undeniable: ' + undeniable); |
702 }); | 726 }); |
703 | 727 |
704 return result; | 728 return result; |
705 } | 729 } |
706 ses.getUndeniables = getUndeniables; | 730 ses.getUndeniables = getUndeniables; |
707 | 731 |
708 // For consistency checking, once we've done all our whitelist | 732 // For consistency checking, once we've done all our whitelist |
709 // processing and monkey patching, we call getUndeniables again and | 733 // processing and monkey patching, we will call getUndeniables again |
710 // check that the undeniables are the same. | 734 // and check that the undeniables are the same. |
711 ses.earlyUndeniables = getUndeniables(); | 735 ses.earlyUndeniables = getUndeniables(); |
712 | 736 |
713 | 737 |
714 /** | 738 /** |
715 * Get the intrinsics not otherwise reachable by named own property | 739 * Get the intrinsics not otherwise reachable by named own property |
716 * traversal. See | 740 * traversal. See |
717 * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-well-known-intrin
sic-objects | 741 * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-well-known-intrin
sic-objects |
718 * and the instrinsics section of whitelist.js | 742 * and the instrinsics section of whitelist.js |
719 * | 743 * |
720 * <p>Unlike getUndeniables(), the result of getAnonIntrinsics() | 744 * <p>Unlike getUndeniables(), the result of getAnonIntrinsics() |
721 * does depend on the current state of the primordials, so we must | 745 * does depend on the current state of the primordials, so we must |
722 * run this again after all other relevant monkey patching is done, | 746 * run this again after all other relevant monkey patching is done, |
723 * in order to properly initialize cajaVM.intrinsics | 747 * in order to properly initialize cajaVM.intrinsics |
724 */ | 748 */ |
725 function getAnonIntrinsics() { | 749 function getAnonIntrinsics() { |
726 var gopd = Object.getOwnPropertyDescriptor; | 750 var gopd = Object.getOwnPropertyDescriptor; |
727 var getProto = Object.getPrototypeOf; | 751 var getProto = Object.getPrototypeOf; |
728 var result = {}; | 752 var result = {}; |
729 | 753 |
730 // If there are still other ThrowTypeError objects left after | 754 // If there are still other ThrowTypeError objects left after |
731 // noFuncPoison-ing, this should be caught by | 755 // noFuncPoison-ing, this should be caught by |
732 // test_THROWTYPEERROR_NOT_UNIQUE below, so we assume here that | 756 // test_THROWTYPEERROR_NOT_UNIQUE below, so we assume here that |
733 // this is the only surviving ThrowTypeError intrinsic. | 757 // this is the only surviving ThrowTypeError intrinsic. |
734 result.ThrowTypeError = gopd(arguments, 'caller').get; | 758 result.ThrowTypeError = gopd(arguments, 'caller').get; |
735 | 759 |
736 // Get the ES6 %ArrayIteratorPrototype%, %StringIteratorPrototype%, | 760 // Get the ES6 %ArrayIteratorPrototype%, %StringIteratorPrototype%, |
737 // and %IteratorPrototype% intrinsics, if present. | 761 // and %IteratorPrototype% intrinsics, if present. |
738 // TODO %MapIteratorPrototype% | 762 |
739 // TODO %SetIteratorPrototype% | 763 // TODO %MapIteratorPrototype%, %SetIteratorPrototype% |
| 764 // It is currently safe to omit %MapIteratorPrototype% and |
| 765 // %SetIteratorPrototype% since we do not yet whitelist Map and |
| 766 // Set. |
740 (function() { | 767 (function() { |
741 var iteratorSym = global.Symbol && global.Symbol.iterator || | 768 var iteratorSym = global.Symbol && global.Symbol.iterator || |
742 "@@iterator"; // used instead of a symbol on FF35 | 769 "@@iterator"; // used instead of a symbol on FF35 |
743 if ([][iteratorSym] === void 0) { return; } | 770 if ([][iteratorSym]) { |
744 var arrayIter = [][iteratorSym](); | 771 var arrayIter = [][iteratorSym](); |
745 var ArrayIteratorPrototype = getProto(arrayIter); | 772 var ArrayIteratorPrototype = getProto(arrayIter); |
746 result.ArrayIteratorPrototype = ArrayIteratorPrototype; | 773 result.ArrayIteratorPrototype = ArrayIteratorPrototype; |
747 var IteratorPrototype = getProto(ArrayIteratorPrototype); | 774 var arrayIterProtoBase = getProto(ArrayIteratorPrototype); |
748 if (IteratorPrototype !== Object.prototype) { | 775 if (arrayIterProtoBase !== Object.prototype) { |
749 if (getProto(IteratorPrototype) !== Object.prototype) { | 776 if (getProto(arrayIterProtoBase) !== Object.prototype) { |
750 throw new Error( | 777 throw new Error( |
751 '%IteratorPrototype%.__proto__ was not Object.prototype'); | 778 '%IteratorPrototype%.__proto__ was not Object.prototype'); |
| 779 } |
| 780 result.IteratorPrototype = arrayIterProtoBase; |
752 } | 781 } |
753 result.IteratorPrototype = IteratorPrototype; | 782 } |
754 } | 783 if (''[iteratorSym]) { |
755 if (''[iteratorSym] === void 0) { return; } | 784 var stringIter = ''[iteratorSym](); |
756 var stringIter = ''[iteratorSym](); | 785 var StringIteratorPrototype = getProto(stringIter); |
757 var StringIteratorPrototype = getProto(stringIter); | 786 result.StringIteratorPrototype = StringIteratorPrototype; |
758 result.StringIteratorPrototype = StringIteratorPrototype; | 787 var stringIterProtoBase = getProto(StringIteratorPrototype); |
759 var stringIterProtoBase = getProto(StringIteratorPrototype); | 788 if (stringIterProtoBase !== Object.prototype) { |
760 if (stringIterProtoBase !== IteratorPrototype && | 789 if (!result.IteratorPrototype) { |
761 stringIterProtoBase !== Object.prototype) { | 790 if (getProto(stringIterProtoBase) !== Object.prototype) { |
762 throw new Error('unexpected %StringIteratorPrototype%.__proto__'); | 791 throw new Error( |
| 792 '%IteratorPrototype%.__proto__ was not Object.prototype'); |
| 793 } |
| 794 result.IteratorPrototype = stringIterProtoBase; |
| 795 } else { |
| 796 if (result.IteratorPrototype !== stringIterProtoBase) { |
| 797 throw new Error('unexpected %StringIteratorPrototype%.__proto__'); |
| 798 } |
| 799 } |
| 800 } |
763 } | 801 } |
764 }()); | 802 }()); |
765 | 803 |
766 // Get the ES6 %GeneratorFunction% intrinsic, if present. | 804 // Get the ES6 %GeneratorFunction% intrinsic, if present. |
767 (function() { | 805 (function() { |
768 var Generator = ses.earlyUndeniables['%Generator%']; | 806 var Generator = ses.earlyUndeniables['%Generator%']; |
769 if (!Generator || Generator === Function.prototype) { return; } | 807 if (!Generator || Generator === Function.prototype) { return; } |
770 if (getProto(Generator) !== Function.prototype) { | 808 if (getProto(Generator) !== Function.prototype) { |
771 throw new Error('Generator.__proto__ was not Function.prototype'); | 809 throw new Error('Generator.__proto__ was not Function.prototype'); |
772 } | 810 } |
(...skipping 16 matching lines...) Expand all Loading... |
789 var TypedArray = getProto(global.Float32Array); | 827 var TypedArray = getProto(global.Float32Array); |
790 if (TypedArray === Function.prototype) { return; } | 828 if (TypedArray === Function.prototype) { return; } |
791 if (getProto(TypedArray) !== Function.prototype) { | 829 if (getProto(TypedArray) !== Function.prototype) { |
792 // http://bespin.cz/~ondras/html/classv8_1_1ArrayBufferView.html | 830 // http://bespin.cz/~ondras/html/classv8_1_1ArrayBufferView.html |
793 // has me worried that someone might make such an intermediate | 831 // has me worried that someone might make such an intermediate |
794 // object visible. | 832 // object visible. |
795 throw new Error('TypedArray.__proto__ was not Function.prototype'); | 833 throw new Error('TypedArray.__proto__ was not Function.prototype'); |
796 } | 834 } |
797 result.TypedArray = TypedArray; | 835 result.TypedArray = TypedArray; |
798 }()); | 836 }()); |
| 837 |
| 838 for (var name in result) { |
| 839 if (result[name] === void 0) { |
| 840 throw new Error('Malformed intrinsic: ' + name); |
| 841 } |
| 842 } |
799 | 843 |
800 return result; | 844 return result; |
801 } | 845 } |
802 ses.getAnonIntrinsics = getAnonIntrinsics; | 846 ses.getAnonIntrinsics = getAnonIntrinsics; |
803 | 847 |
804 var unsafeIntrinsics = getAnonIntrinsics(); | 848 var unsafeIntrinsics = getAnonIntrinsics(); |
805 | 849 |
806 | 850 |
807 ////////////////////////////////////////////////////////// | 851 ////////////////////////////////////////////////////////// |
808 | 852 |
(...skipping 2243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3052 /** | 3096 /** |
3053 * %ThrowTypeError% is not unique (even after whatever cleanup was | 3097 * %ThrowTypeError% is not unique (even after whatever cleanup was |
3054 * already done during the noFuncPoison testing above). | 3098 * already done during the noFuncPoison testing above). |
3055 */ | 3099 */ |
3056 function test_THROWTYPEERROR_NOT_UNIQUE() { | 3100 function test_THROWTYPEERROR_NOT_UNIQUE() { |
3057 var tte = unsafeIntrinsics.ThrowTypeError; | 3101 var tte = unsafeIntrinsics.ThrowTypeError; |
3058 if (typeof tte !== 'function') { | 3102 if (typeof tte !== 'function') { |
3059 return 'Unexpected %ThrowTypeError%: ' + tte; | 3103 return 'Unexpected %ThrowTypeError%: ' + tte; |
3060 } | 3104 } |
3061 var others = []; | 3105 var others = []; |
3062 var triples = [ | 3106 var sourcesOfTTE = [ |
3063 [Function.prototype, 'Function.prototype', ['caller', 'arguments']], | 3107 [Function.prototype, 'Function.prototype', ['caller', 'arguments']], |
3064 [builtInMapMethod, 'builtin function', ['caller', 'arguments']], | 3108 [builtInMapMethod, 'builtin function', ['caller', 'arguments']], |
3065 [strictArguments, 'strict function', ['caller', 'arguments']], | 3109 [strictArguments, 'strict function', ['caller', 'arguments']], |
3066 [sloppyArguments, 'sloppy function', ['caller', 'arguments']], | 3110 [sloppyArguments, 'sloppy function', ['caller', 'arguments']], |
3067 [strictArguments(), 'strict arguments', ['caller', 'callee']], | 3111 [strictArguments(), 'strict arguments', ['caller', 'callee']], |
3068 [sloppyArguments(), 'sloppy arguments', ['caller', 'callee']] | 3112 [sloppyArguments(), 'sloppy arguments', ['caller', 'callee']] |
3069 ]; | 3113 ]; |
3070 if (strictArgumentsGenerator) { | 3114 if (strictArgumentsGenerator) { |
3071 var strictGeneratedArgs = strictArgumentsGenerator().next().value; | 3115 var strictGeneratedArgs = strictArgumentsGenerator().next().value; |
3072 triples.push( | 3116 sourcesOfTTE.push( |
3073 [strictArgumentsGenerator, 'strict generator', ['caller', 'arguments']], | 3117 [strictArgumentsGenerator, 'strict generator', ['caller', 'arguments']], |
3074 [strictGeneratedArgs, 'strict generated arguments', | 3118 [strictGeneratedArgs, 'strict generated arguments', |
3075 ['caller', 'callee']]); | 3119 ['caller', 'callee']]); |
3076 } | 3120 } |
3077 var Generator = ses.earlyUndeniables['%Generator%']; | 3121 var Generator = ses.earlyUndeniables['%Generator%']; |
3078 if (Generator) { | 3122 if (Generator) { |
3079 triples.push([Generator, '%Generator%', ['caller', 'arguments']]); | 3123 sourcesOfTTE.push([Generator, '%Generator%', ['caller', 'arguments']]); |
3080 } | 3124 } |
3081 var GeneratorFunction = unsafeIntrinsics.GeneratorFunction; | 3125 var GeneratorFunction = unsafeIntrinsics.GeneratorFunction; |
3082 if (GeneratorFunction) { | 3126 if (GeneratorFunction) { |
3083 triples.push([GeneratorFunction, '%GeneratorFunction%', | 3127 sourcesOfTTE.push([GeneratorFunction, '%GeneratorFunction%', |
3084 ['caller', 'arguments']]); | 3128 ['caller', 'arguments']]); |
3085 } | 3129 } |
3086 | 3130 |
3087 strictForEachFn(triples, function(triple) { | 3131 strictForEachFn(sourcesOfTTE, function(sourceOfTTE) { |
3088 var base = triple[0]; | 3132 var base = sourceOfTTE[0]; |
3089 var where = triple[1]; | 3133 var where = sourceOfTTE[1]; |
3090 var names = triple[2]; | 3134 var names = sourceOfTTE[2]; |
3091 strictForEachFn(names, function(name) { | 3135 strictForEachFn(names, function(name) { |
3092 var desc = Object.getOwnPropertyDescriptor(base, name); | 3136 var desc = Object.getOwnPropertyDescriptor(base, name); |
3093 if (!desc) { return; } | 3137 if (!desc) { return; } |
3094 strictForEachFn(['get', 'set'], function (attr) { | 3138 strictForEachFn(['get', 'set'], function (attr) { |
3095 var otherTTE = desc[attr]; | 3139 var otherTTE = desc[attr]; |
3096 if (!otherTTE || otherTTE === tte) { return; } | 3140 if (!otherTTE || otherTTE === tte) { return; } |
3097 others.push(where + ' ' + attr + ' ' + name); | 3141 others.push(where + ' ' + attr + ' ' + name); |
3098 }); | 3142 }); |
3099 }); | 3143 }); |
3100 }); | 3144 }); |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3369 return true; | 3413 return true; |
3370 } else { | 3414 } else { |
3371 return 'Unexpected prototype identity from setting a function\'s ' + | 3415 return 'Unexpected prototype identity from setting a function\'s ' + |
3372 'prototype with defineProperty.'; | 3416 'prototype with defineProperty.'; |
3373 } | 3417 } |
3374 } else { | 3418 } else { |
3375 return 'Unexpected result of setting a function\'s prototype ' + | 3419 return 'Unexpected result of setting a function\'s prototype ' + |
3376 'with defineProperty: ' + typeof bar.prototype; | 3420 'with defineProperty: ' + typeof bar.prototype; |
3377 } | 3421 } |
3378 } | 3422 } |
| 3423 |
| 3424 /** |
| 3425 * In ES6, the constructor property of the %Generator% intrinsic |
| 3426 * initially points at the unsafe %GeneratorFunction% intrinsic. This |
| 3427 * property is supposed to have attributes |
| 3428 * { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true } |
| 3429 * Prior to 2/19/2015, on v8 it had attributes |
| 3430 * { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false } |
| 3431 * making it impossible to change the property's value. |
| 3432 * |
| 3433 * <p>Since the original %GeneratorFunction% intrinsic, like the |
| 3434 * global Function constructor, accepts a function body which it |
| 3435 * executes in the global scope, it would be reachable by any |
| 3436 * generator. Without parsing, we would not be able to prevent |
| 3437 * the following expression |
| 3438 * <pre> |
| 3439 * (function*(){}).constructor('yield window;')().next().value |
| 3440 * </pre> |
| 3441 * from providing the genuine global window object of that realm. |
| 3442 */ |
| 3443 function test_GENERATORFUNCTION_CANNOT_BE_DENIED() { |
| 3444 var gopd = Object.getOwnPropertyDescriptor; |
| 3445 var getProto = Object.getPrototypeOf; |
| 3446 |
| 3447 var UnsafeGeneratorFunction = unsafeIntrinsics.GeneratorFunction; |
| 3448 if (!UnsafeGeneratorFunction) { return false; } |
| 3449 var Generator = ses.earlyUndeniables['%Generator%']; |
| 3450 if (!(Generator && |
| 3451 Generator.constructor === UnsafeGeneratorFunction && |
| 3452 UnsafeGeneratorFunction.prototype === Generator && |
| 3453 getProto(UnsafeGeneratorFunction) === UnsafeFunction && |
| 3454 getProto(Generator) === Function.prototype)) { |
| 3455 return 'Unexpected primordial Generator arrangement'; |
| 3456 } |
| 3457 var desc = gopd(Generator, 'constructor'); |
| 3458 return desc.writable === false && desc.configurable === false; |
| 3459 } |
| 3460 |
| 3461 /** |
| 3462 * ES6 introduces a new "import" special form syntax, which imports |
| 3463 * access to modules that we cannot currently control. Therefore, if |
| 3464 * we cannot prevent use of the "import" syntax, we lose |
| 3465 * isolation. Fortunately, the "import" syntax can only legally |
| 3466 * occur with modules, not within the text that the original eval, |
| 3467 * Function, or %GeneratorFunction% would accept. Since untrusted |
| 3468 * code enters a SES environment only through these, we should be |
| 3469 * safe. |
| 3470 * |
| 3471 * <p>This test checks that this assumption indeed holds for the |
| 3472 * current platform. |
| 3473 */ |
| 3474 function test_IMPORT_CAN_BE_EVALLED() { |
| 3475 // From Table 40 at |
| 3476 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-source-text-mod
ule-records |
| 3477 // The following test will actually attempt to eval the following |
| 3478 // strings, so it is important that there not be strings here that |
| 3479 // can do damage if this eval succeeds during SES |
| 3480 // initialization. This is before any untrusted code runs in this |
| 3481 // realm, so we assume that no module named __noModWithThisName__ |
| 3482 // is yet importable. |
| 3483 var importExamples = [ |
| 3484 'import v from "__noModWithThisName__";', |
| 3485 'import * as ns from "__noModWithThisName__";', |
| 3486 'import {x} from "__noModWithThisName__";', |
| 3487 'import {x as v} from "__noModWithThisName__";', |
| 3488 'import "__noModWithThisName__";']; |
| 3489 var evallers = [unsafeEval, UnsafeFunction]; |
| 3490 if (unsafeIntrinsics.GeneratorFunction) { |
| 3491 evallers.push(unsafeIntrinsics.GeneratorFunction); |
| 3492 } |
| 3493 for (var i = 0; i < importExamples.length; i++) { |
| 3494 for (var j = 0; j < evallers.length; j++) { |
| 3495 try { |
| 3496 evallers[j](importExamples[i]); |
| 3497 return true; |
| 3498 } catch (ex) { |
| 3499 if (!(ex instanceof SyntaxError)) { |
| 3500 return 'unexpected "' + importExamples[i] + '" failure: ' + ex; |
| 3501 } |
| 3502 } |
| 3503 } |
| 3504 } |
| 3505 return false; |
| 3506 } |
| 3507 |
| 3508 /** |
| 3509 * Detects https://bugs.webkit.org/show_bug.cgi?id=141865 |
| 3510 * |
| 3511 * <p>On Safari 7.0.5 (9537.77.4), the getter of the |
| 3512 * Object.prototype.__proto__ property, if applied to undefined, |
| 3513 * acts like a sloppy function would, coercing the undefined to the |
| 3514 * global object and returning the global object's [[Prototype]]. |
| 3515 */ |
| 3516 function test_UNDERBAR_PROTO_GETTER_USES_GLOBAL() { |
| 3517 var gopd = Object.getOwnPropertyDescriptor; |
| 3518 var getProto = Object.getPrototypeOf; |
| 3519 |
| 3520 var desc = gopd(Object.prototype, '__proto__'); |
| 3521 if (!desc) { return false; } |
| 3522 var getter = desc.get; |
| 3523 if (!getter) { return false; } |
| 3524 var globalProto = void 0; |
| 3525 try { |
| 3526 globalProto = getter(); |
| 3527 } catch (ex) { |
| 3528 if (ex instanceof TypeError && globalProto === void 0) { |
| 3529 return false; |
| 3530 } |
| 3531 return 'unexpected error: ' + ex; |
| 3532 } |
| 3533 if (getProto(global) === globalProto) { return true; } |
| 3534 return 'unexpected global.__proto__: ' + globalProto; |
| 3535 } |
| 3536 |
| 3537 /** |
| 3538 * Detects https://bugs.webkit.org/show_bug.cgi?id=141865 |
| 3539 * |
| 3540 * <p>On Safari 7.0.5 (9537.77.4), the setter of the |
| 3541 * Object.prototype.__proto__ property, if applied to undefined, |
| 3542 * acts like a sloppy function would, coercing the undefined to the |
| 3543 * global object and setting its [[Prototype]]. |
| 3544 */ |
| 3545 function test_UNDERBAR_PROTO_SETTER_USES_GLOBAL() { |
| 3546 var gopd = Object.getOwnPropertyDescriptor; |
| 3547 var getProto = Object.getPrototypeOf; |
| 3548 |
| 3549 var desc = gopd(Object.prototype, '__proto__'); |
| 3550 if (!desc) { return false; } |
| 3551 var setter = desc.set; |
| 3552 if (!setter) { return false; } |
| 3553 var globalProto = getProto(global); |
| 3554 // Just insert an intermediate object into the prototype chain of the |
| 3555 // global object, so this realm is left in a usable state. |
| 3556 var splicedProto = Object.create(globalProto); |
| 3557 try { |
| 3558 setter(splicedProto); |
| 3559 } catch (ex) { |
| 3560 if (ex instanceof TypeError && getProto(global) === globalProto) { |
| 3561 return false; |
| 3562 } |
| 3563 return 'unexpected error: ' + ex; |
| 3564 } |
| 3565 if (getProto(global) === splicedProto) { return true; } |
| 3566 return 'unexpected global.__proto__: ' + getProto(global); |
| 3567 } |
| 3568 |
| 3569 /** |
| 3570 * Detects https://bugs.webkit.org/show_bug.cgi?id=141878 |
| 3571 * |
| 3572 * <p>On Safari 7.0.5 (9537.77.4), throwing a frozen object results |
| 3573 * in it becoming unfrozen and several properties being added to |
| 3574 * it: 'line', 'column', 'sourceURL' (not always), and 'stack'. The |
| 3575 * big security hole is due to 'stack', which is added as a |
| 3576 * writable configurable property. Although initialized to a string, |
| 3577 * one can assign an arbitrary object to it, opening a capability |
| 3578 * leak. |
| 3579 */ |
| 3580 function test_THROWING_THAWS_FROZEN_OBJECT() { |
| 3581 var o = Object.freeze([1, 2]); |
| 3582 if (!Object.isFrozen(o)) { |
| 3583 return 'Unexpected spontaneous thaw'; |
| 3584 } |
| 3585 var oldNames = Object.getOwnPropertyNames(o); |
| 3586 try { |
| 3587 throw o; |
| 3588 } catch (e) { |
| 3589 if (e !== o) { |
| 3590 return 'What was thrown is not what was caught'; |
| 3591 } |
| 3592 if (Object.isFrozen(e)) { |
| 3593 // In the bug we're testing for, Object.isFrozen(e) is false, |
| 3594 // which is dealt with below this if-statement. |
| 3595 // If Object.isFrozen(e) is true, presumably this platform |
| 3596 // does not have the bug. Before concluding that we're safe |
| 3597 // from this bug (returning false) the rest of this case does |
| 3598 // a bit of sanity checking to make sure that other symptoms |
| 3599 // of this bug are absent. |
| 3600 var newNames = Object.getOwnPropertyNames(o); |
| 3601 if (oldNames.length !== newNames.length) { |
| 3602 return 'Throwing changed properties to: ' + newNames; |
| 3603 } |
| 3604 return false; |
| 3605 } |
| 3606 var oldStack = e.stack; |
| 3607 var capLeak = {}; |
| 3608 try { |
| 3609 e.stack = capLeak; |
| 3610 } catch (err) { |
| 3611 if (e.stack === oldStack) { |
| 3612 throw 'Unexpected failure to leak: ' + err; |
| 3613 } |
| 3614 } |
| 3615 if (e.stack === capLeak) { return true; } |
| 3616 } |
| 3617 return 'Unexpected result of throwing frozen object'; |
| 3618 } |
| 3619 |
3379 | 3620 |
3380 ////////////////////// Repairs ///////////////////// | 3621 ////////////////////// Repairs ///////////////////// |
3381 // | 3622 // |
3382 // Each repair_NAME function exists primarily to repair the problem | 3623 // Each repair_NAME function exists primarily to repair the problem |
3383 // indicated by the corresponding test_NAME function. But other test | 3624 // indicated by the corresponding test_NAME function. But other test |
3384 // failures can still trigger a given repair. | 3625 // failures can still trigger a given repair. |
3385 | 3626 |
3386 | 3627 |
3387 var call = Function.prototype.call; | 3628 var call = Function.prototype.call; |
3388 var apply = Function.prototype.apply; | 3629 var apply = Function.prototype.apply; |
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4008 // conflicting with the caller-specified property names, without | 4249 // conflicting with the caller-specified property names, without |
4009 // needing to examine props twice. | 4250 // needing to examine props twice. |
4010 if (props !== undefined) { | 4251 if (props !== undefined) { |
4011 Object.defineProperties(o, props); | 4252 Object.defineProperties(o, props); |
4012 } | 4253 } |
4013 return o; | 4254 return o; |
4014 } | 4255 } |
4015 }); | 4256 }); |
4016 } | 4257 } |
4017 | 4258 |
| 4259 /** |
| 4260 * Repairs both getter and setter. If either are vulnerable, I don't |
| 4261 * care if the other seemed to pass the test. Better to make them |
| 4262 * both safe. |
| 4263 */ |
| 4264 function repair_UNDERBAR_PROTO_accessors_USE_GLOBAL() { |
| 4265 var gopd = Object.getOwnPropertyDescriptor; |
| 4266 |
| 4267 var oldDesc = gopd(Object.prototype, '__proto__'); |
| 4268 var oldGetter = oldDesc.get; |
| 4269 var oldSetter = oldDesc.set; |
| 4270 function newGetter() { |
| 4271 if (this === null || this === void 0) { |
| 4272 throw new TypeError('Cannot convert null or undefined to object'); |
| 4273 } else { |
| 4274 return oldGetter.call(this); |
| 4275 } |
| 4276 } |
| 4277 function newSetter(newProto) { |
| 4278 if (this === null || this === void 0) { |
| 4279 throw new TypeError('Cannot convert null or undefined to object'); |
| 4280 } else { |
| 4281 oldSetter.call(this, newProto); |
| 4282 } |
| 4283 } |
| 4284 Object.defineProperty(Object.prototype, '__proto__', { |
| 4285 get: oldGetter ? newGetter : void 0, |
| 4286 set: oldSetter ? newSetter : void 0 |
| 4287 }); |
| 4288 } |
| 4289 |
4018 ////////////////////// Generic tests/repairs ///////////////////// | 4290 ////////////////////// Generic tests/repairs ///////////////////// |
4019 // | 4291 // |
4020 // These are tests and repairs which follow a pattern, such that it is | 4292 // These are tests and repairs which follow a pattern, such that it is |
4021 // more practical to define them programmatically. | 4293 // more practical to define them programmatically. |
4022 | 4294 |
4023 function arrayPutProblem(destination, | 4295 function arrayPutProblem(destination, |
4024 prop, testArgs, i, expected, kind, opt_repair) { | 4296 prop, testArgs, i, expected, kind, opt_repair) { |
4025 var pos = ['first', 'last'][i]; | 4297 var pos = ['first', 'last'][i]; |
4026 var descs = { | 4298 var descs = { |
4027 readonly: {writable: false, configurable: false}, | 4299 readonly: {writable: false, configurable: false}, |
(...skipping 1164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5192 id: 'NUMERIC_PROPERTIES_INVISIBLE', | 5464 id: 'NUMERIC_PROPERTIES_INVISIBLE', |
5193 description: 'Numeric properties not reflectable on create()d objects', | 5465 description: 'Numeric properties not reflectable on create()d objects', |
5194 test: test_NUMERIC_PROPERTIES_INVISIBLE, | 5466 test: test_NUMERIC_PROPERTIES_INVISIBLE, |
5195 repair: repair_NUMERIC_PROPERTIES_INVISIBLE, | 5467 repair: repair_NUMERIC_PROPERTIES_INVISIBLE, |
5196 preSeverity: severities.UNSAFE_SPEC_VIOLATION, | 5468 preSeverity: severities.UNSAFE_SPEC_VIOLATION, |
5197 canRepair: true, | 5469 canRepair: true, |
5198 urls: ['http://webreflection.blogspot.co.uk/2014/04/all-ie-objects-are-bro
ken.html'], | 5470 urls: ['http://webreflection.blogspot.co.uk/2014/04/all-ie-objects-are-bro
ken.html'], |
5199 // TODO(kpreid): link Microsoft info page when available | 5471 // TODO(kpreid): link Microsoft info page when available |
5200 sections: ['8.12.6'], | 5472 sections: ['8.12.6'], |
5201 tests: [] // TODO(kpreid): contribute tests | 5473 tests: [] // TODO(kpreid): contribute tests |
| 5474 }, |
| 5475 { |
| 5476 id: 'GENERATORFUNCTION_CANNOT_BE_DENIED', |
| 5477 description: 'Cannot deny access to unsafe %GeneratorFunction%', |
| 5478 test: test_GENERATORFUNCTION_CANNOT_BE_DENIED, |
| 5479 repair: void 0, |
| 5480 preSeverity: severities.NOT_ISOLATED, |
| 5481 canRepair: false, |
| 5482 urls: ['https://code.google.com/p/google-caja/issues/detail?id=1953', |
| 5483 'https://code.google.com/p/v8/issues/detail?id=3902', |
| 5484 'https://code.google.com/p/chromium/issues/detail?id=460145', |
| 5485 'https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generato
rfunction.prototype.constructor'], |
| 5486 sections: [], |
| 5487 tests: [] |
| 5488 }, |
| 5489 { |
| 5490 id: 'IMPORT_CAN_BE_EVALLED', |
| 5491 description: 'Import statement evaluates outside module source text', |
| 5492 test: test_IMPORT_CAN_BE_EVALLED, |
| 5493 repair: void 0, |
| 5494 preSeverity: severities.NOT_ISOLATED, |
| 5495 canRepair: false, |
| 5496 urls: [], |
| 5497 sections: [], |
| 5498 tests: [] |
| 5499 }, |
| 5500 { |
| 5501 id: 'UNDERBAR_PROTO_GETTER_USES_GLOBAL', |
| 5502 description: 'The getter of __proto__ coerces "this" to global', |
| 5503 test: test_UNDERBAR_PROTO_GETTER_USES_GLOBAL, |
| 5504 repair: repair_UNDERBAR_PROTO_accessors_USE_GLOBAL, |
| 5505 preSeverity: severities.NOT_ISOLATED, |
| 5506 canRepair: true, |
| 5507 urls: ['https://bugs.webkit.org/show_bug.cgi?id=141865'], |
| 5508 sections: [], |
| 5509 tests: [] |
| 5510 }, |
| 5511 { |
| 5512 id: 'UNDERBAR_PROTO_SETTER_USES_GLOBAL', |
| 5513 description: 'The setter of __proto__ coerces "this" to global', |
| 5514 test: test_UNDERBAR_PROTO_SETTER_USES_GLOBAL, |
| 5515 repair: repair_UNDERBAR_PROTO_accessors_USE_GLOBAL, |
| 5516 preSeverity: severities.NOT_ISOLATED, |
| 5517 canRepair: true, |
| 5518 urls: ['https://bugs.webkit.org/show_bug.cgi?id=141865'], |
| 5519 sections: [], |
| 5520 tests: [] |
| 5521 }, |
| 5522 { |
| 5523 id: 'THROWING_THAWS_FROZEN_OBJECT', |
| 5524 description: 'Throwing a frozen object opens a capability leak', |
| 5525 test: test_THROWING_THAWS_FROZEN_OBJECT, |
| 5526 repair: void 0, |
| 5527 preSeverity: severities.NOT_ISOLATED, |
| 5528 canRepair: false, |
| 5529 urls: ['https://bugs.webkit.org/show_bug.cgi?id=141871', |
| 5530 'https://bugs.webkit.org/show_bug.cgi?id=141878'], |
| 5531 sections: [], |
| 5532 tests: [] |
5202 } | 5533 } |
5203 ]; | 5534 ]; |
5204 | 5535 |
5205 // SPLICE_PUT_IGNORES_FIRST_READONLY | 5536 // SPLICE_PUT_IGNORES_FIRST_READONLY |
5206 // SPLICE_PUT_DOESNT_THROW_FIRST_READONLY | 5537 // SPLICE_PUT_DOESNT_THROW_FIRST_READONLY |
5207 // SPLICE_PUT_IGNORES_FIRST_NON_WRITABLE | 5538 // SPLICE_PUT_IGNORES_FIRST_NON_WRITABLE |
5208 // SPLICE_PUT_DOESNT_THROW_FIRST_NON_WRITABLE | 5539 // SPLICE_PUT_DOESNT_THROW_FIRST_NON_WRITABLE |
5209 // SPLICE_PUT_IGNORES_LAST_READONLY | 5540 // SPLICE_PUT_IGNORES_LAST_READONLY |
5210 // SPLICE_PUT_DOESNT_THROW_LAST_READONLY | 5541 // SPLICE_PUT_DOESNT_THROW_LAST_READONLY |
5211 arrayPutProblem(supportedProblems, | 5542 arrayPutProblem(supportedProblems, |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5347 ses.es5ProblemReports = indexedReports; | 5678 ses.es5ProblemReports = indexedReports; |
5348 } catch (err) { | 5679 } catch (err) { |
5349 ses._repairer.updateMaxSeverity(ses.severities.NOT_SUPPORTED); | 5680 ses._repairer.updateMaxSeverity(ses.severities.NOT_SUPPORTED); |
5350 var during = ses._repairer.wasDoing(); | 5681 var during = ses._repairer.wasDoing(); |
5351 logger.error('ES5 Repair ' + during + 'failed with: ', err); | 5682 logger.error('ES5 Repair ' + during + 'failed with: ', err); |
5352 } | 5683 } |
5353 | 5684 |
5354 logger.reportMax(); | 5685 logger.reportMax(); |
5355 | 5686 |
5356 })(this); | 5687 })(this); |
LEFT | RIGHT |