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 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://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, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 /** | 15 /** |
16 * @fileoverview Make this frame SES-safe or die trying. | 16 * @fileoverview Make this frame SES-safe or die trying. |
17 * | 17 * |
18 * <p>Assumes ES5 plus a WeakMap that conforms to the anticipated ES6 | 18 * <p>Assumes ES5 plus a WeakMap that conforms to the anticipated ES6 |
19 * WeakMap spec. Compatible with ES5-strict or anticipated ES6. | 19 * WeakMap spec. Compatible with ES5-strict or anticipated ES6. |
20 * | 20 * |
21 * //requires ses.makeCallerHarmless, ses.makeArgumentsHarmless | 21 * //requires ses.makeCallerHarmless, ses.makeArgumentsHarmless |
22 * //requires ses.noFuncPoison | 22 * //requires ses.noFuncPoison |
23 * //requires ses.verifyStrictFunctionBody | 23 * //requires ses.verifyStrictFunctionBody |
| 24 * //requires ses.getUndeniables, ses.earlyUndeniables |
| 25 * //requires ses.getAnonIntrinsics |
24 * //optionally requires ses.mitigateSrcGotchas | 26 * //optionally requires ses.mitigateSrcGotchas |
25 * //provides ses.startSES ses.resolveOptions, ses.securableWrapperSrc | 27 * //provides ses.startSES ses.resolveOptions, ses.securableWrapperSrc |
26 * //provides ses.makeCompiledExpr ses.prepareExpr | 28 * //provides ses.makeCompiledExpr ses.prepareExpr |
27 * | 29 * |
28 * @author Mark S. Miller, | 30 * @author Mark S. Miller, |
29 * @author Jasvir Nagra | 31 * @author Jasvir Nagra |
30 * @requires WeakMap | 32 * @requires WeakMap |
31 * @overrides ses, console, eval, Function, cajaVM | 33 * @overrides ses, console, eval, Function, cajaVM |
32 */ | 34 */ |
33 var ses; | 35 var ses; |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 * whitelist, our safety depends on these variables being | 160 * whitelist, our safety depends on these variables being |
159 * frozen as a side effect of freezing the corresponding | 161 * frozen as a side effect of freezing the corresponding |
160 * properties of {@code global}. These properties are also | 162 * properties of {@code global}. These properties are also |
161 * duplicated onto the virtual global objects which are | 163 * duplicated onto the virtual global objects which are |
162 * provided as the {@code this} binding for the safe | 164 * provided as the {@code this} binding for the safe |
163 * evaluation calls -- emulating the safe subset of the normal | 165 * evaluation calls -- emulating the safe subset of the normal |
164 * global object. | 166 * global object. |
165 * TODO(erights): Currently, the code has only been tested when | 167 * TODO(erights): Currently, the code has only been tested when |
166 * {@code global} is the global object of <i>this</i> | 168 * {@code global} is the global object of <i>this</i> |
167 * frame. The code should be made to work for cross-frame use. | 169 * frame. The code should be made to work for cross-frame use. |
168 * @param whitelist ::Record(Permit) where Permit = true | "*" | | 170 * @param whitelist ::Record(Permit) where |
169 * Record(Permit). Describes the subset of naming | 171 * Permit = true | false | "*" | "maybeAccessor" | Record(Permit). |
170 * paths starting from {@code sharedImports} that should be | 172 * Describes the subset of naming paths starting from {@code |
171 * accessible. The <i>accessible primordials</i> are all values | 173 * sharedImports} that should be accessible. The <i>accessible |
172 * found by navigating these paths starting from {@code | 174 * primordials</i> are all values found by navigating these |
173 * sharedImports}. All non-whitelisted properties of accessible | 175 * paths starting from {@code sharedImports}. All |
174 * primordials are deleted, and then {@code sharedImports} | 176 * non-whitelisted properties of accessible primordials are |
175 * and all accessible primordials are frozen with the | 177 * deleted, and then {@code sharedImports} and all accessible |
176 * whitelisted properties frozen as data properties. | 178 * primordials are frozen with the whitelisted properties |
177 * TODO(erights): fix the code and documentation to also | 179 * frozen as data properties. TODO(erights): fix the code and |
178 * support confined-ES5, suitable for confining potentially | 180 * documentation to also support confined-ES5, suitable for |
179 * offensive code but not supporting defensive code, where we | 181 * confining potentially offensive code but not supporting |
180 * skip this last freezing step. With confined-ES5, each frame | 182 * defensive code, where we skip this last freezing step. With |
181 * is considered a separate protection domain rather that each | 183 * confined-ES5, each frame is considered a separate protection |
182 * individual object. | 184 * domain rather that each individual object. |
183 * @param limitSrcCharset ::F([string]) | 185 * @param limitSrcCharset ::F([string]) |
184 * Given the sourceText for a strict Program, return a record with an | 186 * Given the sourceText for a strict Program, return a record with an |
185 * 'error' field if it is not in the limited character set that SES | 187 * 'error' field if it is not in the limited character set that SES |
186 * should process; otherwise, return a record with a 'programSrc' field | 188 * should process; otherwise, return a record with a 'programSrc' field |
187 * containing the original program text with Unicode escapes. | 189 * containing the original program text with Unicode escapes. |
188 * @param atLeastFreeVarNames ::F([string], Record(true)) | 190 * @param atLeastFreeVarNames ::F([string], Record(true)) |
189 * Given the sourceText for a strict Program, | 191 * Given the sourceText for a strict Program, |
190 * atLeastFreeVarNames(sourceText) returns a Record whose | 192 * atLeastFreeVarNames(sourceText) returns a Record whose |
191 * enumerable own property names must include the names of all the | 193 * enumerable own property names must include the names of all the |
192 * free variables occuring in sourceText. It can include as | 194 * free variables occuring in sourceText. It can include as |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 | 362 |
361 /** | 363 /** |
362 * Use to tamper proof a function which is not intended to ever be | 364 * Use to tamper proof a function which is not intended to ever be |
363 * used as a constructor, since it nulls out the function's | 365 * used as a constructor, since it nulls out the function's |
364 * prototype first. | 366 * prototype first. |
365 */ | 367 */ |
366 function constFunc(func) { | 368 function constFunc(func) { |
367 func.prototype = null; | 369 func.prototype = null; |
368 return freeze(func); | 370 return freeze(func); |
369 } | 371 } |
370 | |
371 | |
372 | |
373 ////////////////////////////// Intrinsics /////////////////////////// | |
374 | |
375 // Intrinsics not otherwise reachable by named own property | |
376 // traversal from globals. | |
377 // See | |
378 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-well-known-intrin
sic-objects | |
379 // and the instrinsics section of whitelist.js | |
380 | |
381 var intrinsics = {}; | |
382 | |
383 // Get the %ThrowTypeError% intrinsic. | |
384 intrinsics.ThrowTypeError = gopd(arguments, 'caller').get; | |
385 | |
386 // Get the ES6 %ArrayIteratorPrototype%, %StringIteratorPrototype%, | |
387 // and %IteratorPrototype% intrinsics, if present. | |
388 // TODO %MapIteratorPrototype% | |
389 // TODO %SetIteratorPrototype% | |
390 (function() { | |
391 var iteratorSym = global.Symbol && global.Symbol.iterator || | |
392 "@@iterator"; // used instead of a symbol on FF35 | |
393 if ([][iteratorSym] === void 0) { return; } | |
394 var arrayIter = [][iteratorSym](); | |
395 var ArrayIteratorPrototype = getProto(arrayIter); | |
396 intrinsics.ArrayIteratorPrototype = ArrayIteratorPrototype; | |
397 var IteratorPrototype = getProto(ArrayIteratorPrototype); | |
398 if (IteratorPrototype !== Object.prototype) { | |
399 if (getProto(IteratorPrototype) !== Object.prototype) { | |
400 throw new Error( | |
401 '%IteratorPrototype%.__proto__ was not Object.prototype'); | |
402 } | |
403 intrinsics.IteratorPrototype = IteratorPrototype; | |
404 } | |
405 if (''[iteratorSym] === void 0) { return; } | |
406 var stringIter = ''[iteratorSym](); | |
407 var StringIteratorPrototype = getProto(stringIter); | |
408 intrinsics.StringIteratorPrototype = StringIteratorPrototype; | |
409 var stringIterProtoBase = getProto(StringIteratorPrototype); | |
410 if (stringIterProtoBase !== IteratorPrototype && | |
411 stringIterProtoBase !== Object.prototype) { | |
412 throw new Error('unexpected %StringIteratorPrototype%.__proto__'); | |
413 } | |
414 }()); | |
415 | |
416 // Get the ES6 %GeneratorFunction% intrinsic, if present. | |
417 (function() { | |
418 // See http://people.mozilla.org/~jorendorff/figure-2.png | |
419 var g1; | |
420 try { | |
421 // ES6 syntax | |
422 g1 = eval('(function*() { "use strict"; yield; })'); | |
423 } catch (_) { | |
424 try { | |
425 // Old Firefox syntax | |
426 g1 = eval('(function() { "use strict"; yield; })'); | |
427 } catch (_2) { | |
428 return; | |
429 } | |
430 } | |
431 var Generator = getProto(g1); | |
432 if (Generator === Function.prototype) { return; } | |
433 if (getProto(Generator) !== Function.prototype) { | |
434 throw new Error('Generator.__proto__ was not Function.prototype'); | |
435 } | |
436 var GeneratorFunction = Generator.constructor; | |
437 if (GeneratorFunction === Function) { return; } | |
438 if (getProto(GeneratorFunction) !== Function) { | |
439 throw new Error('GeneratorFunction.__proto__ was not Function'); | |
440 } | |
441 intrinsics.GeneratorFunction = GeneratorFunction; | |
442 var genProtoBase = getProto(Generator.prototype); | |
443 if (genProtoBase !== intrinsics.IteratorPrototype && | |
444 genProtoBase !== Object.prototype) { | |
445 throw new Error('Unexpected Generator.prototype.__proto__'); | |
446 } | |
447 }()); | |
448 | |
449 // Get the ES6 %TypedArray% intrinsic, if present. | |
450 (function() { | |
451 if (!global.Float32Array) { return; } | |
452 var TypedArray = getProto(global.Float32Array); | |
453 if (TypedArray === Function.prototype) { return; } | |
454 if (getProto(TypedArray) !== Function.prototype) { | |
455 // http://bespin.cz/~ondras/html/classv8_1_1ArrayBufferView.html | |
456 // has me worried that someone might make such an intermediate | |
457 // object visible. | |
458 throw new Error('TypedArray.__proto__ was not Function.prototype'); | |
459 } | |
460 intrinsics.TypedArray = TypedArray; | |
461 }()); | |
462 | |
463 | |
464 | |
465 /////////////////////////////////////////// | |
466 | 372 |
467 function fail(str) { | 373 function fail(str) { |
468 debugger; | 374 debugger; |
469 throw new EvalError(str); | 375 throw new EvalError(str); |
470 } | 376 } |
471 | 377 |
472 if (typeof WeakMap === 'undefined') { | 378 if (typeof WeakMap === 'undefined') { |
473 fail('No built-in WeakMaps, so WeakMap.js must be loaded first'); | 379 fail('No built-in WeakMaps, so WeakMap.js must be loaded first'); |
474 } | 380 } |
475 | 381 |
(...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1096 // Follow the pattern in compileExpr | 1002 // Follow the pattern in compileExpr |
1097 var wrapperSrc = securableWrapperSrc(exprSrc); | 1003 var wrapperSrc = securableWrapperSrc(exprSrc); |
1098 var wrapper = unsafeEval(wrapperSrc); | 1004 var wrapper = unsafeEval(wrapperSrc); |
1099 var freeNames = atLeastFreeVarNames(exprSrc); | 1005 var freeNames = atLeastFreeVarNames(exprSrc); |
1100 var moduleMaker = makeCompiledExpr(wrapper, freeNames, options); | 1006 var moduleMaker = makeCompiledExpr(wrapper, freeNames, options); |
1101 | 1007 |
1102 moduleMaker.requirements = getRequirements(modSrc); | 1008 moduleMaker.requirements = getRequirements(modSrc); |
1103 return freeze(moduleMaker); | 1009 return freeze(moduleMaker); |
1104 } | 1010 } |
1105 | 1011 |
1106 /** | 1012 // This block replaces the original Function constructor, and the |
1107 * A safe form of the {@code Function} constructor, which | 1013 // original %GeneratorFunction% instrinsic if present, with safe |
1108 * constructs strict functions that can only refer freely to the | 1014 // replacements that preserve SES confinement. After this block is |
1109 * {@code sharedImports}. | 1015 // done, the originals should no longer be reachable. |
1110 * | 1016 (function() { |
1111 * <p>The returned function is strict whether or not it declares | 1017 var unsafeIntrinsics = ses.getAnonIntrinsics(); |
1112 * itself to be. | 1018 |
1113 */ | 1019 /** |
1114 function FakeFunction(var_args) { | 1020 * A safe form of the {@code Function} constructor, which |
1115 var params = [].slice.call(arguments, 0); | 1021 * constructs strict functions that can only refer freely to the |
1116 var body = ses.verifyStrictFunctionBody(params.pop() || ''); | 1022 * {@code sharedImports}. |
1117 | 1023 * |
1118 // Although the individual params may not be strings, the params | 1024 * <p>The returned function is strict whether or not it declares |
1119 // array is reliably a fresh array, so under the SES (not CES) | 1025 * itself to be. |
1120 // assumptions of unmodified primordials, this calls the reliable | 1026 */ |
1121 // Array.prototype.join which guarantees that its result is a string. | 1027 function FakeFunction(var_args) { |
1122 params = params.join(','); | 1028 var params = [].slice.call(arguments, 0); |
1123 | 1029 var body = ses.verifyStrictFunctionBody(params.pop() || ''); |
1124 // Note the EOL after body to prevent a trailing line comment in | 1030 · |
1125 // body from eliding the rest of the wrapper. | 1031 // Although the individual params may not be strings, the params |
1126 var exprSrc = '(function(' + params + '\n){' + body + '\n})'; | 1032 // array is reliably a fresh array, so under the SES (not CES) |
1127 return compileExpr(exprSrc)(sharedImports); | 1033 // assumptions of unmodified primordials, this calls the reliable |
1128 } | 1034 // Array.prototype.join which guarantees that its result is a string. |
1129 FakeFunction.prototype = UnsafeFunction.prototype; | 1035 params = params.join(','); |
1130 FakeFunction.prototype.constructor = FakeFunction; | 1036 · |
1131 global.Function = FakeFunction; | 1037 // Note the EOL after body to prevent a trailing line comment in |
1132 | 1038 // body from eliding the rest of the wrapper. |
1133 if (intrinsics.GeneratorFunction) { | 1039 var exprSrc = '(function(' + params + '\n){' + body + '\n})'; |
1134 intrinsics.GeneratorFunction.__proto__ = FakeFunction; | 1040 return compileExpr(exprSrc)(sharedImports); |
1135 if (getProto(intrinsics.GeneratorFunction) !== FakeFunction) { | 1041 } |
1136 throw new Error('Cannot reparent GeneratorFunction'); | 1042 FakeFunction.prototype = UnsafeFunction.prototype; |
1137 } | 1043 FakeFunction.prototype.constructor = FakeFunction; |
1138 } | 1044 global.Function = FakeFunction; |
| 1045 |
| 1046 |
| 1047 function FakeGeneratorFunction(var_args) { |
| 1048 var params = [].slice.call(arguments, 0); |
| 1049 var body = ses.verifyStrictFunctionBody(params.pop() || ''); |
| 1050 params = params.join(','); |
| 1051 |
| 1052 var exprSrc = '(function*(' + params + '\n){' + body + '\n})'; |
| 1053 return compileExpr(exprSrc)(sharedImports); |
| 1054 } |
| 1055 var UnsafeGeneratorFunction = unsafeIntrinsics.GeneratorFunction; |
| 1056 if (UnsafeGeneratorFunction) { |
| 1057 var Generator = ses.earlyUndeniables['%Generator%']; |
| 1058 if (!(Generator && |
| 1059 Generator.constructor === UnsafeGeneratorFunction && |
| 1060 UnsafeGeneratorFunction.prototype === Generator && |
| 1061 getProto(UnsafeGeneratorFunction) === UnsafeFunction && |
| 1062 getProto(Generator) === Function.prototype)) { |
| 1063 throw new Error('Unexpected primordial Generator arrangement'); |
| 1064 } |
| 1065 FakeGeneratorFunction.prototype = Generator; |
| 1066 FakeGeneratorFunction.__proto__ = FakeFunction; |
| 1067 if (getProto(FakeGeneratorFunction) !== FakeFunction) { |
| 1068 throw Error('Failed to set FakeGeneratorFunction.__proto__'); |
| 1069 } |
| 1070 try { |
| 1071 // According to section 25.2.3.1 of the ES6 / ES2015 spec, |
| 1072 // the generator.constructor property should have attributes |
| 1073 // writable: false, configurable: true, so we need to change |
| 1074 // it with defProp rather than assignment. Recall that when |
| 1075 // defProp-ing an existing property, all unspecified |
| 1076 // attributes preserve their existing setting. |
| 1077 defProp(Generator, 'constructor', { value: FakeGeneratorFunction }); |
| 1078 } catch (ex) { |
| 1079 try { |
| 1080 Generator.constructor = FakeGeneratorFunction; |
| 1081 } catch (ex2) { |
| 1082 // TODO: report |
| 1083 } |
| 1084 // TODO: report |
| 1085 } |
| 1086 if (Generator.constructor !== FakeGeneratorFunction) { |
| 1087 // TODO: define logger and reportItem earlier, so we can use |
| 1088 // them here. |
| 1089 ses.updateMaxSeverity(ses.severities.NOT_ISOLATED); |
| 1090 if (Generator.constructor === UnsafeGeneratorFunction) { |
| 1091 ses.logger.error( |
| 1092 'Cannot deny access to unsafe %GeneratorFunction%'); |
| 1093 } else { |
| 1094 throw new Error('Unexpected %Generator%.constructor: ' + |
| 1095 Generator.constructor); |
| 1096 } |
| 1097 } |
| 1098 } |
| 1099 // The next time we ses.getAnonIntrinsics(), the result should be |
| 1100 // safe intrinsics. |
| 1101 }()); |
1139 | 1102 |
1140 | 1103 |
1141 /** | 1104 /** |
1142 * A safe form of the indirect {@code eval} function, which | 1105 * A safe form of the indirect {@code eval} function, which |
1143 * evaluates {@code src} as strict code that can only refer freely | 1106 * evaluates {@code src} as strict code that can only refer freely |
1144 * to the {@code sharedImports}. | 1107 * to the {@code sharedImports}. |
1145 * | 1108 * |
1146 * <p>Given our parserless methods of verifying untrusted sources, | 1109 * <p>Given our parserless methods of verifying untrusted sources, |
1147 * we unfortunately have no practical way to obtain the completion | 1110 * we unfortunately have no practical way to obtain the completion |
1148 * value of a safely evaluated Program. Instead, we adopt a | 1111 * value of a safely evaluated Program. Instead, we adopt a |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1428 makeArrayLike.canBeFullyLive = false; | 1391 makeArrayLike.canBeFullyLive = false; |
1429 })(); | 1392 })(); |
1430 } | 1393 } |
1431 })(); | 1394 })(); |
1432 | 1395 |
1433 | 1396 |
1434 global.cajaVM = { // don't freeze here | 1397 global.cajaVM = { // don't freeze here |
1435 // Note that properties defined on cajaVM must also be added to | 1398 // Note that properties defined on cajaVM must also be added to |
1436 // whitelist.js, or they will be deleted. | 1399 // whitelist.js, or they will be deleted. |
1437 | 1400 |
1438 // Here we make available by name those intrinsics which would | |
1439 // otherwise be accessible, but are not otherwise accessible by | |
1440 // a naming path, starting from available roots, traversing | |
1441 // through named own properties. See instrinsics in whitelist.js | |
1442 // for a complete list of those intrinsics that might eventually | |
1443 // show up here. | |
1444 intrinsics: intrinsics, | |
1445 | |
1446 /** | 1401 /** |
1447 * This is about to be deprecated once we expose ses.logger. | 1402 * This is about to be deprecated once we expose ses.logger. |
1448 * | 1403 * |
1449 * <p>In the meantime, privileged code should use ses.logger.log | 1404 * <p>In the meantime, privileged code should use ses.logger.log |
1450 * instead of cajaVM.log. | 1405 * instead of cajaVM.log. |
1451 */ | 1406 */ |
1452 log: constFunc(function log(str) { | 1407 log: constFunc(function log(str) { |
1453 if (typeof console !== 'undefined' && 'log' in console) { | 1408 if (typeof console !== 'undefined' && 'log' in console) { |
1454 // We no longer test (typeof console.log === 'function') since, | 1409 // We no longer test (typeof console.log === 'function') since, |
1455 // on IE9 and IE10preview, in violation of the ES5 spec, it | 1410 // on IE9 and IE10preview, in violation of the ES5 spec, it |
1456 // is callable but has typeof "object". See | 1411 // is callable but has typeof "object". See |
1457 // https://connect.microsoft.com/IE/feedback/details/685962/ | 1412 // https://connect.microsoft.com/IE/feedback/details/685962/ |
1458 // console-log-and-others-are-callable-but-arent-typeof-function | 1413 // console-log-and-others-are-callable-but-arent-typeof-function |
1459 console.log(str); | 1414 console.log(str); |
1460 } | 1415 } |
1461 }), | 1416 }), |
1462 tamperProof: constFunc(tamperProof), | 1417 tamperProof: constFunc(tamperProof), |
1463 constFunc: constFunc(constFunc), | 1418 constFunc: constFunc(constFunc), |
1464 Nat: constFunc(Nat), | 1419 Nat: constFunc(Nat), |
1465 // def: see below | 1420 // def: see below |
1466 is: constFunc(ses.is), | 1421 is: constFunc(ses.is), |
1467 | 1422 |
1468 compileExpr: constFunc(compileExpr), | 1423 compileExpr: constFunc(compileExpr), |
1469 confine: constFunc(confine), | 1424 confine: constFunc(confine), |
1470 compileModule: constFunc(compileModule), | 1425 compileModule: constFunc(compileModule), |
1471 // compileProgram: compileProgram, // Cannot be implemented in ES5.1. | 1426 // compileProgram: compileProgram, // Cannot be implemented in ES5.1. |
1472 eval: fakeEval, // don't freeze here | 1427 eval: fakeEval, // don't freeze here |
1473 Function: FakeFunction, // don't freeze here, | 1428 Function: global.Function, // don't freeze here, |
1474 | 1429 |
1475 sharedImports: sharedImports, // don't freeze here | 1430 sharedImports: sharedImports, // don't freeze here |
1476 makeImports: constFunc(makeImports), | 1431 makeImports: constFunc(makeImports), |
1477 copyToImports: constFunc(copyToImports), | 1432 copyToImports: constFunc(copyToImports), |
1478 | 1433 |
1479 makeArrayLike: constFunc(makeArrayLike) | 1434 makeArrayLike: constFunc(makeArrayLike) |
1480 | 1435 |
1481 // Not defined here because it cannot be whitelisted; see assignment and | 1436 // Not defined here because it cannot be whitelisted; see assignment and |
1482 // comments below. | 1437 // comments below. |
1483 //es5ProblemReports: ses.es5ProblemReports | 1438 //es5ProblemReports: ses.es5ProblemReports |
1484 }; | 1439 }; |
1485 | 1440 |
| 1441 if (ses.es5ProblemReports.GENERATORFUNCTION_CANNOT_BE_DENIED.afterFailure) { |
| 1442 global.cajaVM.anonIntrinsics = {}; |
| 1443 } else { |
| 1444 // Here we make available by name those intrinsics which would |
| 1445 // otherwise be accessible, but are not otherwise accessible by |
| 1446 // a naming path, starting from available roots, traversing |
| 1447 // through named own properties. See instrinsics in whitelist.js |
| 1448 // for a complete list of those intrinsics that might eventually |
| 1449 // show up here. |
| 1450 // |
| 1451 // The Object.freeze here ensures that if |
| 1452 // ses.getAnonIntrinsics() returns intrinsics not listed in |
| 1453 // the whitelist, then clean will fail rather than silently |
| 1454 // removing them. |
| 1455 global.cajaVM.anonIntrinsics = Object.freeze(ses.getAnonIntrinsics()); |
| 1456 } |
1486 | 1457 |
1487 var extensionsRecord = extensions(); | 1458 var extensionsRecord = extensions(); |
1488 gopn(extensionsRecord).forEach(function (p) { | 1459 gopn(extensionsRecord).forEach(function (p) { |
1489 defProp(cajaVM, p, | 1460 defProp(cajaVM, p, |
1490 gopd(extensionsRecord, p)); | 1461 gopd(extensionsRecord, p)); |
1491 }); | 1462 }); |
1492 | 1463 |
1493 // Move this down here so it is not available during the call to | 1464 // Move this down here so it is not available during the call to |
1494 // extensions(). | 1465 // extensions(). |
1495 global.cajaVM.def = constFunc(def); | 1466 global.cajaVM.def = constFunc(def); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1566 | 1537 |
1567 /** | 1538 /** |
1568 * The whiteTable should map from each path-accessible primordial | 1539 * The whiteTable should map from each path-accessible primordial |
1569 * object to the permit object that describes how it should be | 1540 * object to the permit object that describes how it should be |
1570 * cleaned. | 1541 * cleaned. |
1571 * | 1542 * |
1572 * We initialize the whiteTable only so that {@code getPermit} can | 1543 * We initialize the whiteTable only so that {@code getPermit} can |
1573 * process "*" inheritance using the whitelist, by walking actual | 1544 * process "*" inheritance using the whitelist, by walking actual |
1574 * inheritance chains. | 1545 * inheritance chains. |
1575 */ | 1546 */ |
1576 var whitelistSymbols = [true, '*', 'maybeAccessor']; | 1547 var whitelistSymbols = [true, false, '*', 'maybeAccessor']; |
1577 var whiteTable = new WeakMap(); | 1548 var whiteTable = new WeakMap(); |
1578 function register(value, permit) { | 1549 function register(value, permit) { |
1579 if (value !== Object(value)) { return; } | 1550 if (value !== Object(value)) { return; } |
1580 if (typeof permit !== 'object') { | 1551 if (typeof permit !== 'object') { |
1581 if (whitelistSymbols.indexOf(permit) < 0) { | 1552 if (whitelistSymbols.indexOf(permit) < 0) { |
1582 fail('syntax error in whitelist; unexpected value: ' + permit); | 1553 fail('syntax error in whitelist; unexpected value: ' + permit); |
1583 } | 1554 } |
1584 return; | 1555 return; |
1585 } | 1556 } |
1586 var oldPermit = whiteTable.get(value); | 1557 if (whiteTable.has(value)) { |
1587 if (oldPermit) { | |
1588 fail('primordial reachable through multiple paths'); | 1558 fail('primordial reachable through multiple paths'); |
1589 } | 1559 } |
1590 whiteTable.set(value, permit); | 1560 whiteTable.set(value, permit); |
1591 keys(permit).forEach(function(name) { | 1561 keys(permit).forEach(function(name) { |
1592 // Use gopd to avoid invoking an accessor property. | 1562 // Use gopd to avoid invoking an accessor property. |
1593 // Accessor properties for which permit !== 'maybeAccessor' | 1563 // Accessor properties for which permit !== 'maybeAccessor' |
1594 // are caught later by clean(). | 1564 // are caught later by clean(). |
1595 var desc = gopd(value, name); | 1565 var desc = gopd(value, name); |
1596 if (desc) { | 1566 if (desc) { |
1597 register(desc.value, permit[name]); | 1567 register(desc.value, permit[name]); |
1598 } | 1568 } |
1599 }); | 1569 }); |
1600 } | 1570 } |
1601 register(sharedImports, whitelist); | 1571 register(sharedImports, whitelist); |
1602 | 1572 |
1603 /** | 1573 /** |
1604 * Should the property named {@code name} be whitelisted on the | 1574 * Should the property named {@code name} be whitelisted on the |
1605 * {@code base} object, and if so, with what Permit? | 1575 * {@code base} object, and if so, with what Permit? |
1606 * | 1576 * |
1607 * <p>If it should be permitted, return the Permit (where Permit = | 1577 * <p>If it should be permitted, return the Permit (where Permit = |
1608 * true | "accessor" | "*" | Record(Permit)), all of which are | 1578 * true | "maybeAccessor" | "*" | Record(Permit)), all of which are |
1609 * truthy. If it should not be permitted, return false. | 1579 * truthy. If it should not be permitted, return false. |
1610 */ | 1580 */ |
1611 function getPermit(base, name) { | 1581 function getPermit(base, name) { |
1612 var permit = whiteTable.get(base); | 1582 var permit = whiteTable.get(base); |
1613 if (permit) { | 1583 if (permit) { |
1614 if (hop.call(permit, name)) { return permit[name]; } | 1584 if (hop.call(permit, name)) { return permit[name]; } |
1615 } | 1585 } |
1616 while (true) { | 1586 while (true) { |
1617 base = getProto(base); | 1587 base = getProto(base); |
1618 if (base === null) { return false; } | 1588 if (base === null) { return false; } |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1814 | 1784 |
1815 // This protection is now gathered here, so that a future version | 1785 // This protection is now gathered here, so that a future version |
1816 // can skip it for non-defensive frames that must only be confined. | 1786 // can skip it for non-defensive frames that must only be confined. |
1817 cajaVM.def(sharedImports); | 1787 cajaVM.def(sharedImports); |
1818 | 1788 |
1819 // Internal communication back to repairES5 repairs that need to know if | 1789 // Internal communication back to repairES5 repairs that need to know if |
1820 // things have been frozen. TODO(kpreid): Consider making this more specific | 1790 // things have been frozen. TODO(kpreid): Consider making this more specific |
1821 // (identifying the actually frozen objects) if that doesn't cost too much. | 1791 // (identifying the actually frozen objects) if that doesn't cost too much. |
1822 ses._primordialsHaveBeenFrozen = true; | 1792 ses._primordialsHaveBeenFrozen = true; |
1823 | 1793 |
1824 // The following objects are ambiently available via language constructs, and | 1794 (function() { |
1825 // therefore if we did not clean and defend them we have a problem. This is | 1795 // These objects are ambiently available via language |
1826 // defense against mistakes in modifying the whitelist, not against browser | 1796 // constructs, and therefore if we did not clean and defend them |
1827 // bugs. | 1797 // we have a problem. This is defense against mistakes in |
1828 var undeniables = [ | 1798 // modifying the whitelist, not against browser bugs. |
1829 ['%ThrowTypeError%', intrinsics.ThrowTypeError], // function literals | 1799 var undeniables = ses.getUndeniables(); |
1830 ['Array.prototype', Array.prototype], // [], gOPN etc. | 1800 |
1831 ['Boolean.prototype', Boolean.prototype], // false, true | 1801 // This will catch if the result of cleaning somehow changed the |
1832 ['Function.prototype', Function.prototype], // function(){} | 1802 // result of gathering undeniables, which, because they are |
1833 ['Number.prototype', Number.prototype], // 1, 2 | 1803 // undeniable, should have been invariant across all those |
1834 ['Object.prototype', Object.prototype], // {}, gOPD | 1804 // cleaning steps. |
1835 ['RegExp.prototype', RegExp.prototype], // /.../ | 1805 var undeniableNames = Object.keys(undeniables); |
1836 ['String.prototype', String.prototype] // "..." | 1806 if (undeniableNames.length !== Object.keys(ses.earlyUndeniables).length) { |
1837 ]; | 1807 // By first ensuring that the number of undeniables is the same, |
1838 if (intrinsics.GeneratorFunction) { | 1808 // the following test cannot names in earlyUndeniables that are |
1839 undeniables.push(['%GeneratorFunction%.prototype', | 1809 // absent from undeniables. |
1840 intrinsics.GeneratorFunction.prototype]); | |
1841 } | |
1842 if (intrinsics.IteratorPrototype) { | |
1843 // Not clear that this could be undeniable | |
1844 undeniables.push(['%IteratorPrototype%', | |
1845 intrinsics.IteratorPrototype]); | |
1846 } | |
1847 undeniables.forEach(function(record) { | |
1848 var name = record[0]; | |
1849 var root = record[1]; | |
1850 if (!cleaning.has(root)) { | |
1851 reportItemProblem(rootReports, ses.severities.NOT_ISOLATED, | 1810 reportItemProblem(rootReports, ses.severities.NOT_ISOLATED, |
1852 'Not cleaned', name); | 1811 'Number of undeniables changed'); |
1853 } | 1812 } |
1854 if (!Object.isFrozen(root)) { | 1813 undeniableNames.forEach(function(name) { |
1855 reportItemProblem(rootReports, ses.severities.NOT_ISOLATED, | 1814 var undeniable = undeniables[name]; |
1856 'Not frozen', name); | 1815 if (undeniable !== ses.earlyUndeniables[name]) { |
1857 } | 1816 reportItemProblem(rootReports, ses.severities.NOT_ISOLATED, |
1858 }); | 1817 'Undeniable "' + name + '" changed'); |
| 1818 } |
| 1819 if (!cleaning.has(undeniable)) { |
| 1820 reportItemProblem(rootReports, ses.severities.NOT_ISOLATED, |
| 1821 'Not cleaned', name); |
| 1822 } |
| 1823 if (!Object.isFrozen(undeniable)) { |
| 1824 reportItemProblem(rootReports, ses.severities.NOT_ISOLATED, |
| 1825 'Not frozen', name); |
| 1826 } |
| 1827 }); |
| 1828 }()); |
1859 | 1829 |
1860 logReports(propertyReports); | 1830 logReports(propertyReports); |
1861 logReports(rootReports); | 1831 logReports(rootReports); |
1862 | 1832 |
1863 // This repair cannot be fully tested until after Object.prototype is frozen. | 1833 // This repair cannot be fully tested until after Object.prototype is frozen. |
1864 // TODO(kpreid): Less one-off kludge for this one problem -- or, once the | 1834 // TODO(kpreid): Less one-off kludge for this one problem -- or, once the |
1865 // problem is obsolete, delete all this code. | 1835 // problem is obsolete, delete all this code. |
1866 // (We cannot reuse any infrastructure from repairES5 because it is not | 1836 // (We cannot reuse any infrastructure from repairES5 because it is not |
1867 // exported.) | 1837 // exported.) |
1868 var result; | 1838 var result; |
(...skipping 14 matching lines...) Expand all Loading... |
1883 // We succeeded. Enable safe Function, eval, and compile* to work. | 1853 // We succeeded. Enable safe Function, eval, and compile* to work. |
1884 // TODO(kpreid): This separate 'dirty' flag should be replaced with | 1854 // TODO(kpreid): This separate 'dirty' flag should be replaced with |
1885 // a problem registered with ses._repairer, so that ses.ok() itself | 1855 // a problem registered with ses._repairer, so that ses.ok() itself |
1886 // gives the whole answer. | 1856 // gives the whole answer. |
1887 dirty = false; | 1857 dirty = false; |
1888 ses.logger.log('initSES succeeded.'); | 1858 ses.logger.log('initSES succeeded.'); |
1889 } else { | 1859 } else { |
1890 ses.logger.error('initSES failed.'); | 1860 ses.logger.error('initSES failed.'); |
1891 } | 1861 } |
1892 }; | 1862 }; |
LEFT | RIGHT |