tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RemoteObjectProxy.cpp (7239B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 #include "RemoteObjectProxy.h"
      8 
      9 #include "AccessCheck.h"
     10 #include "js/Object.h"  // JS::GetClass
     11 #include "jsfriendapi.h"
     12 #include "xpcprivate.h"
     13 
     14 namespace mozilla::dom {
     15 
     16 bool RemoteObjectProxyBase::getOwnPropertyDescriptor(
     17    JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
     18    JS::MutableHandle<Maybe<JS::PropertyDescriptor>> aDesc) const {
     19  bool ok = CrossOriginGetOwnPropertyHelper(aCx, aProxy, aId, aDesc);
     20  if (!ok || aDesc.isSome()) {
     21    return ok;
     22  }
     23 
     24  return CrossOriginPropertyFallback(aCx, aProxy, aId, aDesc);
     25 }
     26 
     27 bool RemoteObjectProxyBase::defineProperty(
     28    JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
     29    JS::Handle<JS::PropertyDescriptor> aDesc,
     30    JS::ObjectOpResult& aResult) const {
     31  // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-defineownproperty
     32  // step 3 and
     33  // https://html.spec.whatwg.org/multipage/browsers.html#location-defineownproperty
     34  // step 2
     35  return ReportCrossOriginDenial(aCx, aId, "define"_ns);
     36 }
     37 
     38 bool RemoteObjectProxyBase::ownPropertyKeys(
     39    JSContext* aCx, JS::Handle<JSObject*> aProxy,
     40    JS::MutableHandleVector<jsid> aProps) const {
     41  // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
     42  // step 2 and
     43  // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginproperties-(-o-)
     44  JS::Rooted<JSObject*> holder(aCx);
     45  if (!EnsureHolder(aCx, aProxy, &holder) ||
     46      !js::GetPropertyKeys(aCx, holder,
     47                           JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
     48                           aProps)) {
     49    return false;
     50  }
     51 
     52  // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
     53  // step 3 and 4
     54  return xpc::AppendCrossOriginWhitelistedPropNames(aCx, aProps);
     55 }
     56 
     57 bool RemoteObjectProxyBase::delete_(JSContext* aCx,
     58                                    JS::Handle<JSObject*> aProxy,
     59                                    JS::Handle<jsid> aId,
     60                                    JS::ObjectOpResult& aResult) const {
     61  // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-delete
     62  // step 3 and
     63  // https://html.spec.whatwg.org/multipage/browsers.html#location-delete step 2
     64  return ReportCrossOriginDenial(aCx, aId, "delete"_ns);
     65 }
     66 
     67 bool RemoteObjectProxyBase::getPrototypeIfOrdinary(
     68    JSContext* aCx, JS::Handle<JSObject*> aProxy, bool* aIsOrdinary,
     69    JS::MutableHandle<JSObject*> aProtop) const {
     70  // WindowProxy's and Location's [[GetPrototypeOf]] traps aren't the ordinary
     71  // definition:
     72  //
     73  //   https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof
     74  //   https://html.spec.whatwg.org/multipage/browsers.html#location-getprototypeof
     75  //
     76  // We nonetheless can implement it with a static [[Prototype]], because the
     77  // [[GetPrototypeOf]] trap should always return null.
     78  *aIsOrdinary = true;
     79  aProtop.set(nullptr);
     80  return true;
     81 }
     82 
     83 bool RemoteObjectProxyBase::preventExtensions(
     84    JSContext* aCx, JS::Handle<JSObject*> aProxy,
     85    JS::ObjectOpResult& aResult) const {
     86  // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-preventextensions
     87  // and
     88  // https://html.spec.whatwg.org/multipage/browsers.html#location-preventextensions
     89  return aResult.failCantPreventExtensions();
     90 }
     91 
     92 bool RemoteObjectProxyBase::isExtensible(JSContext* aCx,
     93                                         JS::Handle<JSObject*> aProxy,
     94                                         bool* aExtensible) const {
     95  // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-isextensible
     96  // and
     97  // https://html.spec.whatwg.org/multipage/browsers.html#location-isextensible
     98  *aExtensible = true;
     99  return true;
    100 }
    101 
    102 bool RemoteObjectProxyBase::get(JSContext* aCx, JS::Handle<JSObject*> aProxy,
    103                                JS::Handle<JS::Value> aReceiver,
    104                                JS::Handle<jsid> aId,
    105                                JS::MutableHandle<JS::Value> aVp) const {
    106  return CrossOriginGet(aCx, aProxy, aReceiver, aId, aVp);
    107 }
    108 
    109 bool RemoteObjectProxyBase::set(JSContext* aCx, JS::Handle<JSObject*> aProxy,
    110                                JS::Handle<jsid> aId,
    111                                JS::Handle<JS::Value> aValue,
    112                                JS::Handle<JS::Value> aReceiver,
    113                                JS::ObjectOpResult& aResult) const {
    114  return CrossOriginSet(aCx, aProxy, aId, aValue, aReceiver, aResult);
    115 }
    116 
    117 bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys(
    118    JSContext* aCx, JS::Handle<JSObject*> aProxy,
    119    JS::MutableHandleVector<jsid> aProps) const {
    120  return true;
    121 }
    122 
    123 const char* RemoteObjectProxyBase::className(
    124    JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
    125  MOZ_ASSERT(js::IsProxy(aProxy));
    126 
    127  return NamesOfInterfacesWithProtos(mPrototypeID);
    128 }
    129 
    130 void RemoteObjectProxyBase::GetOrCreateProxyObject(
    131    JSContext* aCx, void* aNative, const JSClass* aClasp,
    132    JS::Handle<JSObject*> aTransplantTo, JS::MutableHandle<JSObject*> aProxy,
    133    bool& aNewObjectCreated) const {
    134  xpc::CompartmentPrivate* priv =
    135      xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
    136  xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap();
    137  if (auto result = map.lookup(aNative)) {
    138    MOZ_RELEASE_ASSERT(!aTransplantTo,
    139                       "GOCPO failed by finding an existing value");
    140 
    141    aProxy.set(result->value());
    142 
    143    // During a transplant, we put an object that is temporarily not a
    144    // proxy object into the map. Make sure that we don't return one of
    145    // these objects in the middle of a transplant.
    146    MOZ_RELEASE_ASSERT(JS::GetClass(aProxy) == aClasp);
    147 
    148    return;
    149  }
    150 
    151  js::ProxyOptions options;
    152  options.setClass(aClasp);
    153  JS::Rooted<JS::Value> native(aCx, JS::PrivateValue(aNative));
    154  JS::Rooted<JSObject*> obj(
    155      aCx, js::NewProxyObject(aCx, this, native, nullptr, options));
    156  if (!obj) {
    157    MOZ_RELEASE_ASSERT(!aTransplantTo, "GOCPO failed at NewProxyObject");
    158    return;
    159  }
    160 
    161  bool success;
    162  if (!JS_SetImmutablePrototype(aCx, obj, &success)) {
    163    MOZ_RELEASE_ASSERT(!aTransplantTo,
    164                       "GOCPO failed at JS_SetImmutablePrototype");
    165    return;
    166  }
    167  MOZ_ASSERT(success);
    168 
    169  aNewObjectCreated = true;
    170 
    171  // If we're transplanting onto an object, we want to make sure that it does
    172  // not have the same class as aClasp to ensure that the release assert earlier
    173  // in this function will actually fire if we try to return a proxy object in
    174  // the middle of a transplant.
    175  MOZ_RELEASE_ASSERT(!aTransplantTo || (JS::GetClass(aTransplantTo) != aClasp),
    176                     "GOCPO failed by not changing the class");
    177 
    178  if (!map.put(aNative, aTransplantTo ? aTransplantTo : obj)) {
    179    MOZ_RELEASE_ASSERT(!aTransplantTo, "GOCPO failed at map.put");
    180    return;
    181  }
    182 
    183  aProxy.set(obj);
    184 }
    185 
    186 const char RemoteObjectProxyBase::sCrossOriginProxyFamily = 0;
    187 
    188 }  // namespace mozilla::dom