tor-browser

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

GMPProcessParent.cpp (12042B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: sw=2 ts=2 et :
      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 "GMPProcessParent.h"
      8 
      9 #include "GMPUtils.h"
     10 #include "nsIRunnable.h"
     11 #ifdef XP_WIN
     12 #  include "WinUtils.h"
     13 #endif
     14 #include <string>
     15 
     16 #include "GMPLog.h"
     17 #include "base/process_util.h"
     18 #include "base/string_util.h"
     19 #include "mozilla/GeckoArgs.h"
     20 #include "mozilla/StaticPrefs_media.h"
     21 #include "mozilla/ipc/ProcessChild.h"
     22 #include "mozilla/ipc/ProcessUtils.h"
     23 #include "nsFmtString.h"
     24 
     25 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
     26 #  include "mozilla/Omnijar.h"
     27 #  include "mozilla/Preferences.h"
     28 #  include "mozilla/Sandbox.h"
     29 #  include "mozilla/SandboxSettings.h"
     30 #  include "nsMacUtilsImpl.h"
     31 #endif
     32 
     33 using std::string;
     34 using std::vector;
     35 
     36 using mozilla::gmp::GMPProcessParent;
     37 using mozilla::ipc::GeckoChildProcessHost;
     38 
     39 namespace mozilla::gmp {
     40 
     41 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
     42 bool GMPProcessParent::sLaunchWithMacSandbox = true;
     43 bool GMPProcessParent::sMacSandboxGMPLogging = false;
     44 #  if defined(DEBUG)
     45 bool GMPProcessParent::sIsMainThreadInitDone = false;
     46 #  endif
     47 #endif
     48 
     49 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
     50 /* static */
     51 void GMPProcessParent::InitStaticMainThread() {
     52  // The GMPProcessParent constructor is called off the
     53  // main thread. Do main thread initialization here.
     54  MOZ_ASSERT(NS_IsMainThread());
     55  sMacSandboxGMPLogging =
     56      Preferences::GetBool("security.sandbox.logging.enabled") ||
     57      PR_GetEnv("MOZ_SANDBOX_GMP_LOGGING") || PR_GetEnv("MOZ_SANDBOX_LOGGING");
     58  GMP_LOG_DEBUG("GMPProcessParent::InitStaticMainThread: sandbox logging=%s",
     59                sMacSandboxGMPLogging ? "true" : "false");
     60 #  if defined(DEBUG)
     61  sIsMainThreadInitDone = true;
     62 #  endif
     63 }
     64 #endif
     65 
     66 GMPProcessParent::GMPProcessParent(const std::string& aGMPPath)
     67    : GeckoChildProcessHost(GeckoProcessType_GMPlugin),
     68      mGMPPath(aGMPPath),
     69      mUseXpcom(StaticPrefs::media_gmp_use_minimal_xpcom())
     70 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
     71      ,
     72      mRequiresWindowServer(false)
     73 #endif
     74 {
     75  MOZ_COUNT_CTOR(GMPProcessParent);
     76 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
     77  MOZ_ASSERT(sIsMainThreadInitDone == true);
     78  mDisableOSActivityMode = sLaunchWithMacSandbox;
     79 #endif
     80 }
     81 
     82 GMPProcessParent::~GMPProcessParent() { MOZ_COUNT_DTOR(GMPProcessParent); }
     83 
     84 bool GMPProcessParent::Launch(int32_t aTimeoutMs) {
     85  class PrefSerializerRunnable final : public Runnable {
     86   public:
     87    PrefSerializerRunnable()
     88        : Runnable("GMPProcessParent::PrefSerializerRunnable"),
     89          mMonitor("GMPProcessParent::PrefSerializerRunnable::mMonitor") {}
     90 
     91    NS_IMETHOD Run() override {
     92      auto prefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>();
     93      bool success =
     94          prefSerializer->SerializeToSharedMemory(GeckoProcessType_GMPlugin,
     95                                                  /* remoteType */ ""_ns);
     96 
     97      MonitorAutoLock lock(mMonitor);
     98      MOZ_ASSERT(!mComplete);
     99      if (success) {
    100        mPrefSerializer = std::move(prefSerializer);
    101      }
    102      mComplete = true;
    103      lock.Notify();
    104      return NS_OK;
    105    }
    106 
    107    void Wait(int32_t aTimeoutMs,
    108              UniquePtr<ipc::SharedPreferenceSerializer>& aOut) {
    109      MonitorAutoLock lock(mMonitor);
    110 
    111      TimeDuration timeout = TimeDuration::FromMilliseconds(aTimeoutMs);
    112      while (!mComplete) {
    113        if (lock.Wait(timeout) == CVStatus::Timeout) {
    114          return;
    115        }
    116      }
    117 
    118      aOut = std::move(mPrefSerializer);
    119    }
    120 
    121   private:
    122    Monitor mMonitor;
    123    UniquePtr<ipc::SharedPreferenceSerializer> mPrefSerializer
    124        MOZ_GUARDED_BY(mMonitor);
    125    bool mComplete MOZ_GUARDED_BY(mMonitor) = false;
    126  };
    127 
    128  nsresult rv;
    129  geckoargs::ChildProcessArgs args;
    130  UniquePtr<ipc::SharedPreferenceSerializer> prefSerializer;
    131 
    132  ipc::ProcessChild::AddPlatformBuildID(args);
    133 
    134  if (mUseXpcom) {
    135    // Dispatch our runnable to the main thread to grab the serialized prefs. We
    136    // can only do this on the main thread, and unfortunately we are the only
    137    // process that launches from the non-main thread.
    138    auto prefTask = MakeRefPtr<PrefSerializerRunnable>();
    139    rv = NS_DispatchToMainThread(prefTask);
    140    if (NS_WARN_IF(NS_FAILED(rv))) {
    141      return false;
    142    }
    143 
    144    // We don't want to release our thread context while we wait for the main
    145    // thread to process the prefs. We already block when waiting for the launch
    146    // of the process itself to finish, and the state machine assumes this call
    147    // is blocking. This is also important for the buffering of pref updates,
    148    // since we know any tasks dispatched with updates won't run until we launch
    149    // (or fail to launch) the process.
    150    prefTask->Wait(aTimeoutMs, prefSerializer);
    151    if (NS_WARN_IF(!prefSerializer)) {
    152      return false;
    153    }
    154 
    155    prefSerializer->AddSharedPrefCmdLineArgs(*this, args);
    156  }
    157 
    158  geckoargs::sPluginNativeEvent.Put(
    159      StaticPrefs::media_gmp_use_native_event_processing(), args);
    160 
    161 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
    162  GMP_LOG_DEBUG("GMPProcessParent::Launch() mLaunchArch: %d", mLaunchArch);
    163 #  if defined(XP_MACOSX)
    164  mLaunchOptions->arch = mLaunchArch;
    165  if (mLaunchArch == base::PROCESS_ARCH_X86_64) {
    166    mLaunchOptions->env_map["MOZ_SHMEM_PAGESIZE_16K"] = 1;
    167  }
    168 #  endif
    169 #endif
    170 
    171  // Resolve symlinks in the plugin path. The sandbox prevents
    172  // resolving symlinks in the child process if access to link
    173  // source file is denied.
    174 #ifdef XP_WIN
    175  nsAutoString normalizedPath;
    176 #else
    177  nsAutoCString normalizedPath;
    178 #endif
    179  rv = NormalizePath(mGMPPath.c_str(), normalizedPath);
    180  if (NS_WARN_IF(NS_FAILED(rv))) {
    181    GMP_LOG_DEBUG(
    182        "GMPProcessParent::Launch: "
    183        "plugin path normaliziation failed for path: %s",
    184        mGMPPath.c_str());
    185  }
    186 
    187 #ifdef XP_WIN
    188  std::wstring wGMPPath;
    189  if (NS_SUCCEEDED(rv)) {
    190    wGMPPath = normalizedPath.get();
    191  } else {
    192    wGMPPath = UTF8ToWide(mGMPPath.c_str());
    193  }
    194 
    195  // The sandbox doesn't allow file system rules where the paths contain
    196  // symbolic links or junction points. Sometimes the Users folder has been
    197  // moved to another drive using a junction point, so allow for this specific
    198  // case. See bug 1236680 for details.
    199  if (NS_WARN_IF(
    200          !widget::WinUtils::ResolveJunctionPointsAndSymLinks(wGMPPath))) {
    201    GMP_LOG_DEBUG("ResolveJunctionPointsAndSymLinks failed for GMP path=%S",
    202                  wGMPPath.c_str());
    203    return false;
    204  }
    205  GMP_LOG_DEBUG("GMPProcessParent::Launch() resolved path to %S",
    206                wGMPPath.c_str());
    207 
    208 #  ifdef MOZ_SANDBOX
    209  // If the GMP path is a network path that is not mapped to a drive letter,
    210  // then we need to fix the path format for the sandbox rule.
    211  wchar_t volPath[MAX_PATH];
    212  if (::GetVolumePathNameW(wGMPPath.c_str(), volPath, MAX_PATH) &&
    213      ::GetDriveTypeW(volPath) == DRIVE_REMOTE &&
    214      wGMPPath.compare(0, 2, L"\\\\") == 0) {
    215    std::wstring sandboxGMPPath(wGMPPath);
    216    sandboxGMPPath.insert(1, L"??\\UNC");
    217    mAllowedFilesRead.push_back(sandboxGMPPath + L"\\*");
    218  } else {
    219    mAllowedFilesRead.push_back(wGMPPath + L"\\*");
    220  }
    221 #  endif
    222 
    223  std::string gmpPath = WideToUTF8(wGMPPath);
    224  geckoargs::sPluginPath.Put(gmpPath.c_str(), args);
    225 #else
    226  if (NS_SUCCEEDED(rv)) {
    227    geckoargs::sPluginPath.Put(normalizedPath.get(), args);
    228  } else {
    229    geckoargs::sPluginPath.Put(mGMPPath.c_str(), args);
    230  }
    231 #endif
    232 
    233  // We need to wait until OnChannelConnected to clear the pref serializer, but
    234  // SyncLaunch will block until that is called, so we don't actually need to do
    235  // any overriding, and it only lives on the stack.
    236  bool launched = SyncLaunch(std::move(args), aTimeoutMs);
    237  if (launched) {
    238    nsFmtString name{FMT_STRING(u"GMPProcessParent {}"),
    239                     static_cast<void*>(this)};
    240    mShutdownBlocker = media::ShutdownBlockingTicket::Create(
    241        name, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__);
    242  }
    243  return launched;
    244 }
    245 
    246 void GMPProcessParent::Delete(nsCOMPtr<nsIRunnable> aCallback) {
    247  mDeletedCallback = aCallback;
    248  XRE_GetAsyncIOEventTarget()->Dispatch(NewNonOwningRunnableMethod(
    249      "gmp::GMPProcessParent::DoDelete", this, &GMPProcessParent::DoDelete));
    250 }
    251 
    252 void GMPProcessParent::DoDelete() {
    253  MOZ_ASSERT(XRE_GetAsyncIOEventTarget()->IsOnCurrentThread());
    254 
    255  if (mDeletedCallback) {
    256    mDeletedCallback->Run();
    257  }
    258 
    259  Destroy();
    260 }
    261 
    262 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
    263 bool GMPProcessParent::IsMacSandboxLaunchEnabled() {
    264  return sLaunchWithMacSandbox;
    265 }
    266 
    267 void GMPProcessParent::SetRequiresWindowServer(bool aRequiresWindowServer) {
    268  mRequiresWindowServer = aRequiresWindowServer;
    269 }
    270 
    271 bool GMPProcessParent::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
    272  aInfo.type = MacSandboxType_GMP;
    273  aInfo.hasWindowServer = mRequiresWindowServer;
    274  aInfo.shouldLog = (aInfo.shouldLog || sMacSandboxGMPLogging);
    275  nsAutoCString appPath;
    276  if (!nsMacUtilsImpl::GetAppPath(appPath)) {
    277    GMP_LOG_DEBUG(
    278        "GMPProcessParent::FillMacSandboxInfo: failed to get app path");
    279    return false;
    280  }
    281  aInfo.appPath.assign(appPath.get());
    282 
    283  GMP_LOG_DEBUG(
    284      "GMPProcessParent::FillMacSandboxInfo: "
    285      "plugin dir path: %s",
    286      mGMPPath.c_str());
    287  nsCOMPtr<nsIFile> pluginDir;
    288  nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(mGMPPath.c_str()),
    289                                getter_AddRefs(pluginDir));
    290  if (NS_FAILED(rv)) {
    291    GMP_LOG_DEBUG(
    292        "GMPProcessParent::FillMacSandboxInfo: "
    293        "NS_NewLocalFile failed for plugin dir, rv=%d",
    294        uint32_t(rv));
    295    return false;
    296  }
    297 
    298  rv = pluginDir->Normalize();
    299  if (NS_FAILED(rv)) {
    300    GMP_LOG_DEBUG(
    301        "GMPProcessParent::FillMacSandboxInfo: "
    302        "failed to normalize plugin dir path, rv=%d",
    303        uint32_t(rv));
    304    return false;
    305  }
    306 
    307  nsAutoCString resolvedPluginPath;
    308  pluginDir->GetNativePath(resolvedPluginPath);
    309  aInfo.pluginPath.assign(resolvedPluginPath.get());
    310  GMP_LOG_DEBUG(
    311      "GMPProcessParent::FillMacSandboxInfo: "
    312      "resolved plugin dir path: %s",
    313      resolvedPluginPath.get());
    314 
    315  if (!mozilla::IsPackagedBuild()) {
    316    GMP_LOG_DEBUG(
    317        "GMPProcessParent::FillMacSandboxInfo: IsPackagedBuild()=false");
    318 
    319    // Repo dir
    320    nsCOMPtr<nsIFile> repoDir;
    321    rv = nsMacUtilsImpl::GetRepoDir(getter_AddRefs(repoDir));
    322    if (NS_FAILED(rv)) {
    323      GMP_LOG_DEBUG(
    324          "GMPProcessParent::FillMacSandboxInfo: failed to get repo dir");
    325      return false;
    326    }
    327    nsCString repoDirPath;
    328    (void)repoDir->GetNativePath(repoDirPath);
    329    aInfo.testingReadPath1 = repoDirPath.get();
    330    GMP_LOG_DEBUG(
    331        "GMPProcessParent::FillMacSandboxInfo: "
    332        "repo dir path: %s",
    333        repoDirPath.get());
    334 
    335    // Object dir
    336    nsCOMPtr<nsIFile> objDir;
    337    rv = nsMacUtilsImpl::GetObjDir(getter_AddRefs(objDir));
    338    if (NS_FAILED(rv)) {
    339      GMP_LOG_DEBUG(
    340          "GMPProcessParent::FillMacSandboxInfo: failed to get object dir");
    341      return false;
    342    }
    343    nsCString objDirPath;
    344    (void)objDir->GetNativePath(objDirPath);
    345    aInfo.testingReadPath2 = objDirPath.get();
    346    GMP_LOG_DEBUG(
    347        "GMPProcessParent::FillMacSandboxInfo: "
    348        "object dir path: %s",
    349        objDirPath.get());
    350  }
    351  return true;
    352 }
    353 #endif
    354 
    355 nsresult GMPProcessParent::NormalizePath(const char* aPath,
    356                                         PathString& aNormalizedPath) {
    357  nsCOMPtr<nsIFile> fileOrDir;
    358  nsresult rv =
    359      NS_NewLocalFile(NS_ConvertUTF8toUTF16(aPath), getter_AddRefs(fileOrDir));
    360  NS_ENSURE_SUCCESS(rv, rv);
    361 
    362  rv = fileOrDir->Normalize();
    363  NS_ENSURE_SUCCESS(rv, rv);
    364 
    365 #ifdef XP_WIN
    366  return fileOrDir->GetTarget(aNormalizedPath);
    367 #else
    368  bool isLink = false;
    369  rv = fileOrDir->IsSymlink(&isLink);
    370  NS_ENSURE_SUCCESS(rv, rv);
    371  if (isLink) {
    372    return fileOrDir->GetNativeTarget(aNormalizedPath);
    373  }
    374  return fileOrDir->GetNativePath(aNormalizedPath);
    375 #endif
    376 }
    377 
    378 }  // namespace mozilla::gmp