Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/js/Wrapper.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
 * vim: set ts=8 sts=4 et sw=4 tw=99:
3
 * This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef js_Wrapper_h
8
#define js_Wrapper_h
9
10
#include "mozilla/Attributes.h"
11
12
#include "js/Proxy.h"
13
14
namespace js {
15
16
/*
17
 * Helper for Wrapper::New default options.
18
 *
19
 * Callers of Wrapper::New() who wish to specify a prototype for the created
20
 * Wrapper, *MUST* construct a WrapperOptions with a JSContext.
21
 */
22
class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
23
  public:
24
    WrapperOptions() : ProxyOptions(false),
25
                       proto_()
26
0
    {}
27
28
    explicit WrapperOptions(JSContext* cx) : ProxyOptions(false),
29
                                             proto_()
30
0
    {
31
0
        proto_.emplace(cx);
32
0
    }
33
34
    inline JSObject* proto() const;
35
0
    WrapperOptions& setProto(JSObject* protoArg) {
36
0
        MOZ_ASSERT(proto_);
37
0
        *proto_ = protoArg;
38
0
        return *this;
39
0
    }
40
41
  private:
42
    mozilla::Maybe<JS::RootedObject> proto_;
43
};
44
45
// Base class for proxy handlers that want to forward all operations to an
46
// object stored in the proxy's private slot.
47
class JS_FRIEND_API(ForwardingProxyHandler) : public BaseProxyHandler
48
{
49
  public:
50
    using BaseProxyHandler::BaseProxyHandler;
51
52
    /* Standard internal methods. */
53
    virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
54
                                          MutableHandle<PropertyDescriptor> desc) const override;
55
    virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
56
                                Handle<PropertyDescriptor> desc,
57
                                ObjectOpResult& result) const override;
58
    virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
59
                                 AutoIdVector& props) const override;
60
    virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
61
                         ObjectOpResult& result) const override;
62
    virtual JSObject* enumerate(JSContext* cx, HandleObject proxy) const override;
63
    virtual bool getPrototype(JSContext* cx, HandleObject proxy,
64
                              MutableHandleObject protop) const override;
65
    virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
66
                              ObjectOpResult& result) const override;
67
    virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
68
                                        MutableHandleObject protop) const override;
69
    virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
70
                                       bool* succeeded) const override;
71
    virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
72
                                   ObjectOpResult& result) const override;
73
    virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
74
    virtual bool has(JSContext* cx, HandleObject proxy, HandleId id,
75
                     bool* bp) const override;
76
    virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
77
                     HandleId id, MutableHandleValue vp) const override;
78
    virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
79
                     HandleValue receiver, ObjectOpResult& result) const override;
80
    virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
81
    virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
82
83
    /* SpiderMonkey extensions. */
84
    virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
85
                                       MutableHandle<PropertyDescriptor> desc) const override;
86
    virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
87
                        bool* bp) const override;
88
    virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
89
                                              AutoIdVector& props) const override;
90
    virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
91
                            const CallArgs& args) const override;
92
    virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
93
                             bool* bp) const override;
94
    virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
95
    virtual bool isArray(JSContext* cx, HandleObject proxy,
96
                         JS::IsArrayAnswer* answer) const override;
97
    virtual const char* className(JSContext* cx, HandleObject proxy) const override;
98
    virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
99
                                   bool isToSource) const override;
100
    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
101
    virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
102
                                  MutableHandleValue vp) const override;
103
    virtual bool isCallable(JSObject* obj) const override;
104
    virtual bool isConstructor(JSObject* obj) const override;
105
};
106
107
/*
108
 * A wrapper is a proxy with a target object to which it generally forwards
109
 * operations, but may restrict access to certain operations or augment those
110
 * operations in various ways.
111
 *
112
 * A wrapper can be "unwrapped" in C++, exposing the underlying object.
113
 * Callers should be careful to avoid unwrapping security wrappers in the wrong
114
 * context.
115
 *
116
 * Important: If you add a method implementation here, you probably also need
117
 * to add an override in CrossCompartmentWrapper. If you don't, you risk
118
 * compartment mismatches. See bug 945826 comment 0.
119
 */
120
class JS_FRIEND_API(Wrapper) : public ForwardingProxyHandler
121
{
122
    unsigned mFlags;
123
124
  public:
125
    explicit constexpr Wrapper(unsigned aFlags, bool aHasPrototype = false,
126
                               bool aHasSecurityPolicy = false)
127
      : ForwardingProxyHandler(&family, aHasPrototype, aHasSecurityPolicy),
128
        mFlags(aFlags)
129
0
    { }
130
131
    virtual bool finalizeInBackground(const Value& priv) const override;
132
    virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override;
133
134
    using BaseProxyHandler::Action;
135
136
    enum Flags {
137
        CROSS_COMPARTMENT = 1 << 0,
138
        LAST_USED_FLAG = CROSS_COMPARTMENT
139
    };
140
141
    static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
142
                         const WrapperOptions& options = WrapperOptions());
143
144
    static JSObject* Renew(JSObject* existing, JSObject* obj, const Wrapper* handler);
145
146
    static inline const Wrapper* wrapperHandler(const JSObject* wrapper);
147
148
    static JSObject* wrappedObject(JSObject* wrapper);
149
150
0
    unsigned flags() const {
151
0
        return mFlags;
152
0
    }
153
154
    static const char family;
155
    static const Wrapper singleton;
156
    static const Wrapper singletonWithPrototype;
157
158
    static JSObject* const defaultProto;
159
};
160
161
inline JSObject*
162
WrapperOptions::proto() const
163
0
{
164
0
    return proto_ ? *proto_ : Wrapper::defaultProto;
165
0
}
166
167
/* Base class for all cross compartment wrapper handlers. */
168
class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
169
{
170
  public:
171
    explicit constexpr CrossCompartmentWrapper(unsigned aFlags, bool aHasPrototype = false,
172
                                                   bool aHasSecurityPolicy = false)
173
      : Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy)
174
0
    { }
175
176
    /* Standard internal methods. */
177
    virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
178
                                          MutableHandle<PropertyDescriptor> desc) const override;
179
    virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
180
                                Handle<PropertyDescriptor> desc,
181
                                ObjectOpResult& result) const override;
182
    virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
183
                                 AutoIdVector& props) const override;
184
    virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
185
                         ObjectOpResult& result) const override;
186
    virtual JSObject* enumerate(JSContext* cx, HandleObject wrapper) const override;
187
    virtual bool getPrototype(JSContext* cx, HandleObject proxy,
188
                              MutableHandleObject protop) const override;
189
    virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
190
                              ObjectOpResult& result) const override;
191
192
    virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
193
                                        MutableHandleObject protop) const override;
194
    virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
195
                                       bool* succeeded) const override;
196
    virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
197
                                   ObjectOpResult& result) const override;
198
    virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
199
    virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
200
    virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
201
                     HandleId id, MutableHandleValue vp) const override;
202
    virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
203
                     HandleValue receiver, ObjectOpResult& result) const override;
204
    virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
205
    virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
206
207
    /* SpiderMonkey extensions. */
208
    virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
209
                                       MutableHandle<PropertyDescriptor> desc) const override;
210
    virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
211
    virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
212
                                              AutoIdVector& props) const override;
213
    virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
214
                            const CallArgs& args) const override;
215
    virtual bool hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v,
216
                             bool* bp) const override;
217
    virtual const char* className(JSContext* cx, HandleObject proxy) const override;
218
    virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
219
                                   bool isToSource) const override;
220
    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
221
    virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
222
223
    // Allocate CrossCompartmentWrappers in the nursery.
224
0
    virtual bool canNurseryAllocate() const override { return true; }
225
226
    static const CrossCompartmentWrapper singleton;
227
    static const CrossCompartmentWrapper singletonWithPrototype;
228
};
229
230
class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrapper
231
{
232
  public:
233
    explicit constexpr OpaqueCrossCompartmentWrapper() : CrossCompartmentWrapper(0)
234
0
    { }
235
236
    /* Standard internal methods. */
237
    virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
238
                                          MutableHandle<PropertyDescriptor> desc) const override;
239
    virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
240
                                Handle<PropertyDescriptor> desc,
241
                                ObjectOpResult& result) const override;
242
    virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
243
                                 AutoIdVector& props) const override;
244
    virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
245
                         ObjectOpResult& result) const override;
246
    virtual JSObject* enumerate(JSContext* cx, HandleObject wrapper) const override;
247
    virtual bool getPrototype(JSContext* cx, HandleObject wrapper,
248
                              MutableHandleObject protop) const override;
249
    virtual bool setPrototype(JSContext* cx, HandleObject wrapper, HandleObject proto,
250
                              ObjectOpResult& result) const override;
251
    virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject wrapper, bool* isOrdinary,
252
                                        MutableHandleObject protop) const override;
253
    virtual bool setImmutablePrototype(JSContext* cx, HandleObject wrapper,
254
                                       bool* succeeded) const override;
255
    virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
256
                                   ObjectOpResult& result) const override;
257
    virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
258
    virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id,
259
                     bool* bp) const override;
260
    virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
261
                     HandleId id, MutableHandleValue vp) const override;
262
    virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
263
                     HandleValue receiver, ObjectOpResult& result) const override;
264
    virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
265
    virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
266
267
    /* SpiderMonkey extensions. */
268
    virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
269
                                       MutableHandle<PropertyDescriptor> desc) const override;
270
    virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
271
                        bool* bp) const override;
272
    virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
273
                                              AutoIdVector& props) const override;
274
    virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
275
    virtual bool isArray(JSContext* cx, HandleObject obj,
276
                         JS::IsArrayAnswer* answer) const override;
277
    virtual const char* className(JSContext* cx, HandleObject wrapper) const override;
278
    virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
279
                                   bool isToSource) const override;
280
281
    static const OpaqueCrossCompartmentWrapper singleton;
282
};
283
284
/*
285
 * Base class for security wrappers. A security wrapper is potentially hiding
286
 * all or part of some wrapped object thus SecurityWrapper defaults to denying
287
 * access to the wrappee. This is the opposite of Wrapper which tries to be
288
 * completely transparent.
289
 *
290
 * NB: Currently, only a few ProxyHandler operations are overridden to deny
291
 * access, relying on derived SecurityWrapper to block access when necessary.
292
 */
293
template <class Base>
294
class JS_FRIEND_API(SecurityWrapper) : public Base
295
{
296
  public:
297
    explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false)
298
      : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true)
299
0
    { }
Unexecuted instantiation: js::SecurityWrapper<js::CrossCompartmentWrapper>::SecurityWrapper(unsigned int, bool)
Unexecuted instantiation: js::SecurityWrapper<js::Wrapper>::SecurityWrapper(unsigned int, bool)
300
301
    virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, Wrapper::Action act,
302
                       bool mayThrow, bool* bp) const override;
303
304
    virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
305
                                Handle<PropertyDescriptor> desc,
306
                                ObjectOpResult& result) const override;
307
    virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
308
    virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
309
                                   ObjectOpResult& result) const override;
310
    virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
311
                              ObjectOpResult& result) const override;
312
    virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override;
313
314
    virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
315
                            const CallArgs& args) const override;
316
    virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
317
    virtual bool isArray(JSContext* cx, HandleObject wrapper, JS::IsArrayAnswer* answer) const override;
318
    virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
319
    virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
320
321
    // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
322
    // against.
323
324
    /*
325
     * Allow our subclasses to select the superclass behavior they want without
326
     * needing to specify an exact superclass.
327
     */
328
    typedef Base Permissive;
329
    typedef SecurityWrapper<Base> Restrictive;
330
};
331
332
typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
333
334
extern JSObject*
335
TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj);
336
337
inline bool
338
IsWrapper(const JSObject* obj)
339
45.4M
{
340
45.4M
    return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family;
341
45.4M
}
342
343
inline bool
344
IsCrossCompartmentWrapper(const JSObject* obj)
345
17.8M
{
346
17.8M
    return IsWrapper(obj) &&
347
17.8M
           (Wrapper::wrapperHandler(obj)->flags() & Wrapper::CROSS_COMPARTMENT);
348
17.8M
}
349
350
/* static */ inline const Wrapper*
351
Wrapper::wrapperHandler(const JSObject* wrapper)
352
0
{
353
0
    MOZ_ASSERT(IsWrapper(wrapper));
354
0
    return static_cast<const Wrapper*>(GetProxyHandler(wrapper));
355
0
}
356
357
// Given a JSObject, returns that object stripped of wrappers. If
358
// stopAtWindowProxy is true, then this returns the WindowProxy if it was
359
// previously wrapped. Otherwise, this returns the first object for which
360
// JSObject::isWrapper returns false.
361
//
362
// ExposeToActiveJS is called on wrapper targets to allow gray marking
363
// assertions to work while an incremental GC is in progress, but this means
364
// that this cannot be called from the GC or off the main thread.
365
JS_FRIEND_API(JSObject*)
366
UncheckedUnwrap(JSObject* obj, bool stopAtWindowProxy = true, unsigned* flagsp = nullptr);
367
368
// Given a JSObject, returns that object stripped of wrappers. At each stage,
369
// the security wrapper has the opportunity to veto the unwrap. If
370
// stopAtWindowProxy is true, then this returns the WindowProxy if it was
371
// previously wrapped.
372
//
373
// ExposeToActiveJS is called on wrapper targets to allow gray marking
374
// assertions to work while an incremental GC is in progress, but this means
375
// that this cannot be called from the GC or off the main thread.
376
JS_FRIEND_API(JSObject*)
377
CheckedUnwrap(JSObject* obj, bool stopAtWindowProxy = true);
378
379
// Unwrap only the outermost security wrapper, with the same semantics as
380
// above. This is the checked version of Wrapper::wrappedObject.
381
JS_FRIEND_API(JSObject*)
382
UnwrapOneChecked(JSObject* obj, bool stopAtWindowProxy = true);
383
384
// Given a JSObject, returns that object stripped of wrappers. This returns the
385
// WindowProxy if it was previously wrapped.
386
//
387
// ExposeToActiveJS is not called on wrapper targets so this can be called from
388
// the GC or off the main thread.
389
JS_FRIEND_API(JSObject*)
390
UncheckedUnwrapWithoutExpose(JSObject* obj);
391
392
void
393
ReportAccessDenied(JSContext* cx);
394
395
JS_FRIEND_API(void)
396
NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper);
397
398
void
399
RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget);
400
401
JS_FRIEND_API(bool)
402
RemapAllWrappersForObject(JSContext* cx, JSObject* oldTarget,
403
                          JSObject* newTarget);
404
405
// API to recompute all cross-compartment wrappers whose source and target
406
// match the given filters.
407
JS_FRIEND_API(bool)
408
RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter,
409
                  const CompartmentFilter& targetFilter);
410
411
} /* namespace js */
412
413
#endif /* js_Wrapper_h */