js/src/jswrapper.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef jswrapper_h
michael@0 8 #define jswrapper_h
michael@0 9
michael@0 10 #include "mozilla/Attributes.h"
michael@0 11
michael@0 12 #include "jsproxy.h"
michael@0 13
michael@0 14 namespace js {
michael@0 15
michael@0 16 class DummyFrameGuard;
michael@0 17
michael@0 18 /*
michael@0 19 * Helper for Wrapper::New default options.
michael@0 20 *
michael@0 21 * Callers of Wrapper::New() who wish to specify a prototype for the created
michael@0 22 * Wrapper, *MUST* construct a WrapperOptions with a JSContext.
michael@0 23 */
michael@0 24 class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
michael@0 25 public:
michael@0 26 WrapperOptions() : ProxyOptions(false, nullptr),
michael@0 27 proto_()
michael@0 28 {}
michael@0 29
michael@0 30 WrapperOptions(JSContext *cx) : ProxyOptions(false, nullptr),
michael@0 31 proto_()
michael@0 32 {
michael@0 33 proto_.construct(cx);
michael@0 34 }
michael@0 35
michael@0 36 inline JSObject *proto() const;
michael@0 37 WrapperOptions &setProto(JSObject *protoArg) {
michael@0 38 JS_ASSERT(!proto_.empty());
michael@0 39 proto_.ref() = protoArg;
michael@0 40 return *this;
michael@0 41 }
michael@0 42
michael@0 43 private:
michael@0 44 mozilla::Maybe<JS::RootedObject> proto_;
michael@0 45 };
michael@0 46
michael@0 47 /*
michael@0 48 * A wrapper is a proxy with a target object to which it generally forwards
michael@0 49 * operations, but may restrict access to certain operations or instrument
michael@0 50 * the trap operations in various ways. A wrapper is distinct from a Direct Proxy
michael@0 51 * Handler in the sense that it can be "unwrapped" in C++, exposing the underlying
michael@0 52 * object (Direct Proxy Handlers have an underlying target object, but don't
michael@0 53 * expect to expose this object via any kind of unwrapping operation). Callers
michael@0 54 * should be careful to avoid unwrapping security wrappers in the wrong context.
michael@0 55 */
michael@0 56 class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
michael@0 57 {
michael@0 58 unsigned mFlags;
michael@0 59
michael@0 60 public:
michael@0 61 using BaseProxyHandler::Action;
michael@0 62
michael@0 63 enum Flags {
michael@0 64 CROSS_COMPARTMENT = 1 << 0,
michael@0 65 LAST_USED_FLAG = CROSS_COMPARTMENT
michael@0 66 };
michael@0 67
michael@0 68 virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
michael@0 69 MutableHandleValue vp) MOZ_OVERRIDE;
michael@0 70
michael@0 71 static JSObject *New(JSContext *cx, JSObject *obj, JSObject *parent, Wrapper *handler,
michael@0 72 const WrapperOptions *options = nullptr);
michael@0 73
michael@0 74 static JSObject *Renew(JSContext *cx, JSObject *existing, JSObject *obj, Wrapper *handler);
michael@0 75
michael@0 76 static Wrapper *wrapperHandler(JSObject *wrapper);
michael@0 77
michael@0 78 static JSObject *wrappedObject(JSObject *wrapper);
michael@0 79
michael@0 80 unsigned flags() const {
michael@0 81 return mFlags;
michael@0 82 }
michael@0 83
michael@0 84 explicit Wrapper(unsigned flags, bool hasPrototype = false);
michael@0 85
michael@0 86 virtual ~Wrapper();
michael@0 87
michael@0 88 virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE;
michael@0 89
michael@0 90 static Wrapper singleton;
michael@0 91 static Wrapper singletonWithPrototype;
michael@0 92
michael@0 93 static JSObject *defaultProto;
michael@0 94 };
michael@0 95
michael@0 96 inline JSObject *
michael@0 97 WrapperOptions::proto() const
michael@0 98 {
michael@0 99 return proto_.empty() ? Wrapper::defaultProto : proto_.ref();
michael@0 100 }
michael@0 101
michael@0 102 /* Base class for all cross compartment wrapper handlers. */
michael@0 103 class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
michael@0 104 {
michael@0 105 public:
michael@0 106 CrossCompartmentWrapper(unsigned flags, bool hasPrototype = false);
michael@0 107
michael@0 108 virtual ~CrossCompartmentWrapper();
michael@0 109
michael@0 110 /* ES5 Harmony fundamental wrapper traps. */
michael@0 111 virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) MOZ_OVERRIDE;
michael@0 112 virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
michael@0 113 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
michael@0 114 virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
michael@0 115 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
michael@0 116 virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
michael@0 117 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
michael@0 118 virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
michael@0 119 AutoIdVector &props) MOZ_OVERRIDE;
michael@0 120 virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
michael@0 121 virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
michael@0 122
michael@0 123 /* ES5 Harmony derived wrapper traps. */
michael@0 124 virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
michael@0 125 virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
michael@0 126 virtual bool get(JSContext *cx, HandleObject wrapper, HandleObject receiver,
michael@0 127 HandleId id, MutableHandleValue vp) MOZ_OVERRIDE;
michael@0 128 virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver,
michael@0 129 HandleId id, bool strict, MutableHandleValue vp) MOZ_OVERRIDE;
michael@0 130 virtual bool keys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
michael@0 131 virtual bool iterate(JSContext *cx, HandleObject wrapper, unsigned flags,
michael@0 132 MutableHandleValue vp) MOZ_OVERRIDE;
michael@0 133
michael@0 134 /* Spidermonkey extensions. */
michael@0 135 virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) MOZ_OVERRIDE;
michael@0 136 virtual bool call(JSContext *cx, HandleObject wrapper, const CallArgs &args) MOZ_OVERRIDE;
michael@0 137 virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) MOZ_OVERRIDE;
michael@0 138 virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
michael@0 139 CallArgs args) MOZ_OVERRIDE;
michael@0 140 virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v,
michael@0 141 bool *bp) MOZ_OVERRIDE;
michael@0 142 virtual const char *className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
michael@0 143 virtual JSString *fun_toString(JSContext *cx, HandleObject wrapper,
michael@0 144 unsigned indent) MOZ_OVERRIDE;
michael@0 145 virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
michael@0 146 virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
michael@0 147 MutableHandleValue vp) MOZ_OVERRIDE;
michael@0 148 virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
michael@0 149 MutableHandleObject protop) MOZ_OVERRIDE;
michael@0 150 virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
michael@0 151 bool *bp) MOZ_OVERRIDE;
michael@0 152
michael@0 153 static CrossCompartmentWrapper singleton;
michael@0 154 static CrossCompartmentWrapper singletonWithPrototype;
michael@0 155 };
michael@0 156
michael@0 157 /*
michael@0 158 * Base class for security wrappers. A security wrapper is potentially hiding
michael@0 159 * all or part of some wrapped object thus SecurityWrapper defaults to denying
michael@0 160 * access to the wrappee. This is the opposite of Wrapper which tries to be
michael@0 161 * completely transparent.
michael@0 162 *
michael@0 163 * NB: Currently, only a few ProxyHandler operations are overridden to deny
michael@0 164 * access, relying on derived SecurityWrapper to block access when necessary.
michael@0 165 */
michael@0 166 template <class Base>
michael@0 167 class JS_FRIEND_API(SecurityWrapper) : public Base
michael@0 168 {
michael@0 169 public:
michael@0 170 SecurityWrapper(unsigned flags);
michael@0 171
michael@0 172 virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) MOZ_OVERRIDE;
michael@0 173 virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) MOZ_OVERRIDE;
michael@0 174 virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Wrapper::Action act,
michael@0 175 bool *bp) MOZ_OVERRIDE;
michael@0 176 virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
michael@0 177 CallArgs args) MOZ_OVERRIDE;
michael@0 178 virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
michael@0 179 MutableHandleValue vp) MOZ_OVERRIDE;
michael@0 180 virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
michael@0 181 JSContext *cx) MOZ_OVERRIDE;
michael@0 182 virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
michael@0 183 virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
michael@0 184 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
michael@0 185
michael@0 186 virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
michael@0 187 bool *bp) MOZ_OVERRIDE;
michael@0 188
michael@0 189 virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
michael@0 190 JS::HandleObject callable) MOZ_OVERRIDE;
michael@0 191 virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) MOZ_OVERRIDE;
michael@0 192
michael@0 193 /*
michael@0 194 * Allow our subclasses to select the superclass behavior they want without
michael@0 195 * needing to specify an exact superclass.
michael@0 196 */
michael@0 197 typedef Base Permissive;
michael@0 198 typedef SecurityWrapper<Base> Restrictive;
michael@0 199 };
michael@0 200
michael@0 201 typedef SecurityWrapper<Wrapper> SameCompartmentSecurityWrapper;
michael@0 202 typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
michael@0 203
michael@0 204 class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
michael@0 205 {
michael@0 206 public:
michael@0 207 // This variable exists solely to provide a unique address for use as an identifier.
michael@0 208 static const char sDeadObjectFamily;
michael@0 209
michael@0 210 explicit DeadObjectProxy();
michael@0 211
michael@0 212 /* ES5 Harmony fundamental wrapper traps. */
michael@0 213 virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
michael@0 214 virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
michael@0 215 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
michael@0 216 virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
michael@0 217 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
michael@0 218 virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
michael@0 219 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
michael@0 220 virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
michael@0 221 AutoIdVector &props) MOZ_OVERRIDE;
michael@0 222 virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
michael@0 223 virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
michael@0 224
michael@0 225 /* Spidermonkey extensions. */
michael@0 226 virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
michael@0 227 virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
michael@0 228 virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
michael@0 229 virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
michael@0 230 CallArgs args) MOZ_OVERRIDE;
michael@0 231 virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
michael@0 232 bool *bp) MOZ_OVERRIDE;
michael@0 233 virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
michael@0 234 JSContext *cx) MOZ_OVERRIDE;
michael@0 235 virtual const char *className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
michael@0 236 virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) MOZ_OVERRIDE;
michael@0 237 virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
michael@0 238 virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
michael@0 239 MutableHandleValue vp) MOZ_OVERRIDE;
michael@0 240 virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
michael@0 241 MutableHandleObject protop) MOZ_OVERRIDE;
michael@0 242
michael@0 243 static DeadObjectProxy singleton;
michael@0 244 };
michael@0 245
michael@0 246 extern JSObject *
michael@0 247 TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
michael@0 248 HandleObject wrappedProto, HandleObject parent,
michael@0 249 unsigned flags);
michael@0 250
michael@0 251 // Proxy family for wrappers. Public so that IsWrapper() can be fully inlined by
michael@0 252 // jsfriendapi users.
michael@0 253 // This variable exists solely to provide a unique address for use as an identifier.
michael@0 254 extern JS_FRIEND_DATA(const char) sWrapperFamily;
michael@0 255
michael@0 256 inline bool
michael@0 257 IsWrapper(JSObject *obj)
michael@0 258 {
michael@0 259 return IsProxy(obj) && GetProxyHandler(obj)->family() == &sWrapperFamily;
michael@0 260 }
michael@0 261
michael@0 262 // Given a JSObject, returns that object stripped of wrappers. If
michael@0 263 // stopAtOuter is true, then this returns the outer window if it was
michael@0 264 // previously wrapped. Otherwise, this returns the first object for
michael@0 265 // which JSObject::isWrapper returns false.
michael@0 266 JS_FRIEND_API(JSObject *)
michael@0 267 UncheckedUnwrap(JSObject *obj, bool stopAtOuter = true, unsigned *flagsp = nullptr);
michael@0 268
michael@0 269 // Given a JSObject, returns that object stripped of wrappers. At each stage,
michael@0 270 // the security wrapper has the opportunity to veto the unwrap. Since checked
michael@0 271 // code should never be unwrapping outer window wrappers, we always stop at
michael@0 272 // outer windows.
michael@0 273 JS_FRIEND_API(JSObject *)
michael@0 274 CheckedUnwrap(JSObject *obj, bool stopAtOuter = true);
michael@0 275
michael@0 276 // Unwrap only the outermost security wrapper, with the same semantics as
michael@0 277 // above. This is the checked version of Wrapper::wrappedObject.
michael@0 278 JS_FRIEND_API(JSObject *)
michael@0 279 UnwrapOneChecked(JSObject *obj, bool stopAtOuter = true);
michael@0 280
michael@0 281 JS_FRIEND_API(bool)
michael@0 282 IsCrossCompartmentWrapper(JSObject *obj);
michael@0 283
michael@0 284 bool
michael@0 285 IsDeadProxyObject(JSObject *obj);
michael@0 286
michael@0 287 JSObject *
michael@0 288 NewDeadProxyObject(JSContext *cx, JSObject *parent,
michael@0 289 const ProxyOptions &options = ProxyOptions());
michael@0 290
michael@0 291 void
michael@0 292 NukeCrossCompartmentWrapper(JSContext *cx, JSObject *wrapper);
michael@0 293
michael@0 294 bool
michael@0 295 RemapWrapper(JSContext *cx, JSObject *wobj, JSObject *newTarget);
michael@0 296
michael@0 297 JS_FRIEND_API(bool)
michael@0 298 RemapAllWrappersForObject(JSContext *cx, JSObject *oldTarget,
michael@0 299 JSObject *newTarget);
michael@0 300
michael@0 301 // API to recompute all cross-compartment wrappers whose source and target
michael@0 302 // match the given filters.
michael@0 303 JS_FRIEND_API(bool)
michael@0 304 RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter,
michael@0 305 const CompartmentFilter &targetFilter);
michael@0 306
michael@0 307 /*
michael@0 308 * This auto class should be used around any code, such as brain transplants,
michael@0 309 * that may touch dead zones. Brain transplants can cause problems
michael@0 310 * because they operate on all compartments, whether live or dead. A brain
michael@0 311 * transplant can cause a formerly dead object to be "reanimated" by causing a
michael@0 312 * read or write barrier to be invoked on it during the transplant. In this way,
michael@0 313 * a zone becomes a zombie, kept alive by repeatedly consuming
michael@0 314 * (transplanted) brains.
michael@0 315 *
michael@0 316 * To work around this issue, we observe when mark bits are set on objects in
michael@0 317 * dead zones. If this happens during a brain transplant, we do a full,
michael@0 318 * non-incremental GC at the end of the brain transplant. This will clean up any
michael@0 319 * objects that were improperly marked.
michael@0 320 */
michael@0 321 struct JS_FRIEND_API(AutoMaybeTouchDeadZones)
michael@0 322 {
michael@0 323 // The version that takes an object just uses it for its runtime.
michael@0 324 AutoMaybeTouchDeadZones(JSContext *cx);
michael@0 325 AutoMaybeTouchDeadZones(JSObject *obj);
michael@0 326 ~AutoMaybeTouchDeadZones();
michael@0 327
michael@0 328 private:
michael@0 329 JSRuntime *runtime;
michael@0 330 unsigned markCount;
michael@0 331 bool inIncremental;
michael@0 332 bool manipulatingDeadZones;
michael@0 333 };
michael@0 334
michael@0 335 } /* namespace js */
michael@0 336
michael@0 337 #endif /* jswrapper_h */

mercurial