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 621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 * | 638 * |
639 * <p>TODO: once all supported browsers implement ES6 generators, we | 639 * <p>TODO: once all supported browsers implement ES6 generators, we |
640 * can drop the "try"s below, drop the check for old Mozilla | 640 * can drop the "try"s below, drop the check for old Mozilla |
641 * generator syntax, and treat strictArgumentsGenerator as | 641 * generator syntax, and treat strictArgumentsGenerator as |
642 * uncondition in the test of the code. | 642 * unconditional in the test of the code. |
643 */ | 643 */ |
644 var strictArgumentsGenerator = void 0; | 644 var strictArgumentsGenerator = void 0; |
645 try { | 645 try { |
646 // ES6 syntax | 646 // ES6 syntax |
647 strictArgumentsGenerator = | 647 strictArgumentsGenerator = |
648 eval('(function*() { "use strict"; yield arguments; })'); | 648 eval('(function*() { "use strict"; yield arguments; })'); |
649 } catch (ex) { | 649 } catch (ex) { |
650 if (!(ex instanceof SyntaxError)) { throw ex; } | 650 if (!(ex instanceof SyntaxError)) { throw ex; } |
651 try { | 651 try { |
652 // Old Firefox syntax | 652 // Old Firefox syntax |
(...skipping 14 matching lines...) Expand all Loading... |
667 * 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 |
668 * environment. | 668 * environment. |
669 */ | 669 */ |
670 function getUndeniables() { | 670 function getUndeniables() { |
671 var gopd = Object.getOwnPropertyDescriptor; | 671 var gopd = Object.getOwnPropertyDescriptor; |
672 var getProto = Object.getPrototypeOf; | 672 var getProto = Object.getPrototypeOf; |
673 | 673 |
674 // The first element of each undeniableTuple is a string used to | 674 // The first element of each undeniableTuple is a string used to |
675 // name the undeniable object for reporting purposes. It has no | 675 // name the undeniable object for reporting purposes. It has no |
676 // other programmatic use. | 676 // other programmatic use. |
677 | 677 // |
678 // The second element of each undeniableTuple should be the | 678 // The second element of each undeniableTuple should be the |
679 // undeniable itself. | 679 // undeniable itself. |
680 | 680 // |
681 // The optional third element of the undeniableTuple, if present, | 681 // The optional third element of the undeniableTuple, if present, |
682 // should be an example of syntax, rather than use of a monkey | 682 // should be an example of syntax, rather than use of a monkey |
683 // patchable API, evaluating to a value from which the undeniable | 683 // patchable API, evaluating to a value from which the undeniable |
684 // object in the second element can be reached by only the | 684 // object in the second element can be reached by only the |
685 // following steps: | 685 // following steps: |
686 // If the value is primitve, convert to an Object wrapper. | 686 // If the value is primitve, convert to an Object wrapper. |
687 // Is the resulting object either the undeniable object, or does | 687 // Is the resulting object either the undeniable object, or does |
688 // it inherit directly from the undeniable object? | 688 // it inherit directly from the undeniable object? |
689 | 689 |
690 var undeniableTuples = [ | 690 var undeniableTuples = [ |
(...skipping 2808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3499 if (!(ex instanceof SyntaxError)) { | 3499 if (!(ex instanceof SyntaxError)) { |
3500 return 'unexpected "' + importExamples[i] + '" failure: ' + ex; | 3500 return 'unexpected "' + importExamples[i] + '" failure: ' + ex; |
3501 } | 3501 } |
3502 } | 3502 } |
3503 } | 3503 } |
3504 } | 3504 } |
3505 return false; | 3505 return false; |
3506 } | 3506 } |
3507 | 3507 |
3508 /** | 3508 /** |
3509 * | 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]]. |
3510 */ | 3515 */ |
3511 function test_UNDERBAR_PROTO_GETTER_USES_GLOBAL() { | 3516 function test_UNDERBAR_PROTO_GETTER_USES_GLOBAL() { |
3512 var gopd = Object.getOwnPropertyDescriptor; | 3517 var gopd = Object.getOwnPropertyDescriptor; |
3513 var getProto = Object.getPrototypeOf; | 3518 var getProto = Object.getPrototypeOf; |
3514 | 3519 |
3515 var desc = gopd(Object.prototype, '__proto__'); | 3520 var desc = gopd(Object.prototype, '__proto__'); |
3516 if (!desc) { return false; } | 3521 if (!desc) { return false; } |
3517 if (!desc.get) { return false; } | 3522 var getter = desc.get; |
| 3523 if (!getter) { return false; } |
3518 var globalProto = void 0; | 3524 var globalProto = void 0; |
3519 try { | 3525 try { |
3520 globalProto = (1,desc.get)(); | 3526 globalProto = getter(); |
3521 } catch (ex) { | 3527 } catch (ex) { |
3522 if (ex instanceof TypeError && globalProto === void 0) { | 3528 if (ex instanceof TypeError && globalProto === void 0) { |
3523 return false; | 3529 return false; |
3524 } | 3530 } |
3525 return 'unexpected error: ' + ex; | 3531 return 'unexpected error: ' + ex; |
3526 } | 3532 } |
3527 if (getProto(global) === globalProto) { return true; } | 3533 if (getProto(global) === globalProto) { return true; } |
3528 return 'unexpected global.__proto__: ' + globalProto; | 3534 return 'unexpected global.__proto__: ' + globalProto; |
3529 } | 3535 } |
3530 | 3536 |
3531 /** | 3537 /** |
3532 * | 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]]. |
3533 */ | 3544 */ |
3534 function test_UNDERBAR_PROTO_SETTER_USES_GLOBAL() { | 3545 function test_UNDERBAR_PROTO_SETTER_USES_GLOBAL() { |
3535 var gopd = Object.getOwnPropertyDescriptor; | 3546 var gopd = Object.getOwnPropertyDescriptor; |
3536 var getProto = Object.getPrototypeOf; | 3547 var getProto = Object.getPrototypeOf; |
3537 | 3548 |
3538 var desc = gopd(Object.prototype, '__proto__'); | 3549 var desc = gopd(Object.prototype, '__proto__'); |
3539 if (!desc) { return false; } | 3550 if (!desc) { return false; } |
3540 if (!desc.set) { return false; } | 3551 var setter = desc.set; |
| 3552 if (!setter) { return false; } |
3541 var globalProto = getProto(global); | 3553 var globalProto = getProto(global); |
3542 // Just insert an intermediate object into the prototype chain of the | 3554 // Just insert an intermediate object into the prototype chain of the |
3543 // global object, so this realm is left in a usable state. | 3555 // global object, so this realm is left in a usable state. |
3544 var splicedProto = Object.create(globalProto); | 3556 var splicedProto = Object.create(globalProto); |
3545 try { | 3557 try { |
3546 (1,desc.set)(splicedProto); | 3558 setter(splicedProto); |
3547 } catch (ex) { | 3559 } catch (ex) { |
3548 if (ex instanceof TypeError && getProto(global) === globalProto) { | 3560 if (ex instanceof TypeError && getProto(global) === globalProto) { |
3549 return false; | 3561 return false; |
3550 } | 3562 } |
3551 return 'unexpected error: ' + ex; | 3563 return 'unexpected error: ' + ex; |
3552 } | 3564 } |
3553 if (getProto(global) === splicedProto) { return true; } | 3565 if (getProto(global) === splicedProto) { return true; } |
3554 return 'unexpected global.__proto__: ' + getProto(global); | 3566 return 'unexpected global.__proto__: ' + getProto(global); |
3555 } | 3567 } |
3556 | 3568 |
3557 /** | 3569 /** |
3558 * | 3570 * Detects https://bugs.webkit.org/show_bug.cgi?id=141878 |
3559 */ | 3571 * |
3560 function test_THROWING_MAKES_OBJECT_FORGET_ITS_FROZEN() { | 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() { |
3561 var o = Object.freeze([1, 2]); | 3581 var o = Object.freeze([1, 2]); |
3562 if (!Object.isFrozen(o)) { | 3582 if (!Object.isFrozen(o)) { |
3563 return 'Unexpected spontaneous thaw'; | 3583 return 'Unexpected spontaneous thaw'; |
3564 } | 3584 } |
| 3585 var oldNames = Object.getOwnPropertyNames(o); |
3565 try { | 3586 try { |
3566 throw o; | 3587 throw o; |
3567 } catch (e) { | 3588 } catch (e) { |
3568 if (e !== o) { | 3589 if (e !== o) { |
3569 return 'What was thrown is not what was caught'; | 3590 return 'What was thrown is not what was caught'; |
3570 } | 3591 } |
3571 if (Object.isFrozen(e)) { return false; } | 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 = {}; |
3572 try { | 3608 try { |
3573 e[2] = 'bar'; | 3609 e.stack = capLeak; |
3574 } catch (ex) { | 3610 } catch (err) { |
3575 if ('2' in e) { | 3611 if (e.stack === oldStack) { |
3576 return 'Assignment happened and threw'; | 3612 throw 'Unexpected failure to leak: ' + err; |
3577 } else { | |
3578 return true; | |
3579 } | 3613 } |
3580 } | 3614 } |
3581 return 'Frozen object was extended'; | 3615 if (e.stack === capLeak) { return true; } |
3582 } | 3616 } |
| 3617 return 'Unexpected result of throwing frozen object'; |
3583 } | 3618 } |
3584 | 3619 |
3585 | 3620 |
3586 ////////////////////// Repairs ///////////////////// | 3621 ////////////////////// Repairs ///////////////////// |
3587 // | 3622 // |
3588 // Each repair_NAME function exists primarily to repair the problem | 3623 // Each repair_NAME function exists primarily to repair the problem |
3589 // indicated by the corresponding test_NAME function. But other test | 3624 // indicated by the corresponding test_NAME function. But other test |
3590 // failures can still trigger a given repair. | 3625 // failures can still trigger a given repair. |
3591 | 3626 |
3592 | 3627 |
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4219 return o; | 4254 return o; |
4220 } | 4255 } |
4221 }); | 4256 }); |
4222 } | 4257 } |
4223 | 4258 |
4224 /** | 4259 /** |
4225 * Repairs both getter and setter. If either are vulnerable, I don't | 4260 * Repairs both getter and setter. If either are vulnerable, I don't |
4226 * care if the other seemed to pass the test. Better to make them | 4261 * care if the other seemed to pass the test. Better to make them |
4227 * both safe. | 4262 * both safe. |
4228 */ | 4263 */ |
4229 function repair_UNDERBAR_PROTO_GETTER_USES_GLOBAL() { | 4264 function repair_UNDERBAR_PROTO_accessors_USE_GLOBAL() { |
4230 var gopd = Object.getOwnPropertyDescriptor; | 4265 var gopd = Object.getOwnPropertyDescriptor; |
4231 | 4266 |
4232 var oldDesc = gopd(Object.prototype, '__proto__'); | 4267 var oldDesc = gopd(Object.prototype, '__proto__'); |
4233 var oldGetter = oldDesc.get; | 4268 var oldGetter = oldDesc.get; |
4234 var oldSetter = oldDesc.set; | 4269 var oldSetter = oldDesc.set; |
4235 function newGetter() { | 4270 function newGetter() { |
4236 if (this === null || this === void 0) { | 4271 if (this === null || this === void 0) { |
4237 throw new TypeError('Cannot convert null or undefined to object'); | 4272 throw new TypeError('Cannot convert null or undefined to object'); |
4238 } else { | 4273 } else { |
4239 return oldGetter.call(this); | 4274 return oldGetter.call(this); |
(...skipping 1219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5459 preSeverity: severities.NOT_ISOLATED, | 5494 preSeverity: severities.NOT_ISOLATED, |
5460 canRepair: false, | 5495 canRepair: false, |
5461 urls: [], | 5496 urls: [], |
5462 sections: [], | 5497 sections: [], |
5463 tests: [] | 5498 tests: [] |
5464 }, | 5499 }, |
5465 { | 5500 { |
5466 id: 'UNDERBAR_PROTO_GETTER_USES_GLOBAL', | 5501 id: 'UNDERBAR_PROTO_GETTER_USES_GLOBAL', |
5467 description: 'The getter of __proto__ coerces "this" to global', | 5502 description: 'The getter of __proto__ coerces "this" to global', |
5468 test: test_UNDERBAR_PROTO_GETTER_USES_GLOBAL, | 5503 test: test_UNDERBAR_PROTO_GETTER_USES_GLOBAL, |
5469 repair: repair_UNDERBAR_PROTO_GETTER_USES_GLOBAL, | 5504 repair: repair_UNDERBAR_PROTO_accessors_USE_GLOBAL, |
5470 preSeverity: severities.NOT_ISOLATED, | 5505 preSeverity: severities.NOT_ISOLATED, |
5471 canRepair: true, | 5506 canRepair: true, |
5472 urls: ['https://bugs.webkit.org/show_bug.cgi?id=141865'], | 5507 urls: ['https://bugs.webkit.org/show_bug.cgi?id=141865'], |
5473 sections: [], | 5508 sections: [], |
5474 tests: [] | 5509 tests: [] |
5475 }, | 5510 }, |
5476 { | 5511 { |
5477 id: 'UNDERBAR_PROTO_SETTER_USES_GLOBAL', | 5512 id: 'UNDERBAR_PROTO_SETTER_USES_GLOBAL', |
5478 description: 'The setter of __proto__ coerces "this" to global', | 5513 description: 'The setter of __proto__ coerces "this" to global', |
5479 test: test_UNDERBAR_PROTO_SETTER_USES_GLOBAL, | 5514 test: test_UNDERBAR_PROTO_SETTER_USES_GLOBAL, |
5480 repair: repair_UNDERBAR_PROTO_GETTER_USES_GLOBAL, | 5515 repair: repair_UNDERBAR_PROTO_accessors_USE_GLOBAL, |
5481 preSeverity: severities.NOT_ISOLATED, | 5516 preSeverity: severities.NOT_ISOLATED, |
5482 canRepair: true, | 5517 canRepair: true, |
5483 urls: ['https://bugs.webkit.org/show_bug.cgi?id=141865'], | 5518 urls: ['https://bugs.webkit.org/show_bug.cgi?id=141865'], |
5484 sections: [], | 5519 sections: [], |
5485 tests: [] | 5520 tests: [] |
5486 }, | 5521 }, |
5487 { | 5522 { |
5488 id: 'THROWING_MAKES_OBJECT_FORGET_ITS_FROZEN', | 5523 id: 'THROWING_THAWS_FROZEN_OBJECT', |
5489 description: 'Throwing a frozen object makes it claim to be unfrozen', | 5524 description: 'Throwing a frozen object opens a capability leak', |
5490 test: test_THROWING_MAKES_OBJECT_FORGET_ITS_FROZEN, | 5525 test: test_THROWING_THAWS_FROZEN_OBJECT, |
5491 repair: void 0, | 5526 repair: void 0, |
5492 preSeverity: severities.SAFE_SPEC_VIOLATION, | 5527 preSeverity: severities.NOT_ISOLATED, |
5493 canRepair: false, | 5528 canRepair: false, |
5494 urls: ['https://bugs.webkit.org/show_bug.cgi?id=141871'], | 5529 urls: ['https://bugs.webkit.org/show_bug.cgi?id=141871', |
| 5530 'https://bugs.webkit.org/show_bug.cgi?id=141878'], |
5495 sections: [], | 5531 sections: [], |
5496 tests: [] | 5532 tests: [] |
5497 } | 5533 } |
5498 ]; | 5534 ]; |
5499 | 5535 |
5500 // SPLICE_PUT_IGNORES_FIRST_READONLY | 5536 // SPLICE_PUT_IGNORES_FIRST_READONLY |
5501 // SPLICE_PUT_DOESNT_THROW_FIRST_READONLY | 5537 // SPLICE_PUT_DOESNT_THROW_FIRST_READONLY |
5502 // SPLICE_PUT_IGNORES_FIRST_NON_WRITABLE | 5538 // SPLICE_PUT_IGNORES_FIRST_NON_WRITABLE |
5503 // SPLICE_PUT_DOESNT_THROW_FIRST_NON_WRITABLE | 5539 // SPLICE_PUT_DOESNT_THROW_FIRST_NON_WRITABLE |
5504 // SPLICE_PUT_IGNORES_LAST_READONLY | 5540 // SPLICE_PUT_IGNORES_LAST_READONLY |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5642 ses.es5ProblemReports = indexedReports; | 5678 ses.es5ProblemReports = indexedReports; |
5643 } catch (err) { | 5679 } catch (err) { |
5644 ses._repairer.updateMaxSeverity(ses.severities.NOT_SUPPORTED); | 5680 ses._repairer.updateMaxSeverity(ses.severities.NOT_SUPPORTED); |
5645 var during = ses._repairer.wasDoing(); | 5681 var during = ses._repairer.wasDoing(); |
5646 logger.error('ES5 Repair ' + during + 'failed with: ', err); | 5682 logger.error('ES5 Repair ' + during + 'failed with: ', err); |
5647 } | 5683 } |
5648 | 5684 |
5649 logger.reportMax(); | 5685 logger.reportMax(); |
5650 | 5686 |
5651 })(this); | 5687 })(this); |
LEFT | RIGHT |