tor-browser

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

Utils.cpp (8966B)


      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 #if defined(MOZILLA_INTERNAL_API)
      8 #  include "MainThreadUtils.h"
      9 #  include "mozilla/dom/ContentChild.h"
     10 #endif
     11 
     12 #include "mozilla/mscom/COMWrappers.h"
     13 #include "mozilla/DebugOnly.h"
     14 #include "mozilla/mscom/Utils.h"
     15 #include "mozilla/RefPtr.h"
     16 
     17 #include <objidl.h>
     18 #include <winnt.h>
     19 
     20 #include <utility>
     21 
     22 #if defined(_MSC_VER)
     23 extern "C" IMAGE_DOS_HEADER __ImageBase;
     24 #endif
     25 
     26 namespace mozilla {
     27 namespace mscom {
     28 
     29 bool IsCOMInitializedOnCurrentThread() {
     30  APTTYPE aptType;
     31  APTTYPEQUALIFIER aptTypeQualifier;
     32  HRESULT hr = wrapped::CoGetApartmentType(&aptType, &aptTypeQualifier);
     33  return hr != CO_E_NOTINITIALIZED;
     34 }
     35 
     36 bool IsCurrentThreadMTA() {
     37  APTTYPE aptType;
     38  APTTYPEQUALIFIER aptTypeQualifier;
     39  HRESULT hr = wrapped::CoGetApartmentType(&aptType, &aptTypeQualifier);
     40  if (FAILED(hr)) {
     41    return false;
     42  }
     43 
     44  return aptType == APTTYPE_MTA;
     45 }
     46 
     47 bool IsCurrentThreadExplicitMTA() {
     48  APTTYPE aptType;
     49  APTTYPEQUALIFIER aptTypeQualifier;
     50  HRESULT hr = wrapped::CoGetApartmentType(&aptType, &aptTypeQualifier);
     51  if (FAILED(hr)) {
     52    return false;
     53  }
     54 
     55  return aptType == APTTYPE_MTA &&
     56         aptTypeQualifier != APTTYPEQUALIFIER_IMPLICIT_MTA;
     57 }
     58 
     59 bool IsCurrentThreadImplicitMTA() {
     60  APTTYPE aptType;
     61  APTTYPEQUALIFIER aptTypeQualifier;
     62  HRESULT hr = wrapped::CoGetApartmentType(&aptType, &aptTypeQualifier);
     63  if (FAILED(hr)) {
     64    return false;
     65  }
     66 
     67  return aptType == APTTYPE_MTA &&
     68         aptTypeQualifier == APTTYPEQUALIFIER_IMPLICIT_MTA;
     69 }
     70 
     71 #if defined(MOZILLA_INTERNAL_API)
     72 bool IsCurrentThreadNonMainMTA() {
     73  if (NS_IsMainThread()) {
     74    return false;
     75  }
     76 
     77  return IsCurrentThreadMTA();
     78 }
     79 #endif  // defined(MOZILLA_INTERNAL_API)
     80 
     81 bool IsProxy(IUnknown* aUnknown) {
     82  if (!aUnknown) {
     83    return false;
     84  }
     85 
     86  // Only proxies implement this interface, so if it is present then we must
     87  // be dealing with a proxied object.
     88  RefPtr<IClientSecurity> clientSecurity;
     89  HRESULT hr = aUnknown->QueryInterface(IID_IClientSecurity,
     90                                        (void**)getter_AddRefs(clientSecurity));
     91  if (SUCCEEDED(hr) || hr == RPC_E_WRONG_THREAD) {
     92    return true;
     93  }
     94  return false;
     95 }
     96 
     97 bool IsValidGUID(REFGUID aCheckGuid) {
     98  // This function determines whether or not aCheckGuid conforms to RFC4122
     99  // as it applies to Microsoft COM.
    100 
    101  BYTE variant = aCheckGuid.Data4[0];
    102  if (!(variant & 0x80)) {
    103    // NCS Reserved
    104    return false;
    105  }
    106  if ((variant & 0xE0) == 0xE0) {
    107    // Reserved for future use
    108    return false;
    109  }
    110  if ((variant & 0xC0) == 0xC0) {
    111    // Microsoft Reserved.
    112    return true;
    113  }
    114 
    115  BYTE version = HIBYTE(aCheckGuid.Data3) >> 4;
    116  // Other versions are specified in RFC4122 but these are the two used by COM.
    117  return version == 1 || version == 4;
    118 }
    119 
    120 uintptr_t GetContainingModuleHandle() {
    121  HMODULE thisModule = nullptr;
    122 #if defined(_MSC_VER)
    123  thisModule = reinterpret_cast<HMODULE>(&__ImageBase);
    124 #else
    125  if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
    126                             GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
    127                         reinterpret_cast<LPCTSTR>(&GetContainingModuleHandle),
    128                         &thisModule)) {
    129    return 0;
    130  }
    131 #endif
    132  return reinterpret_cast<uintptr_t>(thisModule);
    133 }
    134 
    135 namespace detail {
    136 
    137 long BuildRegGuidPath(REFGUID aGuid, const GuidType aGuidType, wchar_t* aBuf,
    138                      const size_t aBufLen) {
    139  constexpr wchar_t kClsid[] = L"CLSID\\";
    140  constexpr wchar_t kAppid[] = L"AppID\\";
    141  constexpr wchar_t kSubkeyBase[] = L"SOFTWARE\\Classes\\";
    142 
    143  // We exclude null terminators in these length calculations because we include
    144  // the stringified GUID's null terminator at the end. Since kClsid and kAppid
    145  // have identical lengths, we just choose one to compute this length.
    146  constexpr size_t kSubkeyBaseLen = std::size(kSubkeyBase) - 1;
    147  constexpr size_t kSubkeyLen = kSubkeyBaseLen + std::size(kClsid) - 1;
    148  // Guid length as formatted for the registry (including curlies and dashes),
    149  // but excluding null terminator.
    150  constexpr size_t kGuidLen = kGuidRegFormatCharLenInclNul - 1;
    151  constexpr size_t kExpectedPathLenInclNul = kSubkeyLen + kGuidLen + 1;
    152 
    153  if (aBufLen < kExpectedPathLenInclNul) {
    154    // Buffer is too short
    155    return E_INVALIDARG;
    156  }
    157 
    158  if (wcscpy_s(aBuf, aBufLen, kSubkeyBase)) {
    159    return E_INVALIDARG;
    160  }
    161 
    162  const wchar_t* strGuidType = aGuidType == GuidType::CLSID ? kClsid : kAppid;
    163  if (wcscat_s(aBuf, aBufLen, strGuidType)) {
    164    return E_INVALIDARG;
    165  }
    166 
    167  int guidConversionResult =
    168      ::StringFromGUID2(aGuid, &aBuf[kSubkeyLen], aBufLen - kSubkeyLen);
    169  if (!guidConversionResult) {
    170    return E_INVALIDARG;
    171  }
    172 
    173  return S_OK;
    174 }
    175 
    176 }  // namespace detail
    177 
    178 long CreateStream(const uint8_t* aInitBuf, const uint32_t aInitBufSize,
    179                  IStream** aOutStream) {
    180  if (!aInitBufSize || !aOutStream) {
    181    return E_INVALIDARG;
    182  }
    183 
    184  *aOutStream = nullptr;
    185 
    186  HRESULT hr;
    187  RefPtr<IStream> stream;
    188 
    189  // If aInitBuf is null then initSize must be 0.
    190  UINT initSize = aInitBuf ? aInitBufSize : 0;
    191  stream = already_AddRefed<IStream>(::SHCreateMemStream(aInitBuf, initSize));
    192  if (!stream) {
    193    return E_OUTOFMEMORY;
    194  }
    195 
    196  if (!aInitBuf) {
    197    // Now we'll set the required size
    198    ULARGE_INTEGER newSize;
    199    newSize.QuadPart = aInitBufSize;
    200    hr = stream->SetSize(newSize);
    201    if (FAILED(hr)) {
    202      return hr;
    203    }
    204  }
    205 
    206  // Ensure that the stream is rewound
    207  LARGE_INTEGER streamOffset;
    208  streamOffset.QuadPart = 0LL;
    209  hr = stream->Seek(streamOffset, STREAM_SEEK_SET, nullptr);
    210  if (FAILED(hr)) {
    211    return hr;
    212  }
    213 
    214  stream.forget(aOutStream);
    215  return S_OK;
    216 }
    217 
    218 #if defined(MOZILLA_INTERNAL_API)
    219 
    220 void GUIDToString(REFGUID aGuid, nsAString& aOutString) {
    221  // This buffer length is long enough to hold a GUID string that is formatted
    222  // to include curly braces and dashes.
    223  const int kBufLenWithNul = 39;
    224  aOutString.SetLength(kBufLenWithNul);
    225  int result = StringFromGUID2(aGuid, char16ptr_t(aOutString.BeginWriting()),
    226                               kBufLenWithNul);
    227  MOZ_ASSERT(result);
    228  if (result) {
    229    // Truncate the terminator
    230    aOutString.SetLength(result - 1);
    231  }
    232 }
    233 
    234 // Undocumented IIDs that are relevant for diagnostic purposes
    235 static const IID IID_ISCMLocalActivator = {
    236    0x00000136,
    237    0x0000,
    238    0x0000,
    239    {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
    240 static const IID IID_IRundown = {
    241    0x00000134,
    242    0x0000,
    243    0x0000,
    244    {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
    245 static const IID IID_IRemUnknown = {
    246    0x00000131,
    247    0x0000,
    248    0x0000,
    249    {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
    250 static const IID IID_IRemUnknown2 = {
    251    0x00000143,
    252    0x0000,
    253    0x0000,
    254    {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
    255 
    256 struct IIDToLiteralMapEntry {
    257  constexpr IIDToLiteralMapEntry(REFIID aIid, nsLiteralCString&& aStr)
    258      : mIid(aIid), mStr(std::forward<nsLiteralCString>(aStr)) {}
    259 
    260  REFIID mIid;
    261  const nsLiteralCString mStr;
    262 };
    263 
    264 /**
    265 * Given the name of an interface, the IID_ENTRY macro generates a pair
    266 * containing a reference to the interface ID and a stringified version of
    267 * the interface name.
    268 *
    269 * For example:
    270 *
    271 *   {IID_ENTRY(IUnknown)}
    272 * is expanded to:
    273 *   {IID_IUnknown, "IUnknown"_ns}
    274 *
    275 */
    276 // clang-format off
    277 #  define IID_ENTRY_STRINGIFY(iface) #iface##_ns
    278 #  define IID_ENTRY(iface) IID_##iface, IID_ENTRY_STRINGIFY(iface)
    279 // clang-format on
    280 
    281 // Mapping of selected IIDs to friendly, human readable descriptions for each
    282 // interface.
    283 static constexpr IIDToLiteralMapEntry sIidDiagStrs[] = {
    284    {IID_ENTRY(IUnknown)},
    285    {IID_IRemUnknown, "cross-apartment IUnknown"_ns},
    286    {IID_IRundown, "cross-apartment object management"_ns},
    287    {IID_ISCMLocalActivator, "out-of-process object instantiation"_ns},
    288    {IID_IRemUnknown2, "cross-apartment IUnknown"_ns}};
    289 
    290 #  undef IID_ENTRY
    291 #  undef IID_ENTRY_STRINGIFY
    292 
    293 void DiagnosticNameForIID(REFIID aIid, nsACString& aOutString) {
    294  // If the IID matches something in sIidDiagStrs, output its string.
    295  for (const auto& curEntry : sIidDiagStrs) {
    296    if (curEntry.mIid == aIid) {
    297      aOutString.Assign(curEntry.mStr);
    298      return;
    299    }
    300  }
    301 
    302  // Otherwise just convert the IID to string form and output that.
    303  nsAutoString strIid;
    304  GUIDToString(aIid, strIid);
    305 
    306  aOutString.AssignLiteral("IID ");
    307  AppendUTF16toUTF8(strIid, aOutString);
    308 }
    309 
    310 #else
    311 
    312 void GUIDToString(REFGUID aGuid,
    313                  wchar_t (&aOutBuf)[kGuidRegFormatCharLenInclNul]) {
    314  DebugOnly<int> result = ::StringFromGUID2(aGuid, aOutBuf, std::size(aOutBuf));
    315  MOZ_ASSERT(result);
    316 }
    317 
    318 #endif  // defined(MOZILLA_INTERNAL_API)
    319 
    320 }  // namespace mscom
    321 }  // namespace mozilla