js/xpconnect/src/XPCCallContext.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 /* Call context. */
     9 #include "xpcprivate.h"
    10 #include "jswrapper.h"
    12 using namespace mozilla;
    13 using namespace xpc;
    14 using namespace JS;
    16 #define IS_TEAROFF_CLASS(clazz) ((clazz) == &XPC_WN_Tearoff_JSClass)
    18 XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage,
    19                                JSContext* cx,
    20                                HandleObject obj    /* = nullptr               */,
    21                                HandleObject funobj /* = nullptr               */,
    22                                HandleId name       /* = JSID_VOID             */,
    23                                unsigned argc       /* = NO_ARGS               */,
    24                                jsval *argv         /* = nullptr               */,
    25                                jsval *rval         /* = nullptr               */)
    26     :   mAr(cx),
    27         mState(INIT_FAILED),
    28         mXPC(nsXPConnect::XPConnect()),
    29         mXPCContext(nullptr),
    30         mJSContext(cx),
    31         mCallerLanguage(callerLanguage),
    32         mFlattenedJSObject(cx),
    33         mWrapper(nullptr),
    34         mTearOff(nullptr),
    35         mName(cx)
    36 {
    37     MOZ_ASSERT(cx);
    38     MOZ_ASSERT(cx == XPCJSRuntime::Get()->GetJSContextStack()->Peek());
    40     if (!mXPC)
    41         return;
    43     mXPCContext = XPCContext::GetXPCContext(mJSContext);
    44     mPrevCallerLanguage = mXPCContext->SetCallingLangType(mCallerLanguage);
    46     // hook into call context chain.
    47     mPrevCallContext = XPCJSRuntime::Get()->SetCallContext(this);
    49     mState = HAVE_CONTEXT;
    51     if (!obj)
    52         return;
    54     mMethodIndex = 0xDEAD;
    56     mState = HAVE_OBJECT;
    58     mTearOff = nullptr;
    60     // If the object is a security wrapper, GetWrappedNativeOfJSObject can't
    61     // handle it. Do special handling here to make cross-origin Xrays work.
    62     JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
    63     if (!unwrapped) {
    64         mWrapper = UnwrapThisIfAllowed(obj, funobj, argc);
    65         if (!mWrapper) {
    66             JS_ReportError(mJSContext, "Permission denied to call method on |this|");
    67             mState = INIT_FAILED;
    68             return;
    69         }
    70     } else {
    71         const js::Class *clasp = js::GetObjectClass(unwrapped);
    72         if (IS_WN_CLASS(clasp)) {
    73             mWrapper = XPCWrappedNative::Get(unwrapped);
    74         } else if (IS_TEAROFF_CLASS(clasp)) {
    75             mTearOff = (XPCWrappedNativeTearOff*)js::GetObjectPrivate(unwrapped);
    76             mWrapper = XPCWrappedNative::Get(js::GetObjectParent(unwrapped));
    77         }
    78     }
    79     if (mWrapper) {
    80         mFlattenedJSObject = mWrapper->GetFlatJSObject();
    82         if (mTearOff)
    83             mScriptableInfo = nullptr;
    84         else
    85             mScriptableInfo = mWrapper->GetScriptableInfo();
    86     } else {
    87         MOZ_ASSERT(!mFlattenedJSObject, "What object do we have?");
    88     }
    90     if (!JSID_IS_VOID(name))
    91         SetName(name);
    93     if (argc != NO_ARGS)
    94         SetArgsAndResultPtr(argc, argv, rval);
    96     CHECK_STATE(HAVE_OBJECT);
    97 }
    99 // static
   100 JSContext *
   101 XPCCallContext::GetDefaultJSContext()
   102 {
   103     // This is slightly questionable. If called without an explicit
   104     // JSContext (generally a call to a wrappedJS) we will use the JSContext
   105     // on the top of the JSContext stack - if there is one - *before*
   106     // falling back on the safe JSContext.
   107     // This is good AND bad because it makes calls from JS -> native -> JS
   108     // have JS stack 'continuity' for purposes of stack traces etc.
   109     // Note: this *is* what the pre-XPCCallContext xpconnect did too.
   111     XPCJSContextStack* stack = XPCJSRuntime::Get()->GetJSContextStack();
   112     JSContext *topJSContext = stack->Peek();
   114     return topJSContext ? topJSContext : stack->GetSafeJSContext();
   115 }
   117 void
   118 XPCCallContext::SetName(jsid name)
   119 {
   120     CHECK_STATE(HAVE_OBJECT);
   122     mName = name;
   124     if (mTearOff) {
   125         mSet = nullptr;
   126         mInterface = mTearOff->GetInterface();
   127         mMember = mInterface->FindMember(mName);
   128         mStaticMemberIsLocal = true;
   129         if (mMember && !mMember->IsConstant())
   130             mMethodIndex = mMember->GetIndex();
   131     } else {
   132         mSet = mWrapper ? mWrapper->GetSet() : nullptr;
   134         if (mSet &&
   135             mSet->FindMember(mName, &mMember, &mInterface,
   136                              mWrapper->HasProto() ?
   137                              mWrapper->GetProto()->GetSet() :
   138                              nullptr,
   139                              &mStaticMemberIsLocal)) {
   140             if (mMember && !mMember->IsConstant())
   141                 mMethodIndex = mMember->GetIndex();
   142         } else {
   143             mMember = nullptr;
   144             mInterface = nullptr;
   145             mStaticMemberIsLocal = false;
   146         }
   147     }
   149     mState = HAVE_NAME;
   150 }
   152 void
   153 XPCCallContext::SetCallInfo(XPCNativeInterface* iface, XPCNativeMember* member,
   154                             bool isSetter)
   155 {
   156     CHECK_STATE(HAVE_CONTEXT);
   158     // We are going straight to the method info and need not do a lookup
   159     // by id.
   161     // don't be tricked if method is called with wrong 'this'
   162     if (mTearOff && mTearOff->GetInterface() != iface)
   163         mTearOff = nullptr;
   165     mSet = nullptr;
   166     mInterface = iface;
   167     mMember = member;
   168     mMethodIndex = mMember->GetIndex() + (isSetter ? 1 : 0);
   169     mName = mMember->GetName();
   171     if (mState < HAVE_NAME)
   172         mState = HAVE_NAME;
   173 }
   175 void
   176 XPCCallContext::SetArgsAndResultPtr(unsigned argc,
   177                                     jsval *argv,
   178                                     jsval *rval)
   179 {
   180     CHECK_STATE(HAVE_OBJECT);
   182     if (mState < HAVE_NAME) {
   183         mSet = nullptr;
   184         mInterface = nullptr;
   185         mMember = nullptr;
   186         mStaticMemberIsLocal = false;
   187     }
   189     mArgc   = argc;
   190     mArgv   = argv;
   191     mRetVal = rval;
   193     mState = HAVE_ARGS;
   194 }
   196 nsresult
   197 XPCCallContext::CanCallNow()
   198 {
   199     nsresult rv;
   201     if (!HasInterfaceAndMember())
   202         return NS_ERROR_UNEXPECTED;
   203     if (mState < HAVE_ARGS)
   204         return NS_ERROR_UNEXPECTED;
   206     if (!mTearOff) {
   207         mTearOff = mWrapper->FindTearOff(mInterface, false, &rv);
   208         if (!mTearOff || mTearOff->GetInterface() != mInterface) {
   209             mTearOff = nullptr;
   210             return NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED;
   211         }
   212     }
   214     // Refresh in case FindTearOff extended the set
   215     mSet = mWrapper->GetSet();
   217     mState = READY_TO_CALL;
   218     return NS_OK;
   219 }
   221 void
   222 XPCCallContext::SystemIsBeingShutDown()
   223 {
   224     // XXX This is pretty questionable since the per thread cleanup stuff
   225     // can be making this call on one thread for call contexts on another
   226     // thread.
   227     NS_WARNING("Shutting Down XPConnect even through there is a live XPCCallContext");
   228     mXPCContext = nullptr;
   229     mState = SYSTEM_SHUTDOWN;
   230     if (mPrevCallContext)
   231         mPrevCallContext->SystemIsBeingShutDown();
   232 }
   234 XPCCallContext::~XPCCallContext()
   235 {
   236     if (mXPCContext) {
   237         mXPCContext->SetCallingLangType(mPrevCallerLanguage);
   239         DebugOnly<XPCCallContext*> old = XPCJSRuntime::Get()->SetCallContext(mPrevCallContext);
   240         MOZ_ASSERT(old == this, "bad pop from per thread data");
   241     }
   242 }
   244 /* readonly attribute nsISupports Callee; */
   245 NS_IMETHODIMP
   246 XPCCallContext::GetCallee(nsISupports * *aCallee)
   247 {
   248     nsCOMPtr<nsISupports> rval = mWrapper ? mWrapper->GetIdentityObject() : nullptr;
   249     rval.forget(aCallee);
   250     return NS_OK;
   251 }
   253 /* readonly attribute uint16_t CalleeMethodIndex; */
   254 NS_IMETHODIMP
   255 XPCCallContext::GetCalleeMethodIndex(uint16_t *aCalleeMethodIndex)
   256 {
   257     *aCalleeMethodIndex = mMethodIndex;
   258     return NS_OK;
   259 }
   261 /* readonly attribute nsIXPConnectWrappedNative CalleeWrapper; */
   262 NS_IMETHODIMP
   263 XPCCallContext::GetCalleeWrapper(nsIXPConnectWrappedNative * *aCalleeWrapper)
   264 {
   265     nsCOMPtr<nsIXPConnectWrappedNative> rval = mWrapper;
   266     rval.forget(aCalleeWrapper);
   267     return NS_OK;
   268 }
   270 /* readonly attribute XPCNativeInterface CalleeInterface; */
   271 NS_IMETHODIMP
   272 XPCCallContext::GetCalleeInterface(nsIInterfaceInfo * *aCalleeInterface)
   273 {
   274     nsCOMPtr<nsIInterfaceInfo> rval = mInterface->GetInterfaceInfo();
   275     rval.forget(aCalleeInterface);
   276     return NS_OK;
   277 }
   279 /* readonly attribute nsIClassInfo CalleeClassInfo; */
   280 NS_IMETHODIMP
   281 XPCCallContext::GetCalleeClassInfo(nsIClassInfo * *aCalleeClassInfo)
   282 {
   283     nsCOMPtr<nsIClassInfo> rval = mWrapper ? mWrapper->GetClassInfo() : nullptr;
   284     rval.forget(aCalleeClassInfo);
   285     return NS_OK;
   286 }
   288 /* readonly attribute JSContextPtr JSContext; */
   289 NS_IMETHODIMP
   290 XPCCallContext::GetJSContext(JSContext * *aJSContext)
   291 {
   292     JS_AbortIfWrongThread(JS_GetRuntime(mJSContext));
   293     *aJSContext = mJSContext;
   294     return NS_OK;
   295 }
   297 /* readonly attribute uint32_t Argc; */
   298 NS_IMETHODIMP
   299 XPCCallContext::GetArgc(uint32_t *aArgc)
   300 {
   301     *aArgc = (uint32_t) mArgc;
   302     return NS_OK;
   303 }
   305 /* readonly attribute JSValPtr ArgvPtr; */
   306 NS_IMETHODIMP
   307 XPCCallContext::GetArgvPtr(jsval * *aArgvPtr)
   308 {
   309     *aArgvPtr = mArgv;
   310     return NS_OK;
   311 }
   313 NS_IMETHODIMP
   314 XPCCallContext::GetPreviousCallContext(nsAXPCNativeCallContext **aResult)
   315 {
   316   NS_ENSURE_ARG_POINTER(aResult);
   317   *aResult = GetPrevCallContext();
   318   return NS_OK;
   319 }
   321 NS_IMETHODIMP
   322 XPCCallContext::GetLanguage(uint16_t *aResult)
   323 {
   324   NS_ENSURE_ARG_POINTER(aResult);
   325   *aResult = GetCallerLanguage();
   326   return NS_OK;
   327 }
   329 XPCWrappedNative*
   330 XPCCallContext::UnwrapThisIfAllowed(HandleObject obj, HandleObject fun, unsigned argc)
   331 {
   332     // We should only get here for objects that aren't safe to unwrap.
   333     MOZ_ASSERT(!js::CheckedUnwrap(obj));
   334     MOZ_ASSERT(js::IsObjectInContextCompartment(obj, mJSContext));
   336     // We can't do anything here without a function.
   337     if (!fun)
   338         return nullptr;
   340     // Determine if we're allowed to unwrap the security wrapper to invoke the
   341     // method.
   342     //
   343     // We have the Interface and Member that this corresponds to, but
   344     // unfortunately our access checks are based on the object class name and
   345     // property name. So we cheat a little bit here - we verify that the object
   346     // does indeed implement the method's Interface, and then just check that we
   347     // can successfully access property with method's name from the object.
   349     // First, get the XPCWN out of the underlying object. We should have a wrapper
   350     // here, potentially an outer window proxy, and then an XPCWN.
   351     MOZ_ASSERT(js::IsWrapper(obj));
   352     RootedObject unwrapped(mJSContext, js::UncheckedUnwrap(obj, /* stopAtOuter = */ false));
   353 #ifdef DEBUG
   354     JS::Rooted<JSObject*> wrappedObj(mJSContext, js::Wrapper::wrappedObject(obj));
   355     MOZ_ASSERT(unwrapped == JS_ObjectToInnerObject(mJSContext, wrappedObj));
   356 #endif
   358     // Make sure we have an XPCWN, and grab it.
   359     if (!IS_WN_REFLECTOR(unwrapped))
   360         return nullptr;
   361     XPCWrappedNative *wn = XPCWrappedNative::Get(unwrapped);
   363     // Next, get the call info off the function object.
   364     XPCNativeInterface *interface;
   365     XPCNativeMember *member;
   366     XPCNativeMember::GetCallInfo(fun, &interface, &member);
   368     // To be extra safe, make sure that the underlying native implements the
   369     // interface before unwrapping. Even if we didn't check this, we'd still
   370     // theoretically fail during tearoff lookup for mismatched methods.
   371     if (!wn->HasInterfaceNoQI(*interface->GetIID()))
   372         return nullptr;
   374     // See if the access is permitted.
   375     //
   376     // NB: This calculation of SET vs GET is a bit wonky, but that's what
   377     // XPC_WN_GetterSetter does.
   378     bool set = argc && argc != NO_ARGS && member->IsWritableAttribute();
   379     js::Wrapper::Action act = set ? js::Wrapper::SET : js::Wrapper::GET;
   380     js::Wrapper *handler = js::Wrapper::wrapperHandler(obj);
   381     bool ignored;
   382     JS::Rooted<jsid> id(mJSContext, member->GetName());
   383     if (!handler->enter(mJSContext, obj, id, act, &ignored))
   384         return nullptr;
   386     // Ok, this call is safe.
   387     return wn;
   388 }

mercurial