From 20b5649ee91e6e284a696728702b8dce1bb8678b Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Thu, 14 Jul 2016 16:54:53 -0600 Subject: [PATCH] Bug 1277075: Add MainThreadRuntime class to mscom glue, enabling safe initialization of COM security and exception handlers; r=jimm MozReview-Commit-ID: BKDnWQLCYGI --HG-- extra : rebase_source : 091ed78a5b30c674ad8a7964b0ae5ffe66e905e5 --- ipc/mscom/COMApartmentRegion.h | 2 +- ipc/mscom/MainThreadRuntime.cpp | 159 ++++++++++++++++++++++++++++++++ ipc/mscom/MainThreadRuntime.h | 42 +++++++++ ipc/mscom/moz.build | 2 + 4 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 ipc/mscom/MainThreadRuntime.cpp create mode 100644 ipc/mscom/MainThreadRuntime.h diff --git a/ipc/mscom/COMApartmentRegion.h b/ipc/mscom/COMApartmentRegion.h index 0168c7e73ffa..dc7ddf9ae2fd 100644 --- a/ipc/mscom/COMApartmentRegion.h +++ b/ipc/mscom/COMApartmentRegion.h @@ -16,7 +16,7 @@ namespace mozilla { namespace mscom { template -class MOZ_RAII COMApartmentRegion +class MOZ_NON_TEMPORARY_CLASS COMApartmentRegion { public: COMApartmentRegion() diff --git a/ipc/mscom/MainThreadRuntime.cpp b/ipc/mscom/MainThreadRuntime.cpp new file mode 100644 index 000000000000..39adaeccf71f --- /dev/null +++ b/ipc/mscom/MainThreadRuntime.cpp @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/mscom/MainThreadRuntime.h" + +#include "mozilla/ArrayUtils.h" +#include "mozilla/Assertions.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/WindowsVersion.h" +#include "nsDebug.h" +#include "nsWindowsHelpers.h" + +#include +#include +#include +#include + +namespace { + +struct LocalFreeDeleter +{ + void operator()(void* aPtr) + { + ::LocalFree(aPtr); + } +}; + +} // anonymous namespace + +namespace mozilla { +namespace mscom { + +MainThreadRuntime::MainThreadRuntime() + : mInitResult(E_UNEXPECTED) +{ + // We must be the outermost COM initialization on this thread. The COM runtime + // cannot be configured once we start manipulating objects + MOZ_ASSERT(mStaRegion.IsValidOutermost()); + if (NS_WARN_IF(!mStaRegion.IsValidOutermost())) { + return; + } + + // We are required to initialize security in order to configure global options. + mInitResult = InitializeSecurity(); + MOZ_ASSERT(SUCCEEDED(mInitResult)); + if (FAILED(mInitResult)) { + return; + } + + RefPtr globalOpts; + mInitResult = ::CoCreateInstance(CLSID_GlobalOptions, nullptr, + CLSCTX_INPROC_SERVER, IID_IGlobalOptions, + (void**)getter_AddRefs(globalOpts)); + // IGlobalOptions doesn't exist on XP, so we only assert if we're expecting it + MOZ_ASSERT(SUCCEEDED(mInitResult) || !IsVistaOrLater()); + if (FAILED(mInitResult)) { + return; + } + + // Windows 7 has a policy that is even more strict. We should use that one + // whenever possible. + ULONG_PTR exceptionSetting = IsWin7OrLater() ? + COMGLB_EXCEPTION_DONOT_HANDLE_ANY : + COMGLB_EXCEPTION_DONOT_HANDLE; + mInitResult = globalOpts->Set(COMGLB_EXCEPTION_HANDLING, exceptionSetting); + MOZ_ASSERT(SUCCEEDED(mInitResult)); +} + +HRESULT +MainThreadRuntime::InitializeSecurity() +{ + HANDLE rawToken = nullptr; + BOOL ok = ::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken); + if (!ok) { + return HRESULT_FROM_WIN32(::GetLastError()); + } + nsAutoHandle token(rawToken); + + DWORD len = 0; + ok = ::GetTokenInformation(token, TokenUser, nullptr, len, &len); + DWORD win32Error = ::GetLastError(); + if (!ok && win32Error != ERROR_INSUFFICIENT_BUFFER) { + return HRESULT_FROM_WIN32(win32Error); + } + + auto tokenUserBuf = MakeUnique(len); + TOKEN_USER& tokenUser = *reinterpret_cast(tokenUserBuf.get()); + ok = ::GetTokenInformation(token, TokenUser, tokenUserBuf.get(), len, &len); + if (!ok) { + return HRESULT_FROM_WIN32(::GetLastError()); + } + + len = 0; + ok = ::GetTokenInformation(token, TokenPrimaryGroup, nullptr, len, &len); + win32Error = ::GetLastError(); + if (!ok && win32Error != ERROR_INSUFFICIENT_BUFFER) { + return HRESULT_FROM_WIN32(win32Error); + } + + auto tokenPrimaryGroupBuf = MakeUnique(len); + TOKEN_PRIMARY_GROUP& tokenPrimaryGroup = + *reinterpret_cast(tokenPrimaryGroupBuf.get()); + ok = ::GetTokenInformation(token, TokenPrimaryGroup, tokenPrimaryGroupBuf.get(), + len, &len); + if (!ok) { + return HRESULT_FROM_WIN32(::GetLastError()); + } + + SECURITY_DESCRIPTOR sd; + if (!::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { + return HRESULT_FROM_WIN32(::GetLastError()); + } + + // Grant access to SYSTEM, Administrators, and the user. + EXPLICIT_ACCESS entries[] = { + {COM_RIGHTS_EXECUTE, GRANT_ACCESS, NO_INHERITANCE, + {nullptr, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_NAME, TRUSTEE_IS_USER, + L"SYSTEM"}}, + {COM_RIGHTS_EXECUTE, GRANT_ACCESS, NO_INHERITANCE, + {nullptr, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_NAME, TRUSTEE_IS_WELL_KNOWN_GROUP, + L"ADMINISTRATORS"}}, + {COM_RIGHTS_EXECUTE, GRANT_ACCESS, NO_INHERITANCE, + {nullptr, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID, TRUSTEE_IS_USER, + reinterpret_cast(tokenUser.User.Sid)}} + }; + + PACL rawDacl = nullptr; + win32Error = ::SetEntriesInAcl(ArrayLength(entries), entries, nullptr, + &rawDacl); + if (win32Error != ERROR_SUCCESS) { + return HRESULT_FROM_WIN32(win32Error); + } + + UniquePtr dacl(rawDacl); + + if (!::SetSecurityDescriptorDacl(&sd, TRUE, dacl.get(), FALSE)) { + return HRESULT_FROM_WIN32(::GetLastError()); + } + + if (!::SetSecurityDescriptorOwner(&sd, tokenUser.User.Sid, FALSE)) { + return HRESULT_FROM_WIN32(::GetLastError()); + } + + if (!::SetSecurityDescriptorGroup(&sd, tokenPrimaryGroup.PrimaryGroup, FALSE)) { + return HRESULT_FROM_WIN32(::GetLastError()); + } + + return ::CoInitializeSecurity(&sd, -1, nullptr, nullptr, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IDENTIFY, nullptr, EOAC_NONE, + nullptr); +} + +} // namespace mscom +} // namespace mozilla + diff --git a/ipc/mscom/MainThreadRuntime.h b/ipc/mscom/MainThreadRuntime.h new file mode 100644 index 000000000000..0e3e52c5f882 --- /dev/null +++ b/ipc/mscom/MainThreadRuntime.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_mscom_MainThreadRuntime_h +#define mozilla_mscom_MainThreadRuntime_h + +#include "mozilla/Attributes.h" +#include "mozilla/mscom/COMApartmentRegion.h" + +namespace mozilla { +namespace mscom { + +class MOZ_NON_TEMPORARY_CLASS MainThreadRuntime +{ +public: + MainThreadRuntime(); + + explicit operator bool() const + { + return mStaRegion.IsValidOutermost() && SUCCEEDED(mInitResult); + } + + MainThreadRuntime(MainThreadRuntime&) = delete; + MainThreadRuntime(MainThreadRuntime&&) = delete; + MainThreadRuntime& operator=(MainThreadRuntime&) = delete; + MainThreadRuntime& operator=(MainThreadRuntime&&) = delete; + +private: + HRESULT InitializeSecurity(); + + STARegion mStaRegion; + HRESULT mInitResult; +}; + +} // namespace mscom +} // namespace mozilla + +#endif // mozilla_mscom_MainThreadRuntime_h + diff --git a/ipc/mscom/moz.build b/ipc/mscom/moz.build index d4de61ceb77b..01d03b5133d2 100644 --- a/ipc/mscom/moz.build +++ b/ipc/mscom/moz.build @@ -6,10 +6,12 @@ EXPORTS.mozilla.mscom += [ 'COMApartmentRegion.h', + 'MainThreadRuntime.h', 'Utils.h', ] UNIFIED_SOURCES += [ + 'MainThreadRuntime.cpp', 'Utils.cpp', ]