LCOV - code coverage report
Current view: top level - js/xpconnect/wrappers - AddonWrapper.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 133 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 24 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "AddonWrapper.h"
       8             : #include "WrapperFactory.h"
       9             : #include "XrayWrapper.h"
      10             : #include "jsapi.h"
      11             : #include "jsfriendapi.h"
      12             : #include "nsIAddonInterposition.h"
      13             : #include "xpcprivate.h"
      14             : #include "mozilla/dom/BindingUtils.h"
      15             : #include "nsGlobalWindow.h"
      16             : 
      17             : #include "GeckoProfiler.h"
      18             : 
      19             : #include "nsID.h"
      20             : 
      21             : using namespace js;
      22             : using namespace JS;
      23             : 
      24             : namespace xpc {
      25             : 
      26             : static inline void
      27           0 : ReportASCIIErrorWithId(JSContext* cx, const char* msg, HandleId id)
      28             : {
      29           0 :     RootedValue idv(cx);
      30           0 :     if (!JS_IdToValue(cx, id, &idv))
      31           0 :         return;
      32           0 :     RootedString idstr(cx, JS::ToString(cx, idv));
      33           0 :     if (!idstr)
      34           0 :         return;
      35           0 :     JSAutoByteString bytes;
      36           0 :     if (!bytes.encodeUtf8(cx, idstr))
      37           0 :         return;
      38           0 :     JS_ReportErrorUTF8(cx, msg, bytes.ptr());
      39             : }
      40             : 
      41             : bool
      42           0 : InterposeProperty(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id,
      43             :                   MutableHandle<PropertyDescriptor> descriptor)
      44             : {
      45             :     // We only want to do interpostion on DOM instances and
      46             :     // wrapped natives.
      47           0 :     RootedObject unwrapped(cx, UncheckedUnwrap(target));
      48           0 :     const js::Class* clasp = js::GetObjectClass(unwrapped);
      49           0 :     bool isCPOW = jsipc::IsWrappedCPOW(unwrapped);
      50           0 :     if (!mozilla::dom::IsDOMClass(clasp) &&
      51           0 :         !IS_WN_CLASS(clasp) &&
      52           0 :         !IS_PROTO_CLASS(clasp) &&
      53           0 :         clasp != &OuterWindowProxyClass &&
      54           0 :         !isCPOW) {
      55           0 :         return true;
      56             :     }
      57             : 
      58           0 :     XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(cx));
      59           0 :     MOZ_ASSERT(scope->HasInterposition());
      60             : 
      61           0 :     nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition();
      62           0 :     InterpositionWhitelist* wl = XPCWrappedNativeScope::GetInterpositionWhitelist(interp);
      63             :     // We do InterposeProperty only if the id is on the whitelist of the interpostion
      64             :     // or if the target is a CPOW.
      65           0 :     if ((!wl || !wl->has(JSID_BITS(id.get()))) && !isCPOW)
      66           0 :         return true;
      67             : 
      68           0 :     JSAddonId* addonId = AddonIdOfObject(target);
      69           0 :     RootedValue addonIdValue(cx, StringValue(StringOfAddonId(addonId)));
      70           0 :     RootedValue prop(cx, IdToValue(id));
      71           0 :     RootedValue targetValue(cx, ObjectValue(*target));
      72           0 :     RootedValue descriptorVal(cx);
      73           0 :     nsresult rv = interp->InterposeProperty(addonIdValue, targetValue,
      74           0 :                                             iid, prop, &descriptorVal);
      75           0 :     if (NS_FAILED(rv)) {
      76           0 :         xpc::Throw(cx, rv);
      77           0 :         return false;
      78             :     }
      79             : 
      80           0 :     if (!descriptorVal.isObject())
      81           0 :         return true;
      82             : 
      83             :     // We need to be careful parsing descriptorVal. |cx| is in the compartment
      84             :     // of the add-on and the descriptor is in the compartment of the
      85             :     // interposition. We could wrap the descriptor in the add-on's compartment
      86             :     // and then parse it. However, parsing the descriptor fetches properties
      87             :     // from it, and we would try to interpose on those property accesses. So
      88             :     // instead we parse in the interposition's compartment and then wrap the
      89             :     // descriptor.
      90             : 
      91             :     {
      92           0 :         JSAutoCompartment ac(cx, &descriptorVal.toObject());
      93           0 :         if (!JS::ObjectToCompletePropertyDescriptor(cx, target, descriptorVal, descriptor))
      94           0 :             return false;
      95             :     }
      96             : 
      97             :     // Always make the property non-configurable regardless of what the
      98             :     // interposition wants.
      99           0 :     descriptor.setAttributes(descriptor.attributes() | JSPROP_PERMANENT);
     100             : 
     101           0 :     if (!JS_WrapPropertyDescriptor(cx, descriptor))
     102           0 :         return false;
     103             : 
     104           0 :     return true;
     105             : }
     106             : 
     107             : bool
     108           0 : InterposeCall(JSContext* cx, JS::HandleObject target, const JS::CallArgs& args, bool* done)
     109             : {
     110           0 :     *done = false;
     111           0 :     XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(cx));
     112           0 :     MOZ_ASSERT(scope->HasInterposition());
     113             : 
     114           0 :     nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition();
     115             : 
     116           0 :     RootedObject unwrappedTarget(cx, UncheckedUnwrap(target));
     117           0 :     XPCWrappedNativeScope* targetScope = ObjectScope(unwrappedTarget);
     118           0 :     bool hasInterpostion = targetScope->HasCallInterposition();
     119             : 
     120           0 :     if (!hasInterpostion)
     121           0 :         return true;
     122             : 
     123             :     // If there is a call interpostion, we don't want to propogate the
     124             :     // call to Base:
     125           0 :     *done = true; 
     126             : 
     127           0 :     JSAddonId* addonId = AddonIdOfObject(target);
     128           0 :     RootedValue addonIdValue(cx, StringValue(StringOfAddonId(addonId)));
     129           0 :     RootedValue targetValue(cx, ObjectValue(*target));
     130           0 :     RootedValue thisValue(cx, args.thisv());
     131           0 :     RootedObject argsArray(cx, ConvertArgsToArray(cx, args));
     132           0 :     if (!argsArray)
     133           0 :         return false;
     134             : 
     135           0 :     RootedValue argsVal(cx, ObjectValue(*argsArray));
     136           0 :     RootedValue returnVal(cx);
     137             : 
     138           0 :     nsresult rv = interp->InterposeCall(addonIdValue, targetValue,
     139           0 :                                         thisValue, argsVal, args.rval());
     140           0 :     if (NS_FAILED(rv)) {
     141           0 :         xpc::Throw(cx, rv);
     142           0 :         return false;
     143             :     }
     144             : 
     145           0 :     return true;
     146             : }
     147             : 
     148             : template<typename Base>
     149           0 : bool AddonWrapper<Base>::call(JSContext* cx, JS::Handle<JSObject*> wrapper,
     150             :                               const JS::CallArgs& args) const
     151             : {
     152           0 :     bool done = false;
     153           0 :     if (!InterposeCall(cx, wrapper, args, &done))
     154           0 :         return false;
     155             : 
     156           0 :     return done || Base::call(cx, wrapper, args);
     157             : }
     158             : 
     159             : template<typename Base>
     160             : bool
     161           0 : AddonWrapper<Base>::getPropertyDescriptor(JSContext* cx, HandleObject wrapper,
     162             :                                           HandleId id, MutableHandle<PropertyDescriptor> desc) const
     163             : {
     164           0 :     if (!InterposeProperty(cx, wrapper, nullptr, id, desc))
     165           0 :         return false;
     166             : 
     167           0 :     if (desc.object())
     168           0 :         return true;
     169             : 
     170           0 :     return Base::getPropertyDescriptor(cx, wrapper, id, desc);
     171             : }
     172             : 
     173             : template<typename Base>
     174             : bool
     175           0 : AddonWrapper<Base>::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper,
     176             :                                              HandleId id, MutableHandle<PropertyDescriptor> desc) const
     177             : {
     178           0 :     if (!InterposeProperty(cx, wrapper, nullptr, id, desc))
     179           0 :         return false;
     180             : 
     181           0 :     if (desc.object())
     182           0 :         return true;
     183             : 
     184           0 :     return Base::getOwnPropertyDescriptor(cx, wrapper, id, desc);
     185             : }
     186             : 
     187             : template<typename Base>
     188             : bool
     189           0 : AddonWrapper<Base>::get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<Value> receiver,
     190             :                         JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const
     191             : {
     192           0 :     AUTO_PROFILER_LABEL("AddonWrapper::get", OTHER);
     193             : 
     194           0 :     Rooted<PropertyDescriptor> desc(cx);
     195           0 :     if (!InterposeProperty(cx, wrapper, nullptr, id, &desc))
     196           0 :         return false;
     197             : 
     198           0 :     if (!desc.object())
     199           0 :         return Base::get(cx, wrapper, receiver, id, vp);
     200             : 
     201           0 :     if (desc.getter()) {
     202           0 :         return Call(cx, receiver, desc.getterObject(), HandleValueArray::empty(), vp);
     203             :     } else {
     204           0 :         vp.set(desc.value());
     205           0 :         return true;
     206             :     }
     207             : }
     208             : 
     209             : template<typename Base>
     210             : bool
     211           0 : AddonWrapper<Base>::set(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::HandleValue v,
     212             :                         JS::HandleValue receiver, JS::ObjectOpResult& result) const
     213             : {
     214           0 :     Rooted<PropertyDescriptor> desc(cx);
     215           0 :     if (!InterposeProperty(cx, wrapper, nullptr, id, &desc))
     216           0 :         return false;
     217             : 
     218           0 :     if (!desc.object())
     219           0 :         return Base::set(cx, wrapper, id, v, receiver, result);
     220             : 
     221           0 :     if (desc.setter()) {
     222           0 :         MOZ_ASSERT(desc.hasSetterObject());
     223           0 :         JS::AutoValueVector args(cx);
     224           0 :         if (!args.append(v))
     225           0 :             return false;
     226           0 :         RootedValue fval(cx, ObjectValue(*desc.setterObject()));
     227           0 :         RootedValue ignored(cx);
     228           0 :         if (!JS::Call(cx, receiver, fval, args, &ignored))
     229           0 :             return false;
     230           0 :         return result.succeed();
     231             :     }
     232             : 
     233           0 :     return result.failCantSetInterposed();
     234             : }
     235             : 
     236             : template<typename Base>
     237             : bool
     238           0 : AddonWrapper<Base>::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
     239             :                                    Handle<PropertyDescriptor> desc,
     240             :                                    ObjectOpResult& result) const
     241             : {
     242           0 :     Rooted<PropertyDescriptor> interpDesc(cx);
     243           0 :     if (!InterposeProperty(cx, wrapper, nullptr, id, &interpDesc))
     244           0 :         return false;
     245             : 
     246           0 :     if (!interpDesc.object())
     247           0 :         return Base::defineProperty(cx, wrapper, id, desc, result);
     248             : 
     249           0 :     ReportASCIIErrorWithId(cx, "unable to modify interposed property %s", id);
     250           0 :     return false;
     251             : }
     252             : 
     253             : template<typename Base>
     254             : bool
     255           0 : AddonWrapper<Base>::delete_(JSContext* cx, HandleObject wrapper, HandleId id,
     256             :                             ObjectOpResult& result) const
     257             : {
     258           0 :     Rooted<PropertyDescriptor> desc(cx);
     259           0 :     if (!InterposeProperty(cx, wrapper, nullptr, id, &desc))
     260           0 :         return false;
     261             : 
     262           0 :     if (!desc.object())
     263           0 :         return Base::delete_(cx, wrapper, id, result);
     264             : 
     265           0 :     ReportASCIIErrorWithId(cx, "unable to delete interposed property %s", id);
     266           0 :     return false;
     267             : }
     268             : 
     269             : #define AddonWrapperCC AddonWrapper<CrossCompartmentWrapper>
     270             : #define AddonWrapperXrayXPCWN AddonWrapper<PermissiveXrayXPCWN>
     271             : #define AddonWrapperXrayDOM AddonWrapper<PermissiveXrayDOM>
     272             : 
     273             : template<> const AddonWrapperCC AddonWrapperCC::singleton(0);
     274             : template<> const AddonWrapperXrayXPCWN AddonWrapperXrayXPCWN::singleton(0);
     275             : template<> const AddonWrapperXrayDOM AddonWrapperXrayDOM::singleton(0);
     276             : 
     277             : template class AddonWrapperCC;
     278             : template class AddonWrapperXrayXPCWN;
     279             : template class AddonWrapperXrayDOM;
     280             : 
     281             : #undef AddonWrapperCC
     282             : #undef AddonWrapperXrayXPCWN
     283             : #undef AddonWrapperXrayDOM
     284             : 
     285             : } // namespace xpc

Generated by: LCOV version 1.13