From a2e223b2f81ac28d6f7910ab8bbecec2fab9d2e3 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Tue, 17 Jan 2017 13:19:40 -0700 Subject: [PATCH] Bug 1331687: Overload mscom::RegisterProxy to allow proxy registration from within xul.dll itself; r=jimm MozReview-Commit-ID: EiIS5sOCntb --HG-- extra : rebase_source : e0c5f6001bc4c85bdf1db10baa748e393df5a031 --- ipc/mscom/ActivationContext.h | 9 +- ipc/mscom/Registration.cpp | 154 ++++++++++++++++++++++++++++------ ipc/mscom/Registration.h | 6 ++ 3 files changed, 142 insertions(+), 27 deletions(-) diff --git a/ipc/mscom/ActivationContext.h b/ipc/mscom/ActivationContext.h index 08eda7772f1e..b14aba9d2cdb 100644 --- a/ipc/mscom/ActivationContext.h +++ b/ipc/mscom/ActivationContext.h @@ -7,12 +7,14 @@ #ifndef mozilla_mscom_ActivationContext_h #define mozilla_mscom_ActivationContext_h +#include "mozilla/Attributes.h" + #include namespace mozilla { namespace mscom { -class ActivationContext +class MOZ_RAII ActivationContext { public: explicit ActivationContext(HMODULE aLoadFromModule); @@ -23,6 +25,11 @@ public: return mActCtx != INVALID_HANDLE_VALUE; } + ActivationContext(const ActivationContext&) = delete; + ActivationContext(ActivationContext&&) = delete; + ActivationContext& operator=(const ActivationContext&) = delete; + ActivationContext& operator=(ActivationContext&&) = delete; + private: HANDLE mActCtx; ULONG_PTR mActivationCookie; diff --git a/ipc/mscom/Registration.cpp b/ipc/mscom/Registration.cpp index 811989272ded..ff28b0f78547 100644 --- a/ipc/mscom/Registration.cpp +++ b/ipc/mscom/Registration.cpp @@ -32,35 +32,64 @@ /* This code MUST NOT use any non-inlined internal Mozilla APIs, as it will be compiled into DLLs that COM may load into non-Mozilla processes! */ -namespace { +extern "C" { // This function is defined in generated code for proxy DLLs but is not declared -// in rpcproxy.h, so we need this typedef. -typedef void (RPC_ENTRY *GetProxyDllInfoFnPtr)(const ProxyFileInfo*** aInfo, - const CLSID** aId); +// in rpcproxy.h, so we need this declaration. +void RPC_ENTRY GetProxyDllInfo(const ProxyFileInfo*** aInfo, const CLSID** aId); -} // anonymous namespace +#if defined(_MSC_VER) +extern IMAGE_DOS_HEADER __ImageBase; +#endif + +} namespace mozilla { namespace mscom { +static HMODULE +GetContainingModule() +{ + HMODULE thisModule = nullptr; +#if defined(_MSC_VER) + thisModule = reinterpret_cast(&__ImageBase); +#else + if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_UNCHANGED_REFCOUNT, + reinterpret_cast(&GetContainingModule), + &thisModule)) { + return nullptr; + } +#endif + return thisModule; +} + +static bool +GetContainingLibPath(wchar_t* aBuffer, size_t aBufferLen) +{ + HMODULE thisModule = GetContainingModule(); + if (!thisModule) { + return false; + } + + DWORD fileNameResult = GetModuleFileName(thisModule, aBuffer, aBufferLen); + if (!fileNameResult || (fileNameResult == aBufferLen && + ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { + return false; + } + + return true; +} + static bool BuildLibPath(RegistrationFlags aFlags, wchar_t* aBuffer, size_t aBufferLen, const wchar_t* aLeafName) { if (aFlags == RegistrationFlags::eUseBinDirectory) { - HMODULE thisModule = nullptr; - if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - reinterpret_cast(&RegisterProxy), - &thisModule)) { - return false; - } - DWORD fileNameResult = GetModuleFileName(thisModule, aBuffer, aBufferLen); - if (!fileNameResult || (fileNameResult == aBufferLen && - ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { + if (!GetContainingLibPath(aBuffer, aBufferLen)) { return false; } + if (!PathRemoveFileSpec(aBuffer)) { return false; } @@ -79,6 +108,74 @@ BuildLibPath(RegistrationFlags aFlags, wchar_t* aBuffer, size_t aBufferLen, return true; } +static bool +RegisterPSClsids(const ProxyFileInfo** aProxyInfo, const CLSID* aProxyClsid) +{ + while (*aProxyInfo) { + const ProxyFileInfo& curInfo = **aProxyInfo; + for (unsigned short idx = 0, size = curInfo.TableSize; idx < size; ++idx) { + HRESULT hr = CoRegisterPSClsid(*(curInfo.pStubVtblList[idx]->header.piid), + *aProxyClsid); + if (FAILED(hr)) { + return false; + } + } + ++aProxyInfo; + } + + return true; +} + +UniquePtr +RegisterProxy() +{ + const ProxyFileInfo** proxyInfo = nullptr; + const CLSID* proxyClsid = nullptr; + GetProxyDllInfo(&proxyInfo, &proxyClsid); + if (!proxyInfo || !proxyClsid) { + return nullptr; + } + + IUnknown* classObject = nullptr; + HRESULT hr = DllGetClassObject(*proxyClsid, IID_IUnknown, (void**)&classObject); + if (FAILED(hr)) { + return nullptr; + } + + DWORD regCookie; + hr = CoRegisterClassObject(*proxyClsid, classObject, CLSCTX_INPROC_SERVER, + REGCLS_MULTIPLEUSE, ®Cookie); + if (FAILED(hr)) { + classObject->lpVtbl->Release(classObject); + return nullptr; + } + + wchar_t modulePathBuf[MAX_PATH + 1] = {0}; + if (!GetContainingLibPath(modulePathBuf, ArrayLength(modulePathBuf))) { + CoRevokeClassObject(regCookie); + classObject->lpVtbl->Release(classObject); + return nullptr; + } + + ITypeLib* typeLib = nullptr; + hr = LoadTypeLibEx(modulePathBuf, REGKIND_NONE, &typeLib); + MOZ_ASSERT(SUCCEEDED(hr)); + if (FAILED(hr)) { + CoRevokeClassObject(regCookie); + classObject->lpVtbl->Release(classObject); + return nullptr; + } + + // RegisteredProxy takes ownership of classObject and typeLib references + auto result(MakeUnique(classObject, regCookie, typeLib)); + + if (!RegisterPSClsids(proxyInfo, proxyClsid)) { + return nullptr; + } + + return result; +} + UniquePtr RegisterProxy(const wchar_t* aLeafName, RegistrationFlags aFlags) { @@ -100,7 +197,7 @@ RegisterProxy(const wchar_t* aLeafName, RegistrationFlags aFlags) return nullptr; } - auto GetProxyDllInfoFn = reinterpret_cast( + auto GetProxyDllInfoFn = reinterpret_cast( GetProcAddress(proxyDll, "GetProxyDllInfo")); if (!GetProxyDllInfoFn) { return nullptr; @@ -144,16 +241,8 @@ RegisterProxy(const wchar_t* aLeafName, RegistrationFlags aFlags) auto result(MakeUnique(reinterpret_cast(proxyDll.disown()), classObject, regCookie, typeLib)); - while (*proxyInfo) { - const ProxyFileInfo& curInfo = **proxyInfo; - for (unsigned short i = 0, e = curInfo.TableSize; i < e; ++i) { - hr = CoRegisterPSClsid(*(curInfo.pStubVtblList[i]->header.piid), - *proxyClsid); - if (FAILED(hr)) { - return nullptr; - } - } - ++proxyInfo; + if (!RegisterPSClsids(proxyInfo, proxyClsid)) { + return nullptr; } return result; @@ -192,6 +281,19 @@ RegisteredProxy::RegisteredProxy(uintptr_t aModule, IUnknown* aClassObject, AddToRegistry(this); } +RegisteredProxy::RegisteredProxy(IUnknown* aClassObject, uint32_t aRegCookie, + ITypeLib* aTypeLib) + : mModule(0) + , mClassObject(aClassObject) + , mRegCookie(aRegCookie) + , mTypeLib(aTypeLib) + , mIsRegisteredInMTA(IsCurrentThreadMTA()) +{ + MOZ_ASSERT(aClassObject); + MOZ_ASSERT(aTypeLib); + AddToRegistry(this); +} + // If we're initializing from a typelib, it doesn't matter which apartment we // run in, so mIsRegisteredInMTA may always be set to false in this case. RegisteredProxy::RegisteredProxy(ITypeLib* aTypeLib) diff --git a/ipc/mscom/Registration.h b/ipc/mscom/Registration.h index 930225ca76ae..32f14ba8839d 100644 --- a/ipc/mscom/Registration.h +++ b/ipc/mscom/Registration.h @@ -28,6 +28,8 @@ class RegisteredProxy public: RegisteredProxy(uintptr_t aModule, IUnknown* aClassObject, uint32_t aRegCookie, ITypeLib* aTypeLib); + RegisteredProxy(IUnknown* aClassObject, uint32_t aRegCookie, + ITypeLib* aTypeLib); explicit RegisteredProxy(ITypeLib* aTypeLib); RegisteredProxy(RegisteredProxy&& aOther); RegisteredProxy& operator=(RegisteredProxy&& aOther); @@ -63,6 +65,10 @@ enum class RegistrationFlags eUseSystemDirectory }; +// For our own DLL that we are currently executing in (ie, xul). +// Assumes corresponding TLB is embedded in resources. +UniquePtr RegisterProxy(); + // For DLL files. Assumes corresponding TLB is embedded in resources. UniquePtr RegisterProxy(const wchar_t* aLeafName, RegistrationFlags aFlags =