jswrapper.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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. #ifndef jswrapper_h
  7. #define jswrapper_h
  8. #include "mozilla/Attributes.h"
  9. #include "js/Proxy.h"
  10. namespace js {
  11. /*
  12. * Helper for Wrapper::New default options.
  13. *
  14. * Callers of Wrapper::New() who wish to specify a prototype for the created
  15. * Wrapper, *MUST* construct a WrapperOptions with a JSContext.
  16. */
  17. class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
  18. public:
  19. WrapperOptions() : ProxyOptions(false),
  20. proto_()
  21. {}
  22. explicit WrapperOptions(JSContext* cx) : ProxyOptions(false),
  23. proto_()
  24. {
  25. proto_.emplace(cx);
  26. }
  27. inline JSObject* proto() const;
  28. WrapperOptions& setProto(JSObject* protoArg) {
  29. MOZ_ASSERT(proto_);
  30. *proto_ = protoArg;
  31. return *this;
  32. }
  33. private:
  34. mozilla::Maybe<JS::RootedObject> proto_;
  35. };
  36. /*
  37. * A wrapper is a proxy with a target object to which it generally forwards
  38. * operations, but may restrict access to certain operations or augment those
  39. * operations in various ways.
  40. *
  41. * A wrapper can be "unwrapped" in C++, exposing the underlying object.
  42. * Callers should be careful to avoid unwrapping security wrappers in the wrong
  43. * context.
  44. *
  45. * Important: If you add a method implementation here, you probably also need
  46. * to add an override in CrossCompartmentWrapper. If you don't, you risk
  47. * compartment mismatches. See bug 945826 comment 0.
  48. */
  49. class JS_FRIEND_API(Wrapper) : public BaseProxyHandler
  50. {
  51. unsigned mFlags;
  52. public:
  53. explicit constexpr Wrapper(unsigned aFlags, bool aHasPrototype = false,
  54. bool aHasSecurityPolicy = false)
  55. : BaseProxyHandler(&family, aHasPrototype, aHasSecurityPolicy),
  56. mFlags(aFlags)
  57. { }
  58. virtual bool finalizeInBackground(const Value& priv) const override;
  59. /* Standard internal methods. */
  60. virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
  61. MutableHandle<PropertyDescriptor> desc) const override;
  62. virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
  63. Handle<PropertyDescriptor> desc,
  64. ObjectOpResult& result) const override;
  65. virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
  66. AutoIdVector& props) const override;
  67. virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
  68. ObjectOpResult& result) const override;
  69. virtual bool enumerate(JSContext* cx, HandleObject proxy,
  70. MutableHandleObject objp) const override;
  71. virtual bool getPrototype(JSContext* cx, HandleObject proxy,
  72. MutableHandleObject protop) const override;
  73. virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
  74. ObjectOpResult& result) const override;
  75. virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
  76. MutableHandleObject protop) const override;
  77. virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
  78. bool* succeeded) const override;
  79. virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
  80. ObjectOpResult& result) const override;
  81. virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
  82. virtual bool has(JSContext* cx, HandleObject proxy, HandleId id,
  83. bool* bp) const override;
  84. virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
  85. HandleId id, MutableHandleValue vp) const override;
  86. virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
  87. HandleValue receiver, ObjectOpResult& result) const override;
  88. virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
  89. virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
  90. /* SpiderMonkey extensions. */
  91. virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
  92. MutableHandle<PropertyDescriptor> desc) const override;
  93. virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
  94. bool* bp) const override;
  95. virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
  96. AutoIdVector& props) const override;
  97. virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
  98. const CallArgs& args) const override;
  99. virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
  100. bool* bp) const override;
  101. virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
  102. virtual bool isArray(JSContext* cx, HandleObject proxy,
  103. JS::IsArrayAnswer* answer) const override;
  104. virtual const char* className(JSContext* cx, HandleObject proxy) const override;
  105. virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
  106. unsigned indent) const override;
  107. virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
  108. RegExpGuard* g) const override;
  109. virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
  110. MutableHandleValue vp) const override;
  111. virtual bool isCallable(JSObject* obj) const override;
  112. virtual bool isConstructor(JSObject* obj) const override;
  113. virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override;
  114. public:
  115. using BaseProxyHandler::Action;
  116. enum Flags {
  117. CROSS_COMPARTMENT = 1 << 0,
  118. LAST_USED_FLAG = CROSS_COMPARTMENT
  119. };
  120. static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
  121. const WrapperOptions& options = WrapperOptions());
  122. static JSObject* Renew(JSContext* cx, JSObject* existing, JSObject* obj, const Wrapper* handler);
  123. static const Wrapper* wrapperHandler(JSObject* wrapper);
  124. static JSObject* wrappedObject(JSObject* wrapper);
  125. unsigned flags() const {
  126. return mFlags;
  127. }
  128. static const char family;
  129. static const Wrapper singleton;
  130. static const Wrapper singletonWithPrototype;
  131. static JSObject* defaultProto;
  132. };
  133. inline JSObject*
  134. WrapperOptions::proto() const
  135. {
  136. return proto_ ? *proto_ : Wrapper::defaultProto;
  137. }
  138. /* Base class for all cross compartment wrapper handlers. */
  139. class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
  140. {
  141. public:
  142. explicit constexpr CrossCompartmentWrapper(unsigned aFlags, bool aHasPrototype = false,
  143. bool aHasSecurityPolicy = false)
  144. : Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy)
  145. { }
  146. /* Standard internal methods. */
  147. virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
  148. MutableHandle<PropertyDescriptor> desc) const override;
  149. virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
  150. Handle<PropertyDescriptor> desc,
  151. ObjectOpResult& result) const override;
  152. virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
  153. AutoIdVector& props) const override;
  154. virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
  155. ObjectOpResult& result) const override;
  156. virtual bool enumerate(JSContext* cx, HandleObject wrapper, MutableHandleObject objp) const override;
  157. virtual bool getPrototype(JSContext* cx, HandleObject proxy,
  158. MutableHandleObject protop) const override;
  159. virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
  160. ObjectOpResult& result) const override;
  161. virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
  162. MutableHandleObject protop) const override;
  163. virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
  164. bool* succeeded) const override;
  165. virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
  166. ObjectOpResult& result) const override;
  167. virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
  168. virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
  169. virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
  170. HandleId id, MutableHandleValue vp) const override;
  171. virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
  172. HandleValue receiver, ObjectOpResult& result) const override;
  173. virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
  174. virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
  175. /* SpiderMonkey extensions. */
  176. virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
  177. MutableHandle<PropertyDescriptor> desc) const override;
  178. virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
  179. virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
  180. AutoIdVector& props) const override;
  181. virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
  182. const CallArgs& args) const override;
  183. virtual bool hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v,
  184. bool* bp) const override;
  185. virtual const char* className(JSContext* cx, HandleObject proxy) const override;
  186. virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
  187. unsigned indent) const override;
  188. virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override;
  189. virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
  190. // Allocate CrossCompartmentWrappers in the nursery.
  191. virtual bool canNurseryAllocate() const override { return true; }
  192. static const CrossCompartmentWrapper singleton;
  193. static const CrossCompartmentWrapper singletonWithPrototype;
  194. };
  195. class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrapper
  196. {
  197. public:
  198. explicit constexpr OpaqueCrossCompartmentWrapper() : CrossCompartmentWrapper(0)
  199. { }
  200. /* Standard internal methods. */
  201. virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
  202. MutableHandle<PropertyDescriptor> desc) const override;
  203. virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
  204. Handle<PropertyDescriptor> desc,
  205. ObjectOpResult& result) const override;
  206. virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
  207. AutoIdVector& props) const override;
  208. virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
  209. ObjectOpResult& result) const override;
  210. virtual bool enumerate(JSContext* cx, HandleObject wrapper,
  211. MutableHandleObject objp) const override;
  212. virtual bool getPrototype(JSContext* cx, HandleObject wrapper,
  213. MutableHandleObject protop) const override;
  214. virtual bool setPrototype(JSContext* cx, HandleObject wrapper, HandleObject proto,
  215. ObjectOpResult& result) const override;
  216. virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject wrapper, bool* isOrdinary,
  217. MutableHandleObject protop) const override;
  218. virtual bool setImmutablePrototype(JSContext* cx, HandleObject wrapper,
  219. bool* succeeded) const override;
  220. virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
  221. ObjectOpResult& result) const override;
  222. virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
  223. virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id,
  224. bool* bp) const override;
  225. virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
  226. HandleId id, MutableHandleValue vp) const override;
  227. virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
  228. HandleValue receiver, ObjectOpResult& result) const override;
  229. virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
  230. virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override;
  231. /* SpiderMonkey extensions. */
  232. virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
  233. MutableHandle<PropertyDescriptor> desc) const override;
  234. virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
  235. bool* bp) const override;
  236. virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
  237. AutoIdVector& props) const override;
  238. virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
  239. virtual bool isArray(JSContext* cx, HandleObject obj,
  240. JS::IsArrayAnswer* answer) const override;
  241. virtual const char* className(JSContext* cx, HandleObject wrapper) const override;
  242. virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override;
  243. static const OpaqueCrossCompartmentWrapper singleton;
  244. };
  245. /*
  246. * Base class for security wrappers. A security wrapper is potentially hiding
  247. * all or part of some wrapped object thus SecurityWrapper defaults to denying
  248. * access to the wrappee. This is the opposite of Wrapper which tries to be
  249. * completely transparent.
  250. *
  251. * NB: Currently, only a few ProxyHandler operations are overridden to deny
  252. * access, relying on derived SecurityWrapper to block access when necessary.
  253. */
  254. template <class Base>
  255. class JS_FRIEND_API(SecurityWrapper) : public Base
  256. {
  257. public:
  258. explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false)
  259. : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true)
  260. { }
  261. virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, Wrapper::Action act,
  262. bool* bp) const override;
  263. virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
  264. Handle<PropertyDescriptor> desc,
  265. ObjectOpResult& result) const override;
  266. virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
  267. virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
  268. ObjectOpResult& result) const override;
  269. virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
  270. ObjectOpResult& result) const override;
  271. virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override;
  272. virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
  273. const CallArgs& args) const override;
  274. virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override;
  275. virtual bool isArray(JSContext* cx, HandleObject wrapper, JS::IsArrayAnswer* answer) const override;
  276. virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override;
  277. virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
  278. // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
  279. // against.
  280. virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
  281. JS::HandleObject callable) const override;
  282. virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const override;
  283. /*
  284. * Allow our subclasses to select the superclass behavior they want without
  285. * needing to specify an exact superclass.
  286. */
  287. typedef Base Permissive;
  288. typedef SecurityWrapper<Base> Restrictive;
  289. };
  290. typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
  291. extern JSObject*
  292. TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj);
  293. inline bool
  294. IsWrapper(JSObject* obj)
  295. {
  296. return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family;
  297. }
  298. // Given a JSObject, returns that object stripped of wrappers. If
  299. // stopAtWindowProxy is true, then this returns the WindowProxy if it was
  300. // previously wrapped. Otherwise, this returns the first object for
  301. // which JSObject::isWrapper returns false.
  302. JS_FRIEND_API(JSObject*)
  303. UncheckedUnwrap(JSObject* obj, bool stopAtWindowProxy = true, unsigned* flagsp = nullptr);
  304. // Given a JSObject, returns that object stripped of wrappers. At each stage,
  305. // the security wrapper has the opportunity to veto the unwrap. If
  306. // stopAtWindowProxy is true, then this returns the WindowProxy if it was
  307. // previously wrapped.
  308. JS_FRIEND_API(JSObject*)
  309. CheckedUnwrap(JSObject* obj, bool stopAtWindowProxy = true);
  310. // Unwrap only the outermost security wrapper, with the same semantics as
  311. // above. This is the checked version of Wrapper::wrappedObject.
  312. JS_FRIEND_API(JSObject*)
  313. UnwrapOneChecked(JSObject* obj, bool stopAtWindowProxy = true);
  314. JS_FRIEND_API(bool)
  315. IsCrossCompartmentWrapper(JSObject* obj);
  316. void
  317. NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper);
  318. void
  319. RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget);
  320. JS_FRIEND_API(bool)
  321. RemapAllWrappersForObject(JSContext* cx, JSObject* oldTarget,
  322. JSObject* newTarget);
  323. // API to recompute all cross-compartment wrappers whose source and target
  324. // match the given filters.
  325. JS_FRIEND_API(bool)
  326. RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter,
  327. const CompartmentFilter& targetFilter);
  328. } /* namespace js */
  329. #endif /* jswrapper_h */