forked from tc39/proposal-shadowrealm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
secreview-notes.txt
111 lines (87 loc) · 4.6 KB
/
secreview-notes.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
unscopables: with(foo) should not say that 'foo' has, e.g. hasOwnProperty
with(foo):
hasOwnProperty('bar') // should not use foo.hasOwnProperty
document[Symbol.unscopables] === ['append', 'prepend']
undeniables:
* Promise.prototype (via async function return value)
* Object.prototype
* Function.prototype
* AsyncFunction.prototype
* GeneratorFunction.prototype
* AsyncGeneratorFunction.prototype
* Array.prototype: Object.getPrototypeOf([])
* RegExp.prototype: Object.getPrototypeOf(//)
* Boolean ? : getPrototypeOf(Object(false))
* Number ?
* String ?
unconscionables
uncomprehensibles
uncorrigibles
buildOptimizer:
* scan safeGlobal, find own properties which have valid variable names
(regexp) and whose descriptors say they're unwritable and unconfigurable
* "how hard could it be?" A: unicode.
* this is merely an optimization, so limiting ourselves to valid ASCII
variable names is ok.
* this also removes the potential injection attack from getting an array
with commas in the members
test('function-unbalanced-comments', t => {
const r = Realm.makeRootRealm();
r.global.evil = 0;
const evilFunc = '// */this.evil = 666; function(a) { return b;\n ';
const f1 = new r.global.Function('a', '/*', evilFunc);
t.notEqual(r.global.evil, 666);
// we never actually invoke the function, we only parse it
t.end();
});
we need a full whitelist of paths that are allowed to be present on the
global object: we should scan and delete everything that's not on the list.
See caja src/com/google/caja/ses/whitelist.js . eg RegExp.$1
markm keeps forgetting: the alternate function constructors do not need safe
versions, even though we could make safe versions, because there is no place
to put them. Because they're evaluators they have to be per-compartment, but
they don't have global names, so there's no place to put them such that
they're reachable from the compartment.
todo: we have two enumerations of the alternate function constructors (one in
functions.js and the other in instrinsics.js), document that they must be
kept in sync
handler: shadow a frozen eval inherited from the real target. proxy
invariants only check the first level. make the proxy's target be an empty
mutable object that inherits from the safe global. so the proxy can act as if
it has the 'eval' property: the target doesn't commit to stability, so the
proxy doesn't either. we need a set trap, which sets the value on the global
rather than on the target. proxy is allowed to switch the value because the
target doesn't commit to stability. user code gets access to safe global, but
not to the proxy or the target. This also means we can change stdlib's
.eval/.Function in the frozen-realm case to be non-writable non-configurable.
todo: add tests that the user can freeze their global object.
todo: rename the base Realm class to 'BaseRealm', don't expose it as the
'Realm' in the primal realm, invoke the realm facade string (buildChildRealm)
with the primal realm's 'eval()' to build the 'Realm' that we expose in the
primal realm. Might let us avoid the weakmaps?
make the Realm *constructor* be the weakmap key, not the prototype?
Two reasons why the function. constructor of the root realm should always throw:
* the mike samuel attack: adversary-controlled data fed into an innocent
program can cause it to accidentally navigate to the root realm's funtion
constructor and then feed a string to it which is code, result is a mild
form of injection attack. The injection doesn't abuse authority, but it
causes unreviewed behavior in the realm
* getting to the constructor via the .constructor link doesn't lead to a
compartment-speciifc behavior, so if it has any non-erroneous behavior at
all, it would be invisibly incompatible, which would cause confusion. if we
can't be compatible, we should thrrow an error.
To protect the __defineGetter__ etc in accessors.js, first build the shimming
mechanism, then copy the source code of accessors.js into a shim that we
always apply. tricky: we need to include it in the root, but since shims are
inherited, we must avoid injecting it twice.
Do we need to provide two different kinds of shims? Ones that run in
rootrealms, a second that only run in compartments? 'Promise' is the example.
A: no.
shims:
* e.g. adding Promise to environment that lacks them: need to run in the
rootrealm, but compartment globals also need that name
* let compartment global inherit from its rootrealm's global?
* but not if it's not frozen
* maybe just copy *all* the properties of the rootrealm's global onto the
compartment's global. use the whitelist to populate the rootrealm's global
* we like this one