tor-browser

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

GeckoChildProcessHost.cpp (68864B)


      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 #include "GeckoChildProcessHost.h"
      8 
      9 #include "base/command_line.h"
     10 #include "base/process.h"
     11 #include "base/process_util.h"
     12 #include "base/string_util.h"
     13 #include "base/task.h"
     14 #include "chrome/common/chrome_switches.h"
     15 #include "chrome/common/process_watcher.h"
     16 #ifdef XP_DARWIN
     17 #  include <mach/mach_traps.h>
     18 #  include "base/rand_util.h"
     19 #  include "chrome/common/mach_ipc_mac.h"
     20 #  include "mozilla/StaticPrefs_layers.h"
     21 #  include "mozilla/StaticPrefs_media.h"
     22 #endif
     23 #ifdef MOZ_WIDGET_COCOA
     24 #  include <bsm/libbsm.h>
     25 #  include <servers/bootstrap.h>
     26 #  include "nsILocalFileMac.h"
     27 #endif
     28 
     29 #include "GeckoProfiler.h"
     30 #include "MainThreadUtils.h"
     31 #include "mozilla/Preferences.h"
     32 #include "mozilla/Sprintf.h"
     33 #include "nsXPCOMPrivate.h"
     34 #include "prenv.h"
     35 #include "prerror.h"
     36 
     37 #if defined(MOZ_SANDBOX)
     38 #  include "mozilla/SandboxSettings.h"
     39 #  include "nsAppDirectoryServiceDefs.h"
     40 #endif
     41 
     42 #include "ProtocolUtils.h"
     43 #include "mozilla/LinkedList.h"
     44 #include "mozilla/Logging.h"
     45 #include "mozilla/Maybe.h"
     46 #include "mozilla/GeckoArgs.h"
     47 #include "mozilla/Omnijar.h"
     48 #include "mozilla/RDDProcessHost.h"
     49 #include "mozilla/Services.h"
     50 #include "mozilla/SharedThreadPool.h"
     51 #include "mozilla/StaticMutex.h"
     52 #include "mozilla/TaskQueue.h"
     53 #include "mozilla/glean/DomMetrics.h"
     54 #include "mozilla/glean/IpcMetrics.h"
     55 #include "mozilla/UniquePtrExtensions.h"
     56 #include "mozilla/ipc/IOThread.h"
     57 #include "mozilla/ipc/EnvironmentMap.h"
     58 #include "mozilla/ipc/NodeController.h"
     59 #include "mozilla/net/SocketProcessHost.h"
     60 #include "nsDirectoryService.h"
     61 #include "nsDirectoryServiceDefs.h"
     62 #include "nsExceptionHandler.h"
     63 #include "nsIFile.h"
     64 #include "nsIObserverService.h"
     65 #include "nsPrintfCString.h"
     66 
     67 #ifdef XP_WIN
     68 #  include <stdlib.h>
     69 
     70 #  include "nsIWinTaskbar.h"
     71 #  define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
     72 
     73 #  if defined(MOZ_SANDBOX)
     74 #    include "WinUtils.h"
     75 #    include "mozilla/Preferences.h"
     76 #    include "mozilla/sandboxing/sandboxLogging.h"
     77 #  endif
     78 
     79 #  include "mozilla/NativeNt.h"
     80 #  include "mozilla/CacheNtDllThunk.h"
     81 #endif
     82 
     83 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
     84 #  include "mozilla/SandboxLaunch.h"
     85 #endif
     86 
     87 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
     88 #  include "GMPProcessParent.h"
     89 #  include "nsMacUtilsImpl.h"
     90 #  include "mozilla/gfx/GPUProcessHost.h"
     91 #endif
     92 
     93 #include "mozilla/ipc/UtilityProcessHost.h"
     94 #include "mozilla/ipc/UtilityProcessSandboxing.h"
     95 
     96 #include "nsClassHashtable.h"
     97 #include "nsHashKeys.h"
     98 #include "nsNativeCharsetUtils.h"
     99 #include "nsTArray.h"
    100 #include "nscore.h"  // for NS_FREE_PERMANENT_DATA
    101 #include "nsIThread.h"
    102 
    103 using mozilla::MonitorAutoLock;
    104 using mozilla::Preferences;
    105 using mozilla::StaticMutexAutoLock;
    106 
    107 #ifdef MOZ_WIDGET_ANDROID
    108 #  include "AndroidBridge.h"
    109 #  include "mozilla/java/GeckoProcessManagerWrappers.h"
    110 #  include "mozilla/java/GeckoProcessTypeWrappers.h"
    111 #  include "mozilla/java/GeckoResultWrappers.h"
    112 #  include "mozilla/jni/Refs.h"
    113 #  include "mozilla/jni/Utils.h"
    114 #endif
    115 
    116 #ifdef MOZ_ENABLE_FORKSERVER
    117 #  include "mozilla/ipc/ForkServiceChild.h"
    118 #endif
    119 
    120 static bool ShouldHaveDirectoryService() {
    121  return GeckoProcessType_Default == XRE_GetProcessType();
    122 }
    123 
    124 #ifdef XP_IOS
    125 // Hack to ensure environment variables are copied into child processes on iOS.
    126 extern char** environ;
    127 #endif
    128 
    129 namespace mozilla {
    130 namespace ipc {
    131 
    132 struct LaunchResults {
    133  base::ProcessHandle mHandle = 0;
    134 #ifdef XP_MACOSX
    135  task_t mChildTask = MACH_PORT_NULL;
    136 #endif
    137 #ifdef XP_IOS
    138  Maybe<ExtensionKitProcess> mExtensionKitProcess;
    139  DarwinObjectPtr<xpc_connection_t> mXPCConnection;
    140  UniqueBEProcessCapabilityGrant mForegroundCapabilityGrant;
    141 #endif
    142 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
    143  UniquePtr<SandboxBroker> mSandboxBroker;
    144 #endif
    145 };
    146 typedef mozilla::MozPromise<LaunchResults, LaunchError, true>
    147    ProcessLaunchPromise;
    148 
    149 // Monotonic counter used to generate a unique ChildID for each process as it is
    150 // created. The parent process is given the ChildID of `0`, and each child
    151 // process is given a non-zero ID.
    152 static Atomic<int32_t> gChildCounter;
    153 
    154 class BaseProcessLauncher {
    155 public:
    156  BaseProcessLauncher(GeckoChildProcessHost* aHost,
    157                      geckoargs::ChildProcessArgs&& aExtraOpts)
    158      : mProcessType(aHost->mProcessType),
    159        mLaunchOptions(std::move(aHost->mLaunchOptions)),
    160        mChildArgs(std::move(aExtraOpts))
    161 #ifdef XP_WIN
    162        ,
    163        mGroupId(aHost->mGroupId)
    164 #endif
    165 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
    166        ,
    167        mAllowedFilesRead(aHost->mAllowedFilesRead),
    168        mSandboxLevel(aHost->mSandboxLevel),
    169        mSandbox(aHost->mSandbox),
    170        mIsFileContent(aHost->mIsFileContent),
    171        mEnableSandboxLogging(aHost->mEnableSandboxLogging)
    172 #endif
    173 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
    174        ,
    175        mDisableOSActivityMode(aHost->mDisableOSActivityMode)
    176 #endif
    177  {
    178    aHost->mInitialChannelId.ToProvidedString(mInitialChannelIdString);
    179    SprintfLiteral(mChildIDString, "%d", aHost->mChildID);
    180 
    181    // Compute the serial event target we'll use for launching.
    182    nsCOMPtr<nsIEventTarget> threadOrPool = GetIPCLauncher();
    183    mLaunchThread =
    184        TaskQueue::Create(threadOrPool.forget(), "BaseProcessLauncher");
    185 
    186    if (ShouldHaveDirectoryService()) {
    187      // "Current process directory" means the app dir, not the current
    188      // working dir or similar.
    189      (void)nsDirectoryService::gService->GetCurrentProcessDirectory(
    190          getter_AddRefs(mAppDir));
    191    }
    192  }
    193 
    194  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseProcessLauncher);
    195 
    196 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
    197  void SetLaunchArchitecture(uint32_t aLaunchArch) {
    198    mLaunchArch = aLaunchArch;
    199  }
    200 #endif
    201 
    202  RefPtr<ProcessLaunchPromise> Launch(GeckoChildProcessHost*);
    203 
    204 protected:
    205  virtual ~BaseProcessLauncher() = default;
    206 
    207  RefPtr<ProcessLaunchPromise> PerformAsyncLaunch();
    208 
    209  // Overrideable hooks. If superclass behavior is invoked, it's always at the
    210  // top of the override.
    211  virtual Result<Ok, LaunchError> DoSetup();
    212  virtual RefPtr<ProcessLaunchPromise> DoLaunch() = 0;
    213 
    214  void MapChildLogging();
    215 
    216  static BinPathType GetPathToBinary(FilePath&, GeckoProcessType);
    217 
    218  void GetChildLogName(const char* origLogName, nsACString& buffer);
    219 
    220  const char* ChildProcessType() {
    221    return XRE_GeckoProcessTypeToString(mProcessType);
    222  }
    223 
    224  nsCOMPtr<nsISerialEventTarget> mLaunchThread;
    225  GeckoProcessType mProcessType;
    226  UniquePtr<base::LaunchOptions> mLaunchOptions;
    227 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
    228  uint32_t mLaunchArch = base::PROCESS_ARCH_INVALID;
    229 #endif
    230  geckoargs::ChildProcessArgs mChildArgs;
    231 #ifdef XP_WIN
    232  nsString mGroupId;
    233 #endif
    234 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
    235  std::vector<std::wstring> mAllowedFilesRead;
    236  int32_t mSandboxLevel;
    237  SandboxingKind mSandbox;
    238  bool mIsFileContent;
    239  bool mEnableSandboxLogging;
    240 #endif
    241 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
    242  // Controls whether or not the process will be launched with
    243  // environment variable OS_ACTIVITY_MODE set to "disabled".
    244  bool mDisableOSActivityMode;
    245 #endif
    246  LaunchResults mResults = LaunchResults();
    247  char mInitialChannelIdString[NSID_LENGTH];
    248  char mChildIDString[32];
    249 
    250  // Set during launch.
    251  nsCOMPtr<nsIFile> mAppDir;
    252 };
    253 
    254 #ifdef XP_WIN
    255 class WindowsProcessLauncher : public BaseProcessLauncher {
    256 public:
    257  WindowsProcessLauncher(GeckoChildProcessHost* aHost,
    258                         geckoargs::ChildProcessArgs&& aExtraOpts)
    259      : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
    260        mCachedNtdllThunk(GetCachedNtDllThunk()) {}
    261 
    262 protected:
    263  virtual Result<Ok, LaunchError> DoSetup() override;
    264  virtual RefPtr<ProcessLaunchPromise> DoLaunch() override;
    265 
    266  mozilla::Maybe<CommandLine> mCmdLine;
    267 #  ifdef MOZ_SANDBOX
    268  bool mUseSandbox = false;
    269 #  endif
    270 
    271  const Buffer<IMAGE_THUNK_DATA>* mCachedNtdllThunk;
    272 };
    273 typedef WindowsProcessLauncher ProcessLauncher;
    274 #endif  // XP_WIN
    275 
    276 #ifdef XP_UNIX
    277 class PosixProcessLauncher : public BaseProcessLauncher {
    278 public:
    279  PosixProcessLauncher(GeckoChildProcessHost* aHost,
    280                       geckoargs::ChildProcessArgs&& aExtraOpts)
    281      : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
    282        mProfileDir(aHost->mProfileDir) {}
    283 
    284 protected:
    285  virtual Result<Ok, LaunchError> DoSetup() override;
    286  virtual RefPtr<ProcessLaunchPromise> DoLaunch() override;
    287 
    288  nsCOMPtr<nsIFile> mProfileDir;
    289 };
    290 
    291 #  if defined(XP_MACOSX)
    292 class MacProcessLauncher : public PosixProcessLauncher {
    293 public:
    294  MacProcessLauncher(GeckoChildProcessHost* aHost,
    295                     geckoargs::ChildProcessArgs&& aExtraOpts)
    296      : PosixProcessLauncher(aHost, std::move(aExtraOpts)),
    297        // Put a random number into the channel name, so that
    298        // a compromised renderer can't pretend being the child
    299        // that's forked off.
    300        mMachConnectionName(
    301            StringPrintf("org.mozilla.machname.%d",
    302                         base::RandInt(0, std::numeric_limits<int>::max()))) {
    303    MOZ_ASSERT(mMachConnectionName.size() < BOOTSTRAP_MAX_NAME_LEN);
    304  }
    305 
    306 protected:
    307  virtual RefPtr<ProcessLaunchPromise> DoLaunch() override;
    308 
    309  std::string mMachConnectionName;
    310  // We add a mach port to the command line so the child can communicate its
    311  // 'task_t' back to the parent.
    312  mozilla::UniqueMachReceiveRight mParentRecvPort;
    313 
    314  friend class PosixProcessLauncher;
    315 };
    316 typedef MacProcessLauncher ProcessLauncher;
    317 #  elif defined(MOZ_WIDGET_ANDROID)
    318 class AndroidProcessLauncher : public PosixProcessLauncher {
    319 public:
    320  AndroidProcessLauncher(GeckoChildProcessHost* aHost,
    321                         geckoargs::ChildProcessArgs&& aExtraOpts)
    322      : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
    323 
    324 protected:
    325  virtual RefPtr<ProcessLaunchPromise> DoLaunch() override;
    326  RefPtr<ProcessHandlePromise> LaunchAndroidService(
    327      const GeckoProcessType aType, const geckoargs::ChildProcessArgs& args);
    328 };
    329 typedef AndroidProcessLauncher ProcessLauncher;
    330 // NB: Technically Android is linux (i.e. XP_LINUX is defined), but we want
    331 // orthogonal IPC machinery there. Conversely, there are tier-3 non-Linux
    332 // platforms (BSD and Solaris) where we want the "linux" IPC machinery. So
    333 // we use MOZ_WIDGET_* to choose the platform backend.
    334 #  elif defined(MOZ_WIDGET_GTK)
    335 class LinuxProcessLauncher : public PosixProcessLauncher {
    336 public:
    337  LinuxProcessLauncher(GeckoChildProcessHost* aHost,
    338                       geckoargs::ChildProcessArgs&& aExtraOpts)
    339      : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
    340 
    341 protected:
    342  virtual Result<Ok, LaunchError> DoSetup() override;
    343 };
    344 typedef LinuxProcessLauncher ProcessLauncher;
    345 #  elif defined(MOZ_WIDGET_UIKIT)
    346 class IosProcessLauncher : public PosixProcessLauncher {
    347 public:
    348  IosProcessLauncher(GeckoChildProcessHost* aHost,
    349                     geckoargs::ChildProcessArgs&& aExtraOpts)
    350      : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
    351 
    352 protected:
    353  virtual Result<Ok, LaunchError> DoSetup() override;
    354  virtual RefPtr<ProcessLaunchPromise> DoLaunch() override;
    355 
    356  DarwinObjectPtr<xpc_object_t> mBootstrapMessage;
    357 };
    358 typedef IosProcessLauncher ProcessLauncher;
    359 #  else
    360 #    error "Unknown platform"
    361 #  endif
    362 #endif  // XP_UNIX
    363 
    364 using base::ProcessHandle;
    365 using mozilla::ipc::BaseProcessLauncher;
    366 using mozilla::ipc::ProcessLauncher;
    367 
    368 mozilla::StaticAutoPtr<mozilla::LinkedList<GeckoChildProcessHost>>
    369    GeckoChildProcessHost::sGeckoChildProcessHosts;
    370 
    371 mozilla::StaticMutex GeckoChildProcessHost::sMutex;
    372 
    373 GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
    374                                             bool aIsFileContent)
    375    : mProcessType(aProcessType),
    376      mChildID(++gChildCounter),
    377      mIsFileContent(aIsFileContent),
    378      mMonitor("mozilla.ipc.GeckoChildProcessHost.mMonitor"),
    379      mLaunchOptions(MakeUnique<base::LaunchOptions>()),
    380      mInitialChannelId(nsID::GenerateUUID()),
    381      mProcessState(CREATING_CHANNEL),
    382 #ifdef XP_WIN
    383      mGroupId(u"-"),
    384 #endif
    385 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
    386      mEnableSandboxLogging(false),
    387      mSandboxLevel(0),
    388 #endif
    389      mHandleLock("mozilla.ipc.GeckoChildProcessHost.mHandleLock"),
    390      mChildProcessHandle(0),
    391 #if defined(XP_MACOSX)
    392      mChildTask(MACH_PORT_NULL),
    393 #endif
    394 #if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
    395      mDisableOSActivityMode(false),
    396 #endif
    397      mDestroying(false) {
    398  MOZ_COUNT_CTOR(GeckoChildProcessHost);
    399  MOZ_RELEASE_ASSERT(mChildID > 0, "gChildCounter overflowed");
    400  StaticMutexAutoLock lock(sMutex);
    401  if (!sGeckoChildProcessHosts) {
    402    sGeckoChildProcessHosts = new mozilla::LinkedList<GeckoChildProcessHost>();
    403  }
    404  sGeckoChildProcessHosts->insertBack(this);
    405 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
    406  if (aProcessType == GeckoProcessType_RDD) {
    407    // The RDD process makes limited use of EGL.  If Mesa's shader
    408    // cache is enabled and the directory isn't explicitly set, then
    409    // it will try to getpwuid() the user which can cause problems
    410    // with sandboxing.  Because we shouldn't need shader caching in
    411    // this process, we just disable the cache to prevent that.
    412    mLaunchOptions->env_map["MESA_GLSL_CACHE_DISABLE"] = "true";
    413    mLaunchOptions->env_map["MESA_SHADER_CACHE_DISABLE"] = "true";
    414    // In case the nvidia driver is also loaded:
    415    mLaunchOptions->env_map["__GL_SHADER_DISK_CACHE"] = "0";
    416  }
    417 #endif
    418 }
    419 
    420 GeckoChildProcessHost::~GeckoChildProcessHost() {
    421  AssertIOThread();
    422  MOZ_RELEASE_ASSERT(mDestroying);
    423 
    424  MOZ_COUNT_DTOR(GeckoChildProcessHost);
    425 
    426  {
    427    mozilla::AutoWriteLock hLock(mHandleLock);
    428 #if defined(XP_MACOSX)
    429    if (mChildTask != MACH_PORT_NULL) {
    430      mach_port_deallocate(mach_task_self(), mChildTask);
    431    }
    432 #endif
    433 #if defined(XP_IOS)
    434    if (mForegroundCapabilityGrant) {
    435      mForegroundCapabilityGrant.reset();
    436    }
    437    if (mExtensionKitProcess) {
    438      mExtensionKitProcess->Invalidate();
    439    }
    440    if (mXPCConnection) {
    441      xpc_connection_cancel(mXPCConnection.get());
    442    }
    443 #endif
    444 
    445    if (mChildProcessHandle != 0) {
    446      ProcessWatcher::EnsureProcessTerminated(mChildProcessHandle);
    447      mChildProcessHandle = 0;
    448    }
    449  }
    450 }
    451 
    452 base::ProcessHandle GeckoChildProcessHost::GetChildProcessHandle() {
    453  mozilla::AutoReadLock handleLock(mHandleLock);
    454  return mChildProcessHandle;
    455 }
    456 
    457 base::ProcessId GeckoChildProcessHost::GetChildProcessId() {
    458  mozilla::AutoReadLock handleLock(mHandleLock);
    459  if (!mChildProcessHandle) {
    460    return 0;
    461  }
    462  return base::GetProcId(mChildProcessHandle);
    463 }
    464 
    465 #ifdef XP_MACOSX
    466 task_t GeckoChildProcessHost::GetChildTask() {
    467  mozilla::AutoReadLock handleLock(mHandleLock);
    468  return mChildTask;
    469 }
    470 #endif
    471 
    472 void GeckoChildProcessHost::RemoveFromProcessList() {
    473  StaticMutexAutoLock lock(sMutex);
    474  if (!sGeckoChildProcessHosts) {
    475    return;
    476  }
    477  LinkedListElement<GeckoChildProcessHost>::removeFrom(
    478      *sGeckoChildProcessHosts);
    479 }
    480 
    481 void GeckoChildProcessHost::Destroy() {
    482  MOZ_RELEASE_ASSERT(!mDestroying);
    483  // We can remove from the list before it's really destroyed
    484  RemoveFromProcessList();
    485  RefPtr<ProcessHandlePromise> whenReady = mHandlePromise;
    486 
    487  if (!whenReady) {
    488    // AsyncLaunch not called yet, so dispatch immediately.
    489    whenReady = ProcessHandlePromise::CreateAndReject(
    490        LaunchError("DestroyEarly"), __func__);
    491  }
    492 
    493  using Value = ProcessHandlePromise::ResolveOrRejectValue;
    494  mDestroying = true;
    495 
    496  // Synchronously invoke `delete this` if we're already shutting the IO thread
    497  // down to ensure we're cleaned up before the thread dies. This is safe as we
    498  // can never resolve `mHandlePromise` after the IO thread goes away.
    499  MessageLoop* loop = MessageLoop::current();
    500  if (loop && MessageLoop::TYPE_IO == loop->type() &&
    501      !loop->IsAcceptingTasks()) {
    502    delete this;
    503    return;
    504  }
    505 
    506  // If we're not in shutdown, do this async, as we may still be waiting for the
    507  // child process PID from the launcher thread.
    508  whenReady->Then(XRE_GetAsyncIOEventTarget(), __func__,
    509                  [this](const Value&) { delete this; });
    510 }
    511 
    512 // static
    513 mozilla::BinPathType BaseProcessLauncher::GetPathToBinary(
    514    FilePath& exePath, GeckoProcessType processType) {
    515  exePath = {};
    516  BinPathType pathType = XRE_GetChildProcBinPathType(processType);
    517 
    518  if (pathType == BinPathType::Self) {
    519 #if defined(XP_WIN)
    520    wchar_t exePathBuf[MAXPATHLEN];
    521    if (!::GetModuleFileNameW(nullptr, exePathBuf, MAXPATHLEN)) {
    522      MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
    523    }
    524    exePath = FilePath::FromWStringHack(exePathBuf);
    525 #else
    526    exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
    527 #endif
    528    return pathType;
    529  }
    530 
    531 #ifdef MOZ_WIDGET_COCOA
    532  // To support different child process types having different codesigning
    533  // entitlements, different executables are used to run some child process
    534  // types.
    535  nsCString bundleName;
    536  std::string executableLeafName;
    537  if (processType == GeckoProcessType_GMPlugin &&
    538      mozilla::StaticPrefs::media_plugin_helper_process_enabled()) {
    539    // Use the media plugin helper executable
    540    bundleName = MOZ_EME_PROCESS_BUNDLENAME;
    541    executableLeafName = MOZ_EME_PROCESS_NAME_BRANDED;
    542  } else if (processType == GeckoProcessType_GPU &&
    543             mozilla::StaticPrefs::layers_gpu_process_executable_enabled()) {
    544    // Use the GPU helper executable
    545    bundleName = MOZ_GPU_PROCESS_BUNDLENAME;
    546    executableLeafName = MOZ_GPU_PROCESS_NAME_BRANDED;
    547  } else {
    548    // the default child process executable
    549    bundleName = MOZ_CHILD_PROCESS_BUNDLENAME;
    550    executableLeafName = MOZ_CHILD_PROCESS_NAME;
    551  }
    552 #endif
    553 
    554  if (ShouldHaveDirectoryService()) {
    555    MOZ_ASSERT(gGREBinPath);
    556 #ifdef XP_WIN
    557    exePath = FilePath(char16ptr_t(gGREBinPath));
    558 #elif MOZ_WIDGET_COCOA
    559    nsCOMPtr<nsIFile> childProcPath;
    560    if (NS_SUCCEEDED(NS_NewLocalFile(nsDependentString(gGREBinPath),
    561                                     getter_AddRefs(childProcPath)))) {
    562      // We need to use an App Bundle on OS X so that we can hide
    563      // the dock icon. See Bug 557225.
    564      if (NS_SUCCEEDED(childProcPath->AppendNative(bundleName)) &&
    565          NS_SUCCEEDED(childProcPath->AppendNative("Contents"_ns)) &&
    566          NS_SUCCEEDED(childProcPath->AppendNative("MacOS"_ns))) {
    567        nsCString tempCPath;
    568        if (NS_SUCCEEDED(childProcPath->GetNativePath(tempCPath))) {
    569          exePath = FilePath(tempCPath.get());
    570        }
    571      }
    572    }
    573 #else
    574    nsCString path;
    575    if (NS_SUCCEEDED(
    576            NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path))) {
    577      exePath = FilePath(path.get());
    578    }
    579 #endif
    580  }
    581 
    582  if (exePath.empty()) {
    583 #ifdef XP_WIN
    584    exePath =
    585        FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
    586 #else
    587    exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
    588 #endif
    589    exePath = exePath.DirName();
    590  }
    591 
    592 #ifdef MOZ_WIDGET_COCOA
    593  exePath = exePath.Append(executableLeafName);
    594 #else
    595  exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
    596 #endif
    597 
    598  return pathType;
    599 }
    600 
    601 #ifdef MOZ_WIDGET_COCOA
    602 class AutoCFTypeObject {
    603 public:
    604  explicit AutoCFTypeObject(CFTypeRef object) { mObject = object; }
    605  ~AutoCFTypeObject() { ::CFRelease(mObject); }
    606 
    607 private:
    608  CFTypeRef mObject;
    609 };
    610 #endif
    611 
    612 // We start the unique IDs at 1 so that 0 can be used to mean that
    613 // a component has no unique ID assigned to it.
    614 uint32_t GeckoChildProcessHost::sNextUniqueID = 1;
    615 
    616 /* static */
    617 uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID++; }
    618 
    619 /* static */
    620 void GeckoChildProcessHost::SetEnv(const char* aKey, const char* aValue) {
    621  MOZ_ASSERT(mLaunchOptions);
    622  mLaunchOptions->env_map[ENVIRONMENT_STRING(aKey)] =
    623      ENVIRONMENT_STRING(aValue);
    624 }
    625 
    626 bool GeckoChildProcessHost::PrepareLaunch(
    627    geckoargs::ChildProcessArgs& aExtraOpts) {
    628 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
    629  if (!SandboxLaunch::Configure(mProcessType, mSandbox, aExtraOpts,
    630                                mLaunchOptions.get())) {
    631    return false;
    632  }
    633 #endif
    634 
    635 #ifdef XP_WIN
    636 
    637 #  if defined(MOZ_SANDBOX)
    638  // We need to get the pref here as the process is launched off main thread.
    639  if (mProcessType == GeckoProcessType_Content) {
    640    // Win32k Lockdown state must be initialized on the main thread.
    641    // This is our last chance to do it before it is read on the IPC Launch
    642    // thread
    643    GetWin32kLockdownState();
    644    mSandboxLevel = GetEffectiveContentSandboxLevel();
    645    mEnableSandboxLogging =
    646        Preferences::GetBool("security.sandbox.logging.enabled");
    647 
    648    // We currently have to whitelist certain paths for tests to work in some
    649    // development configurations.
    650    nsAutoString readPaths;
    651    nsresult rv = Preferences::GetString(
    652        "security.sandbox.content.read_path_whitelist", readPaths);
    653    if (NS_SUCCEEDED(rv)) {
    654      for (const nsAString& readPath : readPaths.Split(',')) {
    655        nsString trimmedPath(readPath);
    656        trimmedPath.Trim(" ", true, true);
    657        std::wstring resolvedPath(trimmedPath.Data());
    658        // Check if path ends with '\' as this indicates we want to give read
    659        // access to a directory and so it needs a wildcard.
    660        if (resolvedPath.back() == L'\\') {
    661          resolvedPath.append(L"*");
    662        }
    663        mAllowedFilesRead.push_back(resolvedPath);
    664      }
    665    }
    666  }
    667 #  endif
    668 
    669 #  if defined(MOZ_SANDBOX)
    670  // For other process types we can't rely on them being launched on main
    671  // thread and they may not have access to prefs in the child process, so allow
    672  // them to turn on logging via an environment variable.
    673  mEnableSandboxLogging =
    674      mEnableSandboxLogging || !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
    675 
    676 #  endif
    677 #elif defined(XP_MACOSX)
    678 #  if defined(MOZ_SANDBOX)
    679  if (ShouldHaveDirectoryService() &&
    680      mProcessType != GeckoProcessType_GMPlugin) {
    681    (void)NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
    682                                 getter_AddRefs(mProfileDir));
    683  }
    684 #  endif
    685 #endif
    686 
    687  return true;
    688 }
    689 
    690 #ifdef XP_WIN
    691 void GeckoChildProcessHost::InitWindowsGroupID() {
    692  // On Win7+, pass the application user model to the child, so it can
    693  // register with it. This insures windows created by the container
    694  // properly group with the parent app on the Win7 taskbar.
    695  nsCOMPtr<nsIWinTaskbar> taskbarInfo = do_GetService(NS_TASKBAR_CONTRACTID);
    696  if (taskbarInfo) {
    697    bool isSupported = false;
    698    taskbarInfo->GetAvailable(&isSupported);
    699    nsAutoString appId;
    700    if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
    701      MOZ_ASSERT(mGroupId.EqualsLiteral("-"));
    702      mGroupId.Assign(appId);
    703    }
    704  }
    705 }
    706 #endif
    707 
    708 bool GeckoChildProcessHost::SyncLaunch(geckoargs::ChildProcessArgs aExtraOpts,
    709                                       int aTimeoutMs) {
    710  if (!AsyncLaunch(std::move(aExtraOpts))) {
    711    return false;
    712  }
    713  return WaitUntilConnected(aTimeoutMs);
    714 }
    715 
    716 // Note: for most process types, we currently call AsyncLaunch, and therefore
    717 // the *ProcessLauncher constructor, on the main thread, while the
    718 // ProcessLauncher methods to actually execute the launch are called on the IO
    719 // or IPC launcher thread. GMP processes are an exception - the GMP code
    720 // invokes GeckoChildProcessHost from non-main-threads, and therefore we cannot
    721 // rely on having access to mainthread-only services (like the directory
    722 // service) from this code if we're launching that type of process.
    723 bool GeckoChildProcessHost::AsyncLaunch(
    724    geckoargs::ChildProcessArgs aExtraOpts) {
    725  if (!PrepareLaunch(aExtraOpts)) {
    726    return false;
    727  }
    728 
    729 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
    730  if (IsMacSandboxLaunchEnabled() &&
    731      !AppendMacSandboxParams(aExtraOpts.mArgs)) {
    732    return false;
    733  }
    734 #endif
    735 
    736  RefPtr<BaseProcessLauncher> launcher =
    737      new ProcessLauncher(this, std::move(aExtraOpts));
    738  TimeStamp startTimeStamp = TimeStamp::Now();
    739 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
    740  launcher->SetLaunchArchitecture(mLaunchArch);
    741 #endif
    742 
    743  // Note: Destroy() waits on mHandlePromise to delete |this|. As such, we want
    744  // to be sure that all of our post-launch processing on |this| happens before
    745  // mHandlePromise notifies.
    746  MOZ_ASSERT(mHandlePromise == nullptr);
    747  mHandlePromise =
    748      mozilla::InvokeAsync<GeckoChildProcessHost*>(
    749          XRE_GetAsyncIOEventTarget(), launcher.get(), __func__,
    750          &BaseProcessLauncher::Launch, this)
    751          ->Then(
    752              XRE_GetAsyncIOEventTarget(), __func__,
    753              [this, startTimeStamp](LaunchResults&& aResults) {
    754                {
    755                  {
    756                    mozilla::AutoWriteLock handleLock(mHandleLock);
    757                    if (!OpenPrivilegedHandle(base::GetProcId(aResults.mHandle))
    758 #ifdef XP_WIN
    759                        // If we failed in opening the process handle, try
    760                        // harder by duplicating one.
    761                        && !::DuplicateHandle(
    762                               ::GetCurrentProcess(), aResults.mHandle,
    763                               ::GetCurrentProcess(), &mChildProcessHandle,
    764                               PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
    765                                   PROCESS_QUERY_INFORMATION | PROCESS_VM_READ |
    766                                   SYNCHRONIZE,
    767                               FALSE, 0)
    768 #endif  // XP_WIN
    769                    ) {
    770                      MOZ_CRASH("cannot open handle to child process");
    771                    }
    772                    // The original handle is no longer needed; it must
    773                    // be closed to prevent a resource leak.
    774                    base::CloseProcessHandle(aResults.mHandle);
    775                    // FIXME (bug 1720523): define a cross-platform
    776                    // "safe" invalid value to use in places like this.
    777                    aResults.mHandle = 0;
    778 
    779 #ifdef XP_MACOSX
    780                    this->mChildTask = aResults.mChildTask;
    781 #endif
    782 #ifdef XP_IOS
    783                    this->mExtensionKitProcess = aResults.mExtensionKitProcess;
    784                    this->mXPCConnection = aResults.mXPCConnection;
    785                    this->mForegroundCapabilityGrant =
    786                        std::move(aResults.mForegroundCapabilityGrant);
    787 #endif
    788 
    789                    if (mNodeChannel) {
    790                      mNodeChannel->SetOtherPid(
    791                          base::GetProcId(this->mChildProcessHandle));
    792 #ifdef XP_MACOSX
    793                      mNodeChannel->SetMachTaskPort(this->mChildTask);
    794 #endif
    795                    }
    796                  }
    797 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
    798                  this->mSandboxBroker = std::move(aResults.mSandboxBroker);
    799 #endif
    800 
    801                  glean::process::child_launch.AccumulateRawDuration(
    802                      TimeStamp::Now() - startTimeStamp);
    803 
    804                  MonitorAutoLock lock(mMonitor);
    805                  // The OnChannel{Connected,Error} may have already advanced
    806                  // the state.
    807                  if (mProcessState < PROCESS_CREATED) {
    808                    mProcessState = PROCESS_CREATED;
    809                  }
    810                  lock.Notify();
    811                }
    812                return ProcessHandlePromise::CreateAndResolve(
    813                    GetChildProcessHandle(), __func__);
    814              },
    815              [this](const LaunchError aError) {
    816                // WaitUntilConnected might be waiting for us to signal.
    817                // If something failed let's set the error state and notify.
    818                CHROMIUM_LOG(ERROR)
    819                    << "Failed to launch "
    820                    << XRE_GeckoProcessTypeToString(mProcessType)
    821                    << " subprocess @" << aError.FunctionName()
    822                    << " (Error:" << aError.ErrorCode() << ")";
    823                glean::subprocess::launch_failure
    824                    .Get(nsDependentCString(
    825                        XRE_GeckoProcessTypeToString(mProcessType)))
    826                    .Add(1);
    827                nsCString telemetryKey = nsPrintfCString(
    828 #if defined(XP_WIN)
    829                    "%s,0x%lx,%s",
    830 #else
    831                    "%s,%ld,%s",
    832 #endif
    833                    aError.FunctionName().get(), aError.ErrorCode(),
    834                    XRE_GeckoProcessTypeToString(mProcessType));
    835                // Max telemetry key is 72 chars
    836                // https://searchfox.org/mozilla-central/rev/c244b16815d1fc827d141472b9faac5610f250e7/toolkit/components/telemetry/core/TelemetryScalar.cpp#105
    837                if (telemetryKey.Length() > 72) {
    838                  NS_WARNING(nsPrintfCString("Truncating telemetry key: %s",
    839                                             telemetryKey.get())
    840                                 .get());
    841                  telemetryKey.Truncate(72);
    842                }
    843                glean::dom_parentprocess::process_launch_errors
    844                    .Get(telemetryKey)
    845                    .Add(1);
    846                {
    847                  MonitorAutoLock lock(mMonitor);
    848                  mProcessState = PROCESS_ERROR;
    849                  lock.Notify();
    850                }
    851                return ProcessHandlePromise::CreateAndReject(aError, __func__);
    852              });
    853  return true;
    854 }
    855 
    856 bool GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs) {
    857  AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER);
    858 
    859  // NB: this uses a different mechanism than the chromium parent
    860  // class.
    861  TimeDuration timeout = (aTimeoutMs > 0)
    862                             ? TimeDuration::FromMilliseconds(aTimeoutMs)
    863                             : TimeDuration::Forever();
    864 
    865  MonitorAutoLock lock(mMonitor);
    866  TimeStamp waitStart = TimeStamp::Now();
    867  TimeStamp current;
    868 
    869  // We'll receive several notifications, we need to exit when we
    870  // have either successfully launched or have timed out.
    871  while (mProcessState != PROCESS_CONNECTED) {
    872    // If there was an error then return it, don't wait out the timeout.
    873    if (mProcessState == PROCESS_ERROR) {
    874      break;
    875    }
    876 
    877    CVStatus status = lock.Wait(timeout);
    878    if (status == CVStatus::Timeout) {
    879      break;
    880    }
    881 
    882    if (timeout != TimeDuration::Forever()) {
    883      current = TimeStamp::Now();
    884      timeout -= current - waitStart;
    885      waitStart = current;
    886    }
    887  }
    888 
    889  return mProcessState == PROCESS_CONNECTED;
    890 }
    891 
    892 bool GeckoChildProcessHost::WaitForProcessHandle() {
    893  MonitorAutoLock lock(mMonitor);
    894  while (mProcessState < PROCESS_CREATED) {
    895    lock.Wait();
    896  }
    897  MOZ_ASSERT(mProcessState == PROCESS_ERROR || GetChildProcessHandle());
    898 
    899  return mProcessState < PROCESS_ERROR;
    900 }
    901 
    902 bool GeckoChildProcessHost::LaunchAndWaitForProcessHandle(
    903    geckoargs::ChildProcessArgs aExtraOpts) {
    904  if (!AsyncLaunch(std::move(aExtraOpts))) {
    905    return false;
    906  }
    907  return WaitForProcessHandle();
    908 }
    909 
    910 bool GeckoChildProcessHost::InitializeChannel(
    911    IPC::Channel::ChannelHandle* aClientHandle) {
    912  mNodeController = NodeController::GetSingleton();
    913  if (!mNodeController->InviteChildProcess(this, aClientHandle, &mInitialPort,
    914                                           getter_AddRefs(mNodeChannel))) {
    915    return false;
    916  }
    917 
    918  MOZ_ASSERT(mInitialPort.IsValid());
    919  MOZ_ASSERT(mNodeChannel);
    920 
    921  MonitorAutoLock lock(mMonitor);
    922  mProcessState = CHANNEL_INITIALIZED;
    923  lock.Notify();
    924  return true;
    925 }
    926 
    927 void GeckoChildProcessHost::SetAlreadyDead() {
    928  mozilla::AutoWriteLock handleLock(mHandleLock);
    929  if (mChildProcessHandle &&
    930      mChildProcessHandle != base::kInvalidProcessHandle) {
    931    base::CloseProcessHandle(mChildProcessHandle);
    932  }
    933 
    934  mChildProcessHandle = 0;
    935 }
    936 
    937 void BaseProcessLauncher::GetChildLogName(const char* origLogName,
    938                                          nsACString& buffer) {
    939 #ifdef XP_WIN
    940  // On Windows we must expand relative paths because sandboxing rules
    941  // bound only to full paths.  fopen fowards to NtCreateFile which checks
    942  // the path against the sanboxing rules as passed to fopen (left relative).
    943  char absPath[MAX_PATH + 2];
    944  if (_fullpath(absPath, origLogName, sizeof(absPath))) {
    945    buffer.Append(absPath);
    946  } else
    947 #endif
    948  {
    949    buffer.Append(origLogName);
    950  }
    951 
    952  // Remove .moz_log extension to avoid its duplication, it will be added
    953  // automatically by the logging backend
    954  static constexpr auto kMozLogExt = nsLiteralCString{MOZ_LOG_FILE_EXTENSION};
    955  if (StringEndsWith(buffer, kMozLogExt)) {
    956    buffer.Truncate(buffer.Length() - kMozLogExt.Length());
    957  }
    958 
    959  // Append child-specific postfix to name
    960  buffer.AppendLiteral(".child-");
    961  buffer.AppendASCII(mChildIDString);
    962 }
    963 
    964 // We use a single dedicated thread for process launching. This is required on
    965 // Windows (due to sandboxing code), Android (due to the java code) and Linux
    966 // (due to ForkServerChild). Using a single thread is not required on macOS or
    967 // iOS, but we use one to keep the implementation consistent.
    968 //
    969 // The only tier-1 platform where we do not need a dedicated thread is macOS,
    970 // however we use a dedicated thread there as well for consistency and
    971 // simplicity of implementation.
    972 
    973 static mozilla::StaticMutex gIPCLaunchThreadMutex;
    974 static mozilla::StaticRefPtr<nsIThread> gIPCLaunchThread
    975    MOZ_GUARDED_BY(gIPCLaunchThreadMutex);
    976 
    977 class IPCLaunchThreadObserver final : public nsIObserver {
    978 public:
    979  NS_DECL_ISUPPORTS
    980  NS_DECL_NSIOBSERVER
    981 protected:
    982  virtual ~IPCLaunchThreadObserver() = default;
    983 };
    984 
    985 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver, nsIObserver, nsISupports)
    986 
    987 NS_IMETHODIMP
    988 IPCLaunchThreadObserver::Observe(nsISupports* aSubject, const char* aTopic,
    989                                 const char16_t* aData) {
    990  MOZ_RELEASE_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0);
    991 
    992  nsCOMPtr<nsIThread> thread;
    993  {
    994    StaticMutexAutoLock lock(gIPCLaunchThreadMutex);
    995    thread = gIPCLaunchThread.forget();
    996  }
    997 
    998  nsresult rv = thread ? thread->Shutdown() : NS_OK;
    999  (void)NS_WARN_IF(NS_FAILED(rv));
   1000  return rv;
   1001 }
   1002 
   1003 nsCOMPtr<nsISerialEventTarget> GetIPCLauncher() {
   1004  StaticMutexAutoLock lock(gIPCLaunchThreadMutex);
   1005  if (!gIPCLaunchThread) {
   1006    nsCOMPtr<nsIThread> thread;
   1007    nsresult rv = NS_NewNamedThread("IPC Launch"_ns, getter_AddRefs(thread));
   1008    if (!NS_WARN_IF(NS_FAILED(rv))) {
   1009      NS_DispatchToMainThread(
   1010          NS_NewRunnableFunction("GeckoChildProcessHost::GetIPCLauncher", [] {
   1011            nsCOMPtr<nsIObserverService> obsService =
   1012                mozilla::services::GetObserverService();
   1013            nsCOMPtr<nsIObserver> obs = new IPCLaunchThreadObserver();
   1014            obsService->AddObserver(obs, "xpcom-shutdown-threads", false);
   1015          }));
   1016      gIPCLaunchThread = thread.forget();
   1017    }
   1018  }
   1019 
   1020  nsCOMPtr<nsISerialEventTarget> thread = gIPCLaunchThread.get();
   1021  MOZ_DIAGNOSTIC_ASSERT(thread);
   1022  return thread;
   1023 }
   1024 
   1025 void
   1026 #if defined(XP_WIN)
   1027 AddAppDirToCommandLine(CommandLine& aCmdLine, nsIFile* aAppDir)
   1028 #else
   1029 AddAppDirToCommandLine(geckoargs::ChildProcessArgs& aCmdLine,
   1030                       nsIFile* aAppDir, nsIFile* aProfileDir)
   1031 #endif
   1032 {
   1033  // Content processes need access to application resources, so pass
   1034  // the full application directory path to the child process.
   1035  if (aAppDir) {
   1036 #if defined(XP_WIN)
   1037    nsString path;
   1038    MOZ_ALWAYS_SUCCEEDS(aAppDir->GetPath(path));
   1039    aCmdLine.AppendLooseValue(UTF8ToWide(geckoargs::sAppDir.Name()));
   1040    std::wstring wpath(path.get());
   1041    aCmdLine.AppendLooseValue(wpath);
   1042 #else
   1043    nsAutoCString path;
   1044    MOZ_ALWAYS_SUCCEEDS(aAppDir->GetNativePath(path));
   1045    geckoargs::sAppDir.Put(path.get(), aCmdLine);
   1046 #endif
   1047 
   1048 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
   1049    // Full path to the profile dir
   1050    if (aProfileDir) {
   1051      // If the profile doesn't exist, normalization will
   1052      // fail. But we don't return an error here because some
   1053      // tests require startup with a missing profile dir.
   1054      // For users, almost universally, the profile will be in
   1055      // the home directory and normalization isn't required.
   1056      (void)aProfileDir->Normalize();
   1057      nsAutoCString path;
   1058      MOZ_ALWAYS_SUCCEEDS(aProfileDir->GetNativePath(path));
   1059      geckoargs::sProfile.Put(path.get(), aCmdLine);
   1060    }
   1061 #endif
   1062  }
   1063 }
   1064 
   1065 #if defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
   1066 static bool Contains(const geckoargs::ChildProcessArgs& aExtraOpts,
   1067                     const char* aValue) {
   1068  return std::any_of(aExtraOpts.mArgs.begin(), aExtraOpts.mArgs.end(),
   1069                     [&](const std::string arg) {
   1070                       return arg.find(aValue) != std::string::npos;
   1071                     });
   1072 }
   1073 #endif  // defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
   1074 
   1075 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::PerformAsyncLaunch() {
   1076  Result<Ok, LaunchError> aError = DoSetup();
   1077  if (aError.isErr()) {
   1078    return ProcessLaunchPromise::CreateAndReject(aError.unwrapErr(), __func__);
   1079  }
   1080  return DoLaunch()->Then(
   1081      mLaunchThread, __func__,
   1082      [self =
   1083           RefPtr{this}](ProcessLaunchPromise::ResolveOrRejectValue&& aResult) {
   1084        // Explicitly destroy any outstanding references to HANDLEs which may be
   1085        // held by mChildArgs before resolving.
   1086        //
   1087        // NOTE: This is technically redundant, as it will happen naturally as
   1088        // the `BaseProcessLauncher` is destroyed, but this step makes it
   1089        // explicit. If we leaked one of these HANDLEs, we could fail to detect
   1090        // a child process shutting down or crashing.
   1091        self->mChildArgs = {};
   1092        return ProcessLaunchPromise::CreateAndResolveOrReject(
   1093            std::move(aResult), __func__);
   1094      });
   1095 }
   1096 
   1097 Result<Ok, LaunchError> BaseProcessLauncher::DoSetup() {
   1098  RefPtr<BaseProcessLauncher> self = this;
   1099  GetProfilerEnvVarsForChildProcess([self](const char* key, const char* value) {
   1100    self->mLaunchOptions->env_map[ENVIRONMENT_STRING(key)] =
   1101        ENVIRONMENT_STRING(value);
   1102  });
   1103 #ifdef MOZ_MEMORY
   1104  if (mProcessType == GeckoProcessType_Content) {
   1105    nsAutoCString mallocOpts(PR_GetEnv("MALLOC_OPTIONS"));
   1106    // Disable randomization of small arenas in content.
   1107    mallocOpts.Append("r");
   1108    self->mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MALLOC_OPTIONS")] =
   1109        ENVIRONMENT_STRING(mallocOpts.get());
   1110  }
   1111 #endif
   1112 
   1113  MapChildLogging();
   1114 
   1115  geckoargs::sInitialChannelID.Put(mInitialChannelIdString, mChildArgs);
   1116 
   1117  geckoargs::sParentPid.Put(static_cast<uint64_t>(base::GetCurrentProcId()),
   1118                            mChildArgs);
   1119 
   1120  if (!CrashReporter::IsDummy() && CrashReporter::GetEnabled() &&
   1121      mProcessType != GeckoProcessType_ForkServer) {
   1122 #if defined(MOZ_WIDGET_COCOA) || defined(XP_WIN)
   1123    geckoargs::sCrashReporter.Put(CrashReporter::GetChildNotificationPipe(),
   1124                                  mChildArgs);
   1125 #elif defined(XP_UNIX) && !defined(XP_IOS)
   1126    UniqueFileHandle childCrashFd = CrashReporter::GetChildNotificationPipe();
   1127    if (!childCrashFd) {
   1128      return Err(LaunchError("DuplicateFileHandle failed"));
   1129    }
   1130    geckoargs::sCrashReporter.Put(std::move(childCrashFd), mChildArgs);
   1131 #endif  // XP_UNIX && !XP_IOS
   1132 
   1133    UniqueFileHandle crashHelperClientFd =
   1134        CrashReporter::RegisterChildIPCChannel();
   1135    if (crashHelperClientFd) {
   1136      geckoargs::sCrashHelper.Put(std::move(crashHelperClientFd), mChildArgs);
   1137    } else {
   1138      NS_WARNING("Could not create an IPC channel to the crash helper");
   1139    }
   1140  }
   1141 
   1142  return Ok();
   1143 }
   1144 
   1145 void BaseProcessLauncher::MapChildLogging() {
   1146  const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
   1147  const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
   1148 
   1149  if (origNSPRLogName) {
   1150    nsAutoCString nsprLogName;
   1151    GetChildLogName(origNSPRLogName, nsprLogName);
   1152    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("NSPR_LOG_FILE")] =
   1153        ENVIRONMENT_STRING(nsprLogName.get());
   1154  }
   1155  if (origMozLogName) {
   1156    nsAutoCString mozLogName;
   1157    GetChildLogName(origMozLogName, mozLogName);
   1158    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MOZ_LOG_FILE")] =
   1159        ENVIRONMENT_STRING(mozLogName.get());
   1160  }
   1161 
   1162  // `RUST_LOG_CHILD` is meant for logging child processes only.
   1163  nsAutoCString childRustLog(PR_GetEnv("RUST_LOG_CHILD"));
   1164  if (!childRustLog.IsEmpty()) {
   1165    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("RUST_LOG")] =
   1166        ENVIRONMENT_STRING(childRustLog.get());
   1167  }
   1168 }
   1169 
   1170 #if defined(MOZ_WIDGET_GTK)
   1171 Result<Ok, LaunchError> LinuxProcessLauncher::DoSetup() {
   1172  Result<Ok, LaunchError> aError = PosixProcessLauncher::DoSetup();
   1173  if (aError.isErr()) {
   1174    return aError;
   1175  }
   1176 
   1177  if (mProcessType == GeckoProcessType_Content) {
   1178    // disable IM module to avoid sandbox violation
   1179    mLaunchOptions->env_map["GTK_IM_MODULE"] = "gtk-im-context-simple";
   1180 
   1181    // Disable ATK accessibility code in content processes because it conflicts
   1182    // with the sandbox, and we proxy that information through the main process
   1183    // anyway.
   1184    mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
   1185  }
   1186 
   1187  return Ok();
   1188 }
   1189 #endif  // MOZ_WIDGET_GTK
   1190 
   1191 #ifdef XP_UNIX
   1192 Result<Ok, LaunchError> PosixProcessLauncher::DoSetup() {
   1193  Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup();
   1194  if (aError.isErr()) {
   1195    return aError;
   1196  }
   1197 
   1198  // XPCOM may not be initialized in some subprocesses.  We don't want
   1199  // to initialize XPCOM just for the directory service, especially
   1200  // since LD_LIBRARY_PATH is already set correctly in subprocesses
   1201  // (meaning that we don't need to set that up in the environment).
   1202  if (ShouldHaveDirectoryService()) {
   1203    MOZ_ASSERT(gGREBinPath);
   1204    nsCString path;
   1205    NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
   1206 #  if defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \
   1207      defined(XP_NETBSD) || defined(XP_OPENBSD)
   1208    const char* ld_library_path = PR_GetEnv("LD_LIBRARY_PATH");
   1209    nsCString new_ld_lib_path(path.get());
   1210 
   1211    if (ld_library_path && *ld_library_path) {
   1212      new_ld_lib_path.Append(':');
   1213      new_ld_lib_path.Append(ld_library_path);
   1214    }
   1215    mLaunchOptions->env_map["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
   1216 
   1217 #  elif XP_MACOSX
   1218    // With signed production Mac builds, the dynamic linker (dyld) will
   1219    // ignore dyld environment variables preventing the use of variables
   1220    // such as DYLD_LIBRARY_PATH and DYLD_INSERT_LIBRARIES.
   1221 
   1222    // If we're running with gtests, add the gtest XUL ahead of normal XUL on
   1223    // the DYLD_LIBRARY_PATH so that plugin-container.app loads it instead.
   1224    nsCString new_dyld_lib_path(path.get());
   1225    if (PR_GetEnv("MOZ_RUN_GTEST")) {
   1226      new_dyld_lib_path = path + "/gtest:"_ns + new_dyld_lib_path;
   1227      mLaunchOptions->env_map["DYLD_LIBRARY_PATH"] = new_dyld_lib_path.get();
   1228    }
   1229 
   1230    // DYLD_INSERT_LIBRARIES is currently unused by default but we allow
   1231    // it to be set by the external environment.
   1232    const char* interpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
   1233    if (interpose && strlen(interpose) > 0) {
   1234      mLaunchOptions->env_map["DYLD_INSERT_LIBRARIES"] = interpose;
   1235    }
   1236 
   1237    // Prevent connection attempts to diagnosticd(8) to save cycles. Log
   1238    // messages can trigger these connection attempts, but access to
   1239    // diagnosticd is blocked in sandboxed child processes.
   1240 #    if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
   1241    if (mDisableOSActivityMode) {
   1242      mLaunchOptions->env_map["OS_ACTIVITY_MODE"] = "disable";
   1243    }
   1244 #    endif  // defined(MOZ_SANDBOX)
   1245 #  endif
   1246  }
   1247 
   1248  FilePath exePath;
   1249  BinPathType pathType = GetPathToBinary(exePath, mProcessType);
   1250 
   1251  // Make sure the executable path is present at the start of our argument list.
   1252  // If we're using BinPathType::Self, also add the `-contentproc` argument.
   1253  if (pathType == BinPathType::Self) {
   1254    std::string args[]{exePath.value(), "-contentproc"};
   1255    mChildArgs.mArgs.insert(mChildArgs.mArgs.begin(), std::begin(args),
   1256                            std::end(args));
   1257  } else {
   1258    mChildArgs.mArgs.insert(mChildArgs.mArgs.begin(), exePath.value());
   1259  }
   1260 
   1261  if ((mProcessType == GeckoProcessType_Content ||
   1262       mProcessType == GeckoProcessType_ForkServer) &&
   1263      Omnijar::IsInitialized()) {
   1264    // Make sure that child processes can find the omnijar, if they
   1265    // use full XPCOM.  See Omnijar::ChildProcessInit and its callers.
   1266    nsAutoCString path;
   1267    nsCOMPtr<nsIFile> greFile = Omnijar::GetPath(Omnijar::GRE);
   1268    if (greFile && NS_SUCCEEDED(greFile->GetNativePath(path))) {
   1269      geckoargs::sGREOmni.Put(path.get(), mChildArgs);
   1270    }
   1271    nsCOMPtr<nsIFile> appFile = Omnijar::GetPath(Omnijar::APP);
   1272    if (appFile && NS_SUCCEEDED(appFile->GetNativePath(path))) {
   1273      geckoargs::sAppOmni.Put(path.get(), mChildArgs);
   1274    }
   1275  }
   1276 
   1277  if (mProcessType != GeckoProcessType_GMPlugin) {
   1278    // Add the application directory path (-appdir path)
   1279 #  ifdef XP_MACOSX
   1280    AddAppDirToCommandLine(mChildArgs, mAppDir, mProfileDir);
   1281 #  else
   1282    AddAppDirToCommandLine(mChildArgs, mAppDir, nullptr);
   1283 #  endif
   1284  }
   1285 
   1286  // XXX Command line params past this point are expected to be at
   1287  // the end of the command line string, and in a specific order.
   1288  // See XRE_InitChildProcess in nsEmbedFunction.
   1289 
   1290 #  ifdef MOZ_WIDGET_COCOA
   1291  {
   1292    auto* thisMac = static_cast<MacProcessLauncher*>(this);
   1293    kern_return_t kr =
   1294        bootstrap_check_in(bootstrap_port, thisMac->mMachConnectionName.c_str(),
   1295                           getter_Transfers(thisMac->mParentRecvPort));
   1296    if (kr != KERN_SUCCESS) {
   1297      CHROMIUM_LOG(ERROR) << "parent bootstrap_check_in failed: "
   1298                          << mach_error_string(kr);
   1299      return Err(LaunchError("bootstrap_check_in", kr));
   1300    }
   1301    mChildArgs.mArgs.push_back(thisMac->mMachConnectionName.c_str());
   1302  }
   1303 #  endif  // MOZ_WIDGET_COCOA
   1304 
   1305  mChildArgs.mArgs.push_back(mChildIDString);
   1306 
   1307  mChildArgs.mArgs.push_back(ChildProcessType());
   1308 
   1309 #  ifdef MOZ_ENABLE_FORKSERVER
   1310  // Any unexpected fds given to the fork server could be leaked into
   1311  // child processes if they aren't closed properly; this assertion is
   1312  // a reminder to deal with that.
   1313  MOZ_ASSERT(mProcessType != GeckoProcessType_ForkServer ||
   1314                 mChildArgs.mFiles.size() == 2,
   1315             "wrong number of FDs for the fork server");
   1316 #  endif
   1317 
   1318 #  if !defined(MOZ_WIDGET_ANDROID)
   1319  // Add any files which need to be transferred to fds_to_remap.
   1320  // NOTE: This doesn't transfer ownership of the files out of `mChildArgs`.
   1321  geckoargs::AddToFdsToRemap(mChildArgs, mLaunchOptions->fds_to_remap);
   1322 #  endif
   1323 
   1324  return Ok();
   1325 }
   1326 #endif  // XP_UNIX
   1327 
   1328 #if defined(MOZ_WIDGET_ANDROID)
   1329 RefPtr<ProcessLaunchPromise> AndroidProcessLauncher::DoLaunch() {
   1330  return LaunchAndroidService(mProcessType, mChildArgs)
   1331      ->Then(
   1332          mLaunchThread, __func__,
   1333          [self = RefPtr{this}](ProcessHandle aHandle) {
   1334            self->mResults.mHandle = aHandle;
   1335            return ProcessLaunchPromise::CreateAndResolve(
   1336                std::move(self->mResults), __func__);
   1337          },
   1338          [](LaunchError aError) {
   1339            return ProcessLaunchPromise::CreateAndReject(aError, __func__);
   1340          });
   1341 }
   1342 #endif  // MOZ_WIDGET_ANDROID
   1343 
   1344 #ifdef XP_UNIX
   1345 RefPtr<ProcessLaunchPromise> PosixProcessLauncher::DoLaunch() {
   1346  Result<Ok, LaunchError> result = Err(LaunchError{"Launch not attempted"});
   1347 #  ifdef MOZ_ENABLE_FORKSERVER
   1348  if (mProcessType != GeckoProcessType_ForkServer && ForkServiceChild::Get()) {
   1349    result = ForkServiceChild::Get()->SendForkNewSubprocess(
   1350        std::move(mChildArgs), std::move(*mLaunchOptions), &mResults.mHandle);
   1351  } else
   1352 #  endif
   1353  {
   1354    result = base::LaunchApp(mChildArgs.mArgs, std::move(*mLaunchOptions),
   1355                             &mResults.mHandle);
   1356  }
   1357 
   1358  if (result.isErr()) {
   1359    return ProcessLaunchPromise::CreateAndReject(result.unwrapErr(), __func__);
   1360  }
   1361  return ProcessLaunchPromise::CreateAndResolve(std::move(mResults), __func__);
   1362 }
   1363 #endif  // XP_UNIX
   1364 
   1365 #ifdef XP_IOS
   1366 Result<Ok, LaunchError> IosProcessLauncher::DoSetup() {
   1367  Result<Ok, LaunchError> aError = PosixProcessLauncher::DoSetup();
   1368  if (aError.isErr()) {
   1369    return aError;
   1370  }
   1371 
   1372  // Unlike on other platforms, the child process will not inherit the parent
   1373  // process's environment, so we need to manually copy over environment
   1374  // variables.
   1375  for (char** envp = environ; *envp != 0; ++envp) {
   1376    // Only copy over `MOZ_` keys.
   1377    if (strncmp(*envp, "MOZ_", 4) != 0) {
   1378      continue;
   1379    }
   1380 
   1381    std::string_view env{*envp};
   1382    size_t eqIdx = env.find('=');
   1383    if (eqIdx == std::string_view::npos) {
   1384      continue;
   1385    }
   1386 
   1387    std::string key{env.substr(0, eqIdx)};
   1388    if (mLaunchOptions->env_map.count(key)) {
   1389      // If the key already exists in the map, we don't want to overwrite it.
   1390      continue;
   1391    }
   1392 
   1393    mLaunchOptions->env_map[key] = env.substr(eqIdx + 1);
   1394  }
   1395  return Ok();
   1396 }
   1397 
   1398 RefPtr<ProcessLaunchPromise> IosProcessLauncher::DoLaunch() {
   1399  ExtensionKitProcess::Kind kind = ExtensionKitProcess::Kind::WebContent;
   1400  if (mProcessType == GeckoProcessType_GPU) {
   1401    kind = ExtensionKitProcess::Kind::Rendering;
   1402  } else if (mProcessType == GeckoProcessType_Socket) {
   1403    kind = ExtensionKitProcess::Kind::Networking;
   1404  }
   1405 
   1406  DarwinObjectPtr<xpc_object_t> bootstrapMessage =
   1407      AdoptDarwinObject(xpc_dictionary_create_empty());
   1408  xpc_dictionary_set_string(bootstrapMessage.get(), "message-name",
   1409                            "bootstrap");
   1410 
   1411  DarwinObjectPtr<xpc_object_t> environDict =
   1412      AdoptDarwinObject(xpc_dictionary_create_empty());
   1413  for (auto& [envKey, envValue] : mLaunchOptions->env_map) {
   1414    xpc_dictionary_set_string(environDict.get(), envKey.c_str(),
   1415                              envValue.c_str());
   1416  }
   1417  xpc_dictionary_set_value(bootstrapMessage.get(), "environ",
   1418                           environDict.get());
   1419 
   1420  // Setup stdout and stderr to inherit.
   1421  xpc_dictionary_set_fd(bootstrapMessage.get(), "stdout", STDOUT_FILENO);
   1422  xpc_dictionary_set_fd(bootstrapMessage.get(), "stderr", STDERR_FILENO);
   1423 
   1424  DarwinObjectPtr<xpc_object_t> argsArray =
   1425      AdoptDarwinObject(xpc_array_create_empty());
   1426  for (auto& argv : mChildArgs.mArgs) {
   1427    xpc_array_set_string(argsArray.get(), XPC_ARRAY_APPEND, argv.c_str());
   1428  }
   1429  MOZ_ASSERT(xpc_array_get_count(argsArray.get()) == mChildArgs.mArgs.size());
   1430  xpc_dictionary_set_value(bootstrapMessage.get(), "argv", argsArray.get());
   1431 
   1432  DarwinObjectPtr<xpc_object_t> fdsArray =
   1433      AdoptDarwinObject(xpc_array_create_empty());
   1434  for (auto& file : mChildArgs.mFiles) {
   1435    xpc_array_set_fd(fdsArray.get(), XPC_ARRAY_APPEND, file.get());
   1436  }
   1437  MOZ_ASSERT(xpc_array_get_count(fdsArray.get()) == mChildArgs.mFiles.size());
   1438  xpc_dictionary_set_value(bootstrapMessage.get(), "fds", fdsArray.get());
   1439 
   1440  DarwinObjectPtr<xpc_object_t> sendRightsArray =
   1441      AdoptDarwinObject(xpc_array_create_empty());
   1442  for (auto& sendRight : mChildArgs.mSendRights) {
   1443    // NOTE: As iOS doesn't expose an xpc_array_set_mach_send function, send
   1444    // rights are wrapped with single-key dictionaries.
   1445    DarwinObjectPtr<xpc_object_t> sendRightWrapper =
   1446        AdoptDarwinObject(xpc_dictionary_create_empty());
   1447    xpc_dictionary_set_mach_send(sendRightWrapper.get(), "port",
   1448                                 sendRight.get());
   1449    xpc_array_set_value(sendRightsArray.get(), XPC_ARRAY_APPEND,
   1450                        sendRightWrapper.get());
   1451  }
   1452  MOZ_ASSERT(xpc_array_get_count(sendRightsArray.get()) ==
   1453             mChildArgs.mSendRights.size());
   1454  xpc_dictionary_set_value(bootstrapMessage.get(), "sendRights",
   1455                           sendRightsArray.get());
   1456 
   1457  auto promise = MakeRefPtr<ProcessLaunchPromise::Private>(__func__);
   1458  ExtensionKitProcess::StartProcess(kind, [self = RefPtr{this}, promise,
   1459                                           bootstrapMessage =
   1460                                               std::move(bootstrapMessage)](
   1461                                              Result<ExtensionKitProcess,
   1462                                                     LaunchError>&& result) {
   1463    if (result.isErr()) {
   1464      CHROMIUM_LOG(ERROR) << "ExtensionKitProcess::StartProcess failed";
   1465      promise->Reject(result.unwrapErr(), __func__);
   1466      return;
   1467    }
   1468 
   1469    auto process = result.unwrap();
   1470    self->mResults.mForegroundCapabilityGrant =
   1471        process.GrantForegroundCapability();
   1472    self->mResults.mXPCConnection = process.MakeLibXPCConnection();
   1473    self->mResults.mExtensionKitProcess = Some(std::move(process));
   1474 
   1475    // We don't actually use the event handler for anything other than
   1476    // watching for errors. Once the promise is resolved, this becomes a
   1477    // no-op.
   1478    xpc_connection_set_event_handler(self->mResults.mXPCConnection.get(), ^(
   1479                                         xpc_object_t event) {
   1480      if (!event || xpc_get_type(event) == XPC_TYPE_ERROR) {
   1481        CHROMIUM_LOG(WARNING) << "XPC connection received encountered an error";
   1482        promise->Reject(LaunchError("xpc_connection_event_handler"), __func__);
   1483      }
   1484    });
   1485    xpc_connection_resume(self->mResults.mXPCConnection.get());
   1486 
   1487    // Send our bootstrap message to the content and wait for it to reply with
   1488    // the task port before resolving.
   1489    // FIXME: Should we have a time-out for if the child process doesn't respond
   1490    // in time? The main thread may be blocked while we're starting this
   1491    // process.
   1492    xpc_connection_send_message_with_reply(
   1493        self->mResults.mXPCConnection.get(), bootstrapMessage.get(), nullptr,
   1494        ^(xpc_object_t reply) {
   1495          if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
   1496            CHROMIUM_LOG(ERROR)
   1497                << "Got error sending XPC bootstrap message to child";
   1498            promise->Reject(
   1499                LaunchError("xpc_connection_send_message_with_reply error"),
   1500                __func__);
   1501            return;
   1502          }
   1503 
   1504          if (xpc_get_type(reply) != XPC_TYPE_DICTIONARY) {
   1505            CHROMIUM_LOG(ERROR)
   1506                << "Unexpected reply type for bootstrap message from child";
   1507            promise->Reject(
   1508                LaunchError(
   1509                    "xpc_connection_send_message_with_reply non-dictionary"),
   1510                __func__);
   1511            return;
   1512          }
   1513 
   1514          // NOTE: We have to trust the child to tell us its pid. The child is
   1515          // blocked by sandbox from sending its mach task.
   1516          // WebKit uses `xpc_connection_get_pid` to get the pid, however this
   1517          // is marked as unavailable on iOS.
   1518          //
   1519          // The process hasn't had a chance to load any untrusted content at
   1520          // this point, so we should be able to trust it.
   1521          pid_t pid =
   1522              static_cast<pid_t>(xpc_dictionary_get_int64(reply, "pid"));
   1523          CHROMIUM_LOG(INFO) << "ExtensionKit process started, pid: " << pid;
   1524 
   1525          self->mResults.mHandle = pid;
   1526          promise->Resolve(std::move(self->mResults), __func__);
   1527        });
   1528  });
   1529 
   1530  return promise;
   1531 }
   1532 #endif
   1533 
   1534 #ifdef XP_MACOSX
   1535 RefPtr<ProcessLaunchPromise> MacProcessLauncher::DoLaunch() {
   1536  return PosixProcessLauncher::DoLaunch()->Then(
   1537      XRE_GetAsyncIOEventTarget(), __func__,
   1538      [self = RefPtr{this}](
   1539          LaunchResults&& aResults) -> RefPtr<ProcessLaunchPromise> {
   1540        // Wait for the child process to send us its 'task_t' data, then
   1541        // send it the mach send/receive rights which are being passed on
   1542        // the commandline.
   1543        return MachHandleProcessCheckIn(std::move(self->mParentRecvPort),
   1544                                        base::GetProcId(aResults.mHandle),
   1545                                        mozilla::TimeDuration::FromSeconds(10),
   1546                                        std::move(self->mChildArgs.mSendRights))
   1547            ->Then(
   1548                XRE_GetAsyncIOEventTarget(), __func__,
   1549                [self, results = std::move(aResults)](task_t aTask) mutable {
   1550                  results.mChildTask = aTask;
   1551                  return ProcessLaunchPromise::CreateAndResolve(
   1552                      std::move(results), __func__);
   1553                },
   1554                [](LaunchError aError) {
   1555                  return ProcessLaunchPromise::CreateAndReject(aError,
   1556                                                               __func__);
   1557                });
   1558      },
   1559      [](LaunchError aError) {
   1560        return ProcessLaunchPromise::CreateAndReject(aError, __func__);
   1561      });
   1562 }
   1563 #endif  // XP_MACOSX
   1564 
   1565 #ifdef XP_WIN
   1566 Result<Ok, LaunchError> WindowsProcessLauncher::DoSetup() {
   1567  Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup();
   1568  if (aError.isErr()) {
   1569    return aError;
   1570  }
   1571 
   1572  FilePath exePath;
   1573  BinPathType pathType = GetPathToBinary(exePath, mProcessType);
   1574 
   1575  mCmdLine.emplace(exePath.ToWStringHack());
   1576 
   1577  if (pathType == BinPathType::Self) {
   1578    mCmdLine->AppendLooseValue(UTF8ToWide("-contentproc"));
   1579  }
   1580 
   1581 #  ifdef HAS_DLL_BLOCKLIST
   1582  if (IsDynamicBlocklistDisabled(
   1583          gSafeMode,
   1584          CommandLine::ForCurrentProcess()->HasSwitch(UTF8ToWide(
   1585              mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch)))) {
   1586    mCmdLine->AppendLooseValue(
   1587        UTF8ToWide(mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch));
   1588  }
   1589 #  endif  // HAS_DLL_BLOCKLIST
   1590 
   1591  for (const std::string& arg : mChildArgs.mArgs) {
   1592    mCmdLine->AppendLooseValue(UTF8ToWide(arg));
   1593  }
   1594 
   1595 #  if defined(MOZ_SANDBOX)
   1596  mResults.mSandboxBroker = MakeUnique<SandboxBroker>();
   1597 
   1598  // XXX: Bug 1124167: We should get rid of the process specific logic for
   1599  // sandboxing in this class at some point. Unfortunately it will take a bit
   1600  // of reorganizing so I don't think this patch is the right time.
   1601  switch (mProcessType) {
   1602    case GeckoProcessType_Content:
   1603      if (mSandboxLevel > 0) {
   1604        // For now we treat every failure as fatal in
   1605        // SetSecurityLevelForContentProcess and just crash there right away.
   1606        // Should this change in the future then we should also handle the error
   1607        // here.
   1608        mResults.mSandboxBroker->SetSecurityLevelForContentProcess(
   1609            mSandboxLevel, mIsFileContent);
   1610        mUseSandbox = true;
   1611      }
   1612      break;
   1613    case GeckoProcessType_IPDLUnitTest:
   1614      // XXX: We don't sandbox this process type yet
   1615      break;
   1616    case GeckoProcessType_GMPlugin:
   1617      if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
   1618        auto gmpSandboxKind = GMPSandboxKind::Default;
   1619        if (Contains(mChildArgs, "gmp-widevinecdm")) {
   1620          gmpSandboxKind = GMPSandboxKind::Widevine;
   1621        } else if (Contains(mChildArgs, "gmp-clearkey")) {
   1622          gmpSandboxKind = GMPSandboxKind::Clearkey;
   1623        } else if (Contains(mChildArgs, "gmp-fake")) {
   1624          gmpSandboxKind = GMPSandboxKind::Fake;
   1625        }
   1626 
   1627        if (NS_WARN_IF(!mResults.mSandboxBroker->SetSecurityLevelForGMPlugin(
   1628                gmpSandboxKind))) {
   1629          return Err(LaunchError("SetSecurityLevelForGMPlugin"));
   1630        }
   1631        mUseSandbox = true;
   1632      }
   1633      break;
   1634    case GeckoProcessType_GPU:
   1635      if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) {
   1636        // For now we treat every failure as fatal in
   1637        // SetSecurityLevelForGPUProcess and just crash there right away. Should
   1638        // this change in the future then we should also handle the error here.
   1639        mResults.mSandboxBroker->SetSecurityLevelForGPUProcess(mSandboxLevel);
   1640        mUseSandbox = true;
   1641      }
   1642      break;
   1643    case GeckoProcessType_VR:
   1644      if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
   1645        // TODO: Implement sandbox for VR process, Bug 1430043.
   1646      }
   1647      break;
   1648    case GeckoProcessType_RDD:
   1649      if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
   1650        if (NS_WARN_IF(
   1651                !mResults.mSandboxBroker->SetSecurityLevelForRDDProcess())) {
   1652          return Err(LaunchError("SetSecurityLevelForRDDProcess"));
   1653        }
   1654        mUseSandbox = true;
   1655      }
   1656      break;
   1657    case GeckoProcessType_Socket:
   1658      if (!PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS_SANDBOX")) {
   1659        if (NS_WARN_IF(
   1660                !mResults.mSandboxBroker->SetSecurityLevelForSocketProcess())) {
   1661          return Err(LaunchError("SetSecurityLevelForSocketProcess"));
   1662        }
   1663        mUseSandbox = true;
   1664      }
   1665      break;
   1666    case GeckoProcessType_Utility:
   1667      if (IsUtilitySandboxEnabled(mSandbox)) {
   1668        if (!mResults.mSandboxBroker->SetSecurityLevelForUtilityProcess(
   1669                mSandbox)) {
   1670          return Err(LaunchError("SetSecurityLevelForUtilityProcess"));
   1671        }
   1672        mUseSandbox = true;
   1673      }
   1674      break;
   1675    case GeckoProcessType_Default:
   1676    default:
   1677      MOZ_CRASH("Bad process type in GeckoChildProcessHost");
   1678      break;
   1679  };
   1680 
   1681  if (mUseSandbox) {
   1682    for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end();
   1683         ++it) {
   1684      mResults.mSandboxBroker->AllowReadFile(it->c_str());
   1685    }
   1686 
   1687    if (mResults.mSandboxBroker->IsWin32kLockedDown()) {
   1688      mCmdLine->AppendLooseValue(
   1689          UTF8ToWide(geckoargs::sWin32kLockedDown.Name()));
   1690    }
   1691  }
   1692 #  endif  // defined(MOZ_SANDBOX)
   1693 
   1694  // Add the application directory path (-appdir path)
   1695  AddAppDirToCommandLine(mCmdLine.ref(), mAppDir);
   1696 
   1697  // XXX Command line params past this point are expected to be at
   1698  // the end of the command line string, and in a specific order.
   1699  // See XRE_InitChildProcess in nsEmbedFunction.
   1700 
   1701  // Win app model id
   1702  mCmdLine->AppendLooseValue(mGroupId.get());
   1703 
   1704  // Gecko child id
   1705  mCmdLine->AppendLooseValue(UTF8ToWide(mChildIDString));
   1706 
   1707  // Process type
   1708  mCmdLine->AppendLooseValue(UTF8ToWide(ChildProcessType()));
   1709 
   1710  // Add any files which need to be transferred to handles_to_inherit.
   1711  for (auto& file : mChildArgs.mFiles) {
   1712    mLaunchOptions->handles_to_inherit.push_back(file.get());
   1713  }
   1714 
   1715 #  ifdef MOZ_SANDBOX
   1716  if (mUseSandbox) {
   1717    // Mark the handles to inherit as inheritable.
   1718    for (HANDLE h : mLaunchOptions->handles_to_inherit) {
   1719      mResults.mSandboxBroker->AddHandleToShare(h);
   1720    }
   1721  }
   1722 #  endif  // MOZ_SANDBOX
   1723 
   1724  return Ok();
   1725 }
   1726 
   1727 RefPtr<ProcessLaunchPromise> WindowsProcessLauncher::DoLaunch() {
   1728 #  ifdef MOZ_SANDBOX
   1729  if (mUseSandbox) {
   1730    const IMAGE_THUNK_DATA* cachedNtdllThunk =
   1731        mCachedNtdllThunk ? mCachedNtdllThunk->begin() : nullptr;
   1732    Result<Ok, LaunchError> err = mResults.mSandboxBroker->LaunchApp(
   1733        mCmdLine->program().c_str(), mCmdLine->command_line_string().c_str(),
   1734        mLaunchOptions->env_map, mProcessType, mEnableSandboxLogging,
   1735        cachedNtdllThunk, &mResults.mHandle);
   1736    if (err.isOk()) {
   1737      EnvironmentLog("MOZ_PROCESS_LOG")
   1738          .print("==> process %d launched child process %d (%S)\n",
   1739                 base::GetCurrentProcId(), base::GetProcId(mResults.mHandle),
   1740                 mCmdLine->command_line_string().c_str());
   1741      return ProcessLaunchPromise::CreateAndResolve(std::move(mResults),
   1742                                                    __func__);
   1743    }
   1744    return ProcessLaunchPromise::CreateAndReject(err.unwrapErr(), __func__);
   1745  }
   1746 #  endif  // defined(MOZ_SANDBOX)
   1747 
   1748  Result<Ok, LaunchError> launchErr =
   1749      base::LaunchApp(mCmdLine.ref(), *mLaunchOptions, &mResults.mHandle);
   1750  if (launchErr.isErr()) {
   1751    return ProcessLaunchPromise::CreateAndReject(launchErr.unwrapErr(),
   1752                                                 __func__);
   1753  }
   1754  return ProcessLaunchPromise::CreateAndResolve(std::move(mResults), __func__);
   1755 }
   1756 #endif  // XP_WIN
   1757 
   1758 bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid) {
   1759  if (mChildProcessHandle) {
   1760    MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
   1761    return true;
   1762  }
   1763 
   1764  return base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle);
   1765 }
   1766 
   1767 void GeckoChildProcessHost::OnChannelConnected(base::ProcessId peer_pid) {
   1768  {
   1769    mozilla::AutoWriteLock hLock(mHandleLock);
   1770    if (!OpenPrivilegedHandle(peer_pid)) {
   1771      MOZ_CRASH("can't open handle to child process");
   1772    }
   1773  }
   1774  MonitorAutoLock lock(mMonitor);
   1775  mProcessState = PROCESS_CONNECTED;
   1776  lock.Notify();
   1777 }
   1778 
   1779 RefPtr<ProcessHandlePromise> GeckoChildProcessHost::WhenProcessHandleReady() {
   1780  MOZ_ASSERT(mHandlePromise != nullptr);
   1781  return mHandlePromise;
   1782 }
   1783 
   1784 #ifdef MOZ_WIDGET_ANDROID
   1785 RefPtr<ProcessHandlePromise> AndroidProcessLauncher::LaunchAndroidService(
   1786    const GeckoProcessType aType, const geckoargs::ChildProcessArgs& args) {
   1787  JNIEnv* const env = mozilla::jni::GetEnvForThread();
   1788  MOZ_ASSERT(env);
   1789 
   1790  const size_t argvSize = args.mArgs.size();
   1791  jni::ObjectArray::LocalRef jargs =
   1792      jni::ObjectArray::New<jni::String>(argvSize);
   1793  for (size_t ix = 0; ix < argvSize; ix++) {
   1794    jargs->SetElement(ix, jni::StringParam(args.mArgs[ix].c_str(), env));
   1795  }
   1796 
   1797  std::vector<int> fds(args.mFiles.size());
   1798  for (size_t ix = 0; ix < fds.size(); ix++) {
   1799    fds[ix] = args.mFiles[ix].get();
   1800  }
   1801  jni::IntArray::LocalRef jfds = jni::IntArray::New(fds.data(), fds.size());
   1802 
   1803  auto type = java::GeckoProcessType::FromInt(aType);
   1804  auto genericResult = java::GeckoProcessManager::Start(type, jargs, jfds);
   1805  auto typedResult = java::GeckoResult::LocalRef(std::move(genericResult));
   1806  return ProcessHandlePromise::FromGeckoResult(typedResult);
   1807 }
   1808 #endif
   1809 
   1810 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
   1811 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector& aArgs) {
   1812  MacSandboxInfo info;
   1813  if (NS_WARN_IF(!FillMacSandboxInfo(info))) {
   1814    return false;
   1815  }
   1816  info.AppendAsParams(aArgs);
   1817  return true;
   1818 }
   1819 
   1820 // Fill |aInfo| with the flags needed to launch the utility sandbox
   1821 bool GeckoChildProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
   1822  aInfo.type = GetDefaultMacSandboxType();
   1823  aInfo.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled") ||
   1824                    PR_GetEnv("MOZ_SANDBOX_LOGGING");
   1825 
   1826  nsAutoCString appPath;
   1827  if (!nsMacUtilsImpl::GetAppPath(appPath)) {
   1828    MOZ_CRASH("Failed to get app path");
   1829  }
   1830  aInfo.appPath.assign(appPath.get());
   1831  return true;
   1832 }
   1833 
   1834 void GeckoChildProcessHost::DisableOSActivityMode() {
   1835  mDisableOSActivityMode = true;
   1836 }
   1837 
   1838 //
   1839 // If early sandbox startup is enabled for this process type, map the
   1840 // process type to the sandbox type and enable the sandbox. Returns true
   1841 // if no errors were encountered or if early sandbox startup is not
   1842 // enabled for this process. Returns false if an error was encountered.
   1843 //
   1844 /* static */
   1845 bool GeckoChildProcessHost::StartMacSandbox(int aArgc, char** aArgv,
   1846                                            std::string& aErrorMessage) {
   1847  MacSandboxType sandboxType = MacSandboxType_Invalid;
   1848  switch (XRE_GetProcessType()) {
   1849    // For now, only support early sandbox startup for content,
   1850    // RDD, and GMP processes. Add case statements for the additional
   1851    // process types once early sandbox startup is implemented for them.
   1852    case GeckoProcessType_Content:
   1853      // Content processes don't use GeckoChildProcessHost
   1854      // to configure sandboxing so hard code the sandbox type.
   1855      sandboxType = MacSandboxType_Content;
   1856      break;
   1857    case GeckoProcessType_RDD:
   1858      sandboxType = RDDProcessHost::GetMacSandboxType();
   1859      break;
   1860    case GeckoProcessType_Socket:
   1861      sandboxType = net::SocketProcessHost::GetMacSandboxType();
   1862      break;
   1863    case GeckoProcessType_GMPlugin:
   1864      sandboxType = gmp::GMPProcessParent::GetMacSandboxType();
   1865      break;
   1866    case GeckoProcessType_Utility:
   1867      sandboxType = ipc::UtilityProcessHost::GetMacSandboxType();
   1868      break;
   1869    case GeckoProcessType_GPU:
   1870      sandboxType = gfx::GPUProcessHost::GetMacSandboxType();
   1871      break;
   1872    default:
   1873      return true;
   1874  }
   1875 
   1876  return mozilla::StartMacSandboxIfEnabled(sandboxType, aArgc, aArgv,
   1877                                           aErrorMessage);
   1878 }
   1879 
   1880 #endif /* XP_MACOSX && MOZ_SANDBOX */
   1881 
   1882 /* static */
   1883 void GeckoChildProcessHost::GetAll(const GeckoProcessCallback& aCallback) {
   1884  StaticMutexAutoLock lock(sMutex);
   1885  if (!sGeckoChildProcessHosts) {
   1886    return;
   1887  }
   1888  for (GeckoChildProcessHost* gp = sGeckoChildProcessHosts->getFirst(); gp;
   1889       gp = static_cast<mozilla::LinkedListElement<GeckoChildProcessHost>*>(gp)
   1890                ->getNext()) {
   1891    aCallback(gp);
   1892  }
   1893 }
   1894 
   1895 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::Launch(
   1896    GeckoChildProcessHost* aHost) {
   1897  AssertIOThread();
   1898 
   1899  // The ForkServer doesn't use IPC::Channel for communication, so we can skip
   1900  // initializing it.
   1901  if (mProcessType != GeckoProcessType_ForkServer) {
   1902    IPC::Channel::ChannelHandle clientHandle;
   1903    if (!aHost->InitializeChannel(&clientHandle)) {
   1904      return ProcessLaunchPromise::CreateAndReject(
   1905          LaunchError("InitializeChannel"), __func__);
   1906    }
   1907 
   1908    if (auto* handle = std::get_if<UniqueFileHandle>(&clientHandle)) {
   1909      geckoargs::sIPCHandle.Put(std::move(*handle), mChildArgs);
   1910    }
   1911 #ifdef XP_DARWIN
   1912    // NOTE: We don't support passing UniqueMachReceiveRight instances on the
   1913    // command line, so clientHandle must be a send right.
   1914    else if (auto* port = std::get_if<UniqueMachSendRight>(&clientHandle)) {
   1915      geckoargs::sIPCPort.Put(std::move(*port), mChildArgs);
   1916    }
   1917 #endif
   1918    else {
   1919      MOZ_ASSERT_UNREACHABLE();
   1920      return ProcessLaunchPromise::CreateAndReject(LaunchError("BadPipeType"),
   1921                                                   __func__);
   1922    }
   1923  }
   1924 
   1925  return InvokeAsync(mLaunchThread, this, __func__,
   1926                     &BaseProcessLauncher::PerformAsyncLaunch);
   1927 }
   1928 
   1929 }  // namespace ipc
   1930 }  // namespace mozilla