LCOV - code coverage report
Current view: top level - ipc/glue - GeckoChildProcessHost.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 41 230 17.8 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       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/string_util.h"
      11             : #include "base/task.h"
      12             : #include "chrome/common/chrome_switches.h"
      13             : #include "chrome/common/process_watcher.h"
      14             : #ifdef MOZ_WIDGET_COCOA
      15             : #include "chrome/common/mach_ipc_mac.h"
      16             : #include "base/rand_util.h"
      17             : #include "nsILocalFileMac.h"
      18             : #include "SharedMemoryBasic.h"
      19             : #endif
      20             : 
      21             : #include "MainThreadUtils.h"
      22             : #include "mozilla/Sprintf.h"
      23             : #include "prenv.h"
      24             : #include "nsXPCOMPrivate.h"
      25             : 
      26             : #if defined(MOZ_CONTENT_SANDBOX)
      27             : #include "mozilla/SandboxSettings.h"
      28             : #include "nsAppDirectoryServiceDefs.h"
      29             : #endif
      30             : 
      31             : #include "nsExceptionHandler.h"
      32             : 
      33             : #include "nsDirectoryServiceDefs.h"
      34             : #include "nsIFile.h"
      35             : #include "nsPrintfCString.h"
      36             : 
      37             : #include "mozilla/ClearOnShutdown.h"
      38             : #include "mozilla/ipc/BrowserProcessSubThread.h"
      39             : #include "mozilla/ipc/EnvironmentMap.h"
      40             : #include "mozilla/Omnijar.h"
      41             : #include "mozilla/Telemetry.h"
      42             : #include "ProtocolUtils.h"
      43             : #include <sys/stat.h>
      44             : 
      45             : #ifdef XP_WIN
      46             : #include "nsIWinTaskbar.h"
      47             : #include <stdlib.h>
      48             : #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
      49             : 
      50             : #if defined(MOZ_SANDBOX)
      51             : #include "mozilla/Preferences.h"
      52             : #include "mozilla/sandboxing/sandboxLogging.h"
      53             : #include "WinUtils.h"
      54             : #endif
      55             : #endif
      56             : 
      57             : #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
      58             : #include "mozilla/SandboxLaunch.h"
      59             : #endif
      60             : 
      61             : #include "nsTArray.h"
      62             : #include "nsClassHashtable.h"
      63             : #include "nsHashKeys.h"
      64             : #include "nsNativeCharsetUtils.h"
      65             : #include "nscore.h" // for NS_FREE_PERMANENT_DATA
      66             : #include "private/pprio.h"
      67             : 
      68             : using mozilla::MonitorAutoLock;
      69             : using mozilla::ipc::GeckoChildProcessHost;
      70             : 
      71             : #ifdef MOZ_WIDGET_ANDROID
      72             : #include "AndroidBridge.h"
      73             : #include "GeneratedJNIWrappers.h"
      74             : #include "mozilla/jni/Refs.h"
      75             : #include "mozilla/jni/Utils.h"
      76             : #endif
      77             : 
      78             : static bool
      79           0 : ShouldHaveDirectoryService()
      80             : {
      81           0 :   return GeckoProcessType_Default == XRE_GetProcessType();
      82             : }
      83             : 
      84           0 : GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
      85           0 :                                              bool aIsFileContent)
      86             :   : mProcessType(aProcessType),
      87             :     mIsFileContent(aIsFileContent),
      88             :     mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
      89             :     mLaunchOptions(MakeUnique<base::LaunchOptions>()),
      90             :     mProcessState(CREATING_CHANNEL),
      91             : #ifdef XP_WIN
      92             :     mGroupId(u"-"),
      93             : #endif
      94             : #if defined(MOZ_SANDBOX) && defined(XP_WIN)
      95             :     mEnableSandboxLogging(false),
      96             :     mSandboxLevel(0),
      97             : #endif
      98           0 :     mChildProcessHandle(0)
      99             : #if defined(MOZ_WIDGET_COCOA)
     100             :   , mChildTask(MACH_PORT_NULL)
     101             : #endif
     102             : {
     103           0 :     MOZ_COUNT_CTOR(GeckoChildProcessHost);
     104           0 : }
     105             : 
     106           0 : GeckoChildProcessHost::~GeckoChildProcessHost()
     107             : 
     108             : {
     109           0 :   AssertIOThread();
     110             : 
     111           0 :   MOZ_COUNT_DTOR(GeckoChildProcessHost);
     112             : 
     113           0 :   if (mChildProcessHandle != 0) {
     114             : #if defined(MOZ_WIDGET_COCOA)
     115             :     SharedMemoryBasic::CleanupForPid(mChildProcessHandle);
     116             : #endif
     117             :     ProcessWatcher::EnsureProcessTerminated(mChildProcessHandle
     118             : #ifdef NS_FREE_PERMANENT_DATA
     119             :     // If we're doing leak logging, shutdown can be slow.
     120             :                                             , false // don't "force"
     121             : #endif
     122           0 :     );
     123             :   }
     124             : 
     125             : #if defined(MOZ_WIDGET_COCOA)
     126             :   if (mChildTask != MACH_PORT_NULL)
     127             :     mach_port_deallocate(mach_task_self(), mChildTask);
     128             : #endif
     129             : 
     130           0 :   if (mChildProcessHandle != 0) {
     131             : #if defined(XP_WIN)
     132             :     CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
     133             :       base::GetProcId(mChildProcessHandle));
     134             : #else
     135             :     CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
     136           0 :       mChildProcessHandle);
     137             : #endif
     138             :   }
     139           0 : }
     140             : 
     141             : //static
     142             : auto
     143           0 : GeckoChildProcessHost::GetPathToBinary(FilePath& exePath, GeckoProcessType processType) -> BinaryPathType
     144             : {
     145           0 :   if (sRunSelfAsContentProc &&
     146           0 :       (processType == GeckoProcessType_Content || processType == GeckoProcessType_GPU)) {
     147             : #if defined(OS_WIN)
     148             :     wchar_t exePathBuf[MAXPATHLEN];
     149             :     if (!::GetModuleFileNameW(nullptr, exePathBuf, MAXPATHLEN)) {
     150             :       MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
     151             :     }
     152             : #if defined(MOZ_SANDBOX)
     153             :     // We need to start the child process using the real path, so that the
     154             :     // sandbox policy rules will match for DLLs loaded from the bin dir after
     155             :     // we have lowered the sandbox.
     156             :     std::wstring exePathStr = exePathBuf;
     157             :     if (widget::WinUtils::ResolveJunctionPointsAndSymLinks(exePathStr)) {
     158             :       exePath = FilePath::FromWStringHack(exePathStr);
     159             :     } else
     160             : #endif
     161             :     {
     162             :       exePath = FilePath::FromWStringHack(exePathBuf);
     163             :     }
     164             : #elif defined(OS_POSIX)
     165           0 :     exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
     166             : #else
     167             : #  error Sorry; target OS not supported yet.
     168             : #endif
     169           0 :     return BinaryPathType::Self;
     170             :   }
     171             : 
     172           0 :   if (ShouldHaveDirectoryService()) {
     173           0 :     MOZ_ASSERT(gGREBinPath);
     174             : #ifdef OS_WIN
     175             :     exePath = FilePath(char16ptr_t(gGREBinPath));
     176             : #elif MOZ_WIDGET_COCOA
     177             :     nsCOMPtr<nsIFile> childProcPath;
     178             :     NS_NewLocalFile(nsDependentString(gGREBinPath), false,
     179             :                     getter_AddRefs(childProcPath));
     180             : 
     181             :     // We need to use an App Bundle on OS X so that we can hide
     182             :     // the dock icon. See Bug 557225.
     183             :     childProcPath->AppendNative(NS_LITERAL_CSTRING("plugin-container.app"));
     184             :     childProcPath->AppendNative(NS_LITERAL_CSTRING("Contents"));
     185             :     childProcPath->AppendNative(NS_LITERAL_CSTRING("MacOS"));
     186             :     nsCString tempCPath;
     187             :     childProcPath->GetNativePath(tempCPath);
     188             :     exePath = FilePath(tempCPath.get());
     189             : #else
     190           0 :     nsCString path;
     191           0 :     NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
     192           0 :     exePath = FilePath(path.get());
     193             : #endif
     194             :   }
     195             : 
     196           0 :   if (exePath.empty()) {
     197             : #ifdef OS_WIN
     198             :     exePath = FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
     199             : #else
     200           0 :     exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
     201             : #endif
     202           0 :     exePath = exePath.DirName();
     203             :   }
     204             : 
     205           0 :   exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
     206             : 
     207           0 :   return BinaryPathType::PluginContainer;
     208             : }
     209             : 
     210             : #ifdef MOZ_WIDGET_COCOA
     211             : class AutoCFTypeObject {
     212             : public:
     213             :   explicit AutoCFTypeObject(CFTypeRef object)
     214             :   {
     215             :     mObject = object;
     216             :   }
     217             :   ~AutoCFTypeObject()
     218             :   {
     219             :     ::CFRelease(mObject);
     220             :   }
     221             : private:
     222             :   CFTypeRef mObject;
     223             : };
     224             : #endif
     225             : 
     226             : // We start the unique IDs at 1 so that 0 can be used to mean that
     227             : // a component has no unique ID assigned to it.
     228             : uint32_t GeckoChildProcessHost::sNextUniqueID = 1;
     229             : 
     230             : /* static */
     231             : uint32_t
     232           0 : GeckoChildProcessHost::GetUniqueID()
     233             : {
     234           0 :   return sNextUniqueID++;
     235             : }
     236             : 
     237             : void
     238           0 : GeckoChildProcessHost::PrepareLaunch()
     239             : {
     240           0 :   if (CrashReporter::GetEnabled()) {
     241           0 :     CrashReporter::OOPInit();
     242             :   }
     243             : 
     244             : #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
     245             :   SandboxLaunchPrepare(mProcessType, mLaunchOptions.get());
     246             : #endif
     247             : 
     248             : #ifdef XP_WIN
     249             :   if (mProcessType == GeckoProcessType_Plugin) {
     250             :     InitWindowsGroupID();
     251             :   }
     252             : 
     253             : #if defined(MOZ_CONTENT_SANDBOX)
     254             :   // We need to get the pref here as the process is launched off main thread.
     255             :   if (mProcessType == GeckoProcessType_Content) {
     256             :     mSandboxLevel = GetEffectiveContentSandboxLevel();
     257             :     mEnableSandboxLogging =
     258             :       Preferences::GetBool("security.sandbox.logging.enabled");
     259             : 
     260             :     // We currently have to whitelist certain paths for tests to work in some
     261             :     // development configurations.
     262             :     nsAutoString readPaths;
     263             :     nsresult rv =
     264             :       Preferences::GetString("security.sandbox.content.read_path_whitelist",
     265             :                              readPaths);
     266             :     if (NS_SUCCEEDED(rv)) {
     267             :       for (const nsAString& readPath : readPaths.Split(',')) {
     268             :         nsString trimmedPath(readPath);
     269             :         trimmedPath.Trim(" ", true, true);
     270             :         std::wstring resolvedPath(trimmedPath.Data());
     271             :         // Before resolving check if path ends with '\' as this indicates we
     272             :         // want to give read access to a directory and so it needs a wildcard.
     273             :         bool addWildcard = (resolvedPath.back() == L'\\');
     274             :         if (!widget::WinUtils::ResolveJunctionPointsAndSymLinks(resolvedPath)) {
     275             :           NS_ERROR("Failed to resolve test read policy rule.");
     276             :           continue;
     277             :         }
     278             : 
     279             :         if (addWildcard) {
     280             :           resolvedPath.append(L"\\*");
     281             :         }
     282             :         mAllowedFilesRead.push_back(resolvedPath);
     283             :       }
     284             :     }
     285             :   }
     286             : #endif
     287             : 
     288             : #if defined(MOZ_SANDBOX)
     289             :   // For other process types we can't rely on them being launched on main
     290             :   // thread and they may not have access to prefs in the child process, so allow
     291             :   // them to turn on logging via an environment variable.
     292             :   mEnableSandboxLogging = mEnableSandboxLogging
     293             :                           || !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
     294             : #endif
     295             : #elif defined(XP_LINUX)
     296             : #if defined(MOZ_CONTENT_SANDBOX)
     297             :   // Get and remember the path to the per-content-process tmpdir
     298             :   if (ShouldHaveDirectoryService()) {
     299             :     nsCOMPtr<nsIFile> contentTempDir;
     300             :     nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
     301             :                                          getter_AddRefs(contentTempDir));
     302             :     if (NS_SUCCEEDED(rv)) {
     303             :       contentTempDir->GetNativePath(mTmpDirName);
     304             :     }
     305             :   }
     306             : #endif
     307             : #endif
     308           0 : }
     309             : 
     310             : #ifdef XP_WIN
     311             : void GeckoChildProcessHost::InitWindowsGroupID()
     312             : {
     313             :   // On Win7+, pass the application user model to the child, so it can
     314             :   // register with it. This insures windows created by the container
     315             :   // properly group with the parent app on the Win7 taskbar.
     316             :   nsCOMPtr<nsIWinTaskbar> taskbarInfo =
     317             :     do_GetService(NS_TASKBAR_CONTRACTID);
     318             :   if (taskbarInfo) {
     319             :     bool isSupported = false;
     320             :     taskbarInfo->GetAvailable(&isSupported);
     321             :     nsAutoString appId;
     322             :     if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
     323             :       MOZ_ASSERT(mGroupId.EqualsLiteral("-"));
     324             :       mGroupId.Assign(appId);
     325             :     }
     326             :   }
     327             : }
     328             : #endif
     329             : 
     330             : bool
     331           0 : GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTimeoutMs)
     332             : {
     333           0 :   PrepareLaunch();
     334             : 
     335           0 :   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
     336           0 :   NS_ASSERTION(MessageLoop::current() != ioLoop, "sync launch from the IO thread NYI");
     337             : 
     338           0 :   ioLoop->PostTask(NewNonOwningRunnableMethod<std::vector<std::string>>(
     339             :     "ipc::GeckoChildProcessHost::RunPerformAsyncLaunch",
     340             :     this,
     341             :     &GeckoChildProcessHost::RunPerformAsyncLaunch,
     342           0 :     aExtraOpts));
     343             : 
     344           0 :   return WaitUntilConnected(aTimeoutMs);
     345             : }
     346             : 
     347             : bool
     348           0 : GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts)
     349             : {
     350           0 :   PrepareLaunch();
     351             : 
     352           0 :   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
     353             : 
     354           0 :   ioLoop->PostTask(NewNonOwningRunnableMethod<std::vector<std::string>>(
     355             :     "ipc::GeckoChildProcessHost::RunPerformAsyncLaunch",
     356             :     this,
     357             :     &GeckoChildProcessHost::RunPerformAsyncLaunch,
     358           0 :     aExtraOpts));
     359             : 
     360             :   // This may look like the sync launch wait, but we only delay as
     361             :   // long as it takes to create the channel.
     362           0 :   MonitorAutoLock lock(mMonitor);
     363           0 :   while (mProcessState < CHANNEL_INITIALIZED) {
     364           0 :     lock.Wait();
     365             :   }
     366             : 
     367           0 :   return true;
     368             : }
     369             : 
     370             : bool
     371           0 : GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs)
     372             : {
     373           0 :   AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER);
     374             : 
     375             :   // NB: this uses a different mechanism than the chromium parent
     376             :   // class.
     377             :   TimeDuration timeout = (aTimeoutMs > 0) ?
     378           0 :     TimeDuration::FromMilliseconds(aTimeoutMs) : TimeDuration::Forever();
     379             : 
     380           0 :   MonitorAutoLock lock(mMonitor);
     381           0 :   TimeStamp waitStart = TimeStamp::Now();
     382           0 :   TimeStamp current;
     383             : 
     384             :   // We'll receive several notifications, we need to exit when we
     385             :   // have either successfully launched or have timed out.
     386           0 :   while (mProcessState != PROCESS_CONNECTED) {
     387             :     // If there was an error then return it, don't wait out the timeout.
     388           0 :     if (mProcessState == PROCESS_ERROR) {
     389             :       break;
     390             :     }
     391             : 
     392           0 :     CVStatus status = lock.Wait(timeout);
     393           0 :     if (status == CVStatus::Timeout) {
     394             :       break;
     395             :     }
     396             : 
     397           0 :     if (timeout != TimeDuration::Forever()) {
     398           0 :       current = TimeStamp::Now();
     399           0 :       timeout -= current - waitStart;
     400           0 :       waitStart = current;
     401             :     }
     402             :   }
     403             : 
     404           0 :   return mProcessState == PROCESS_CONNECTED;
     405             : }
     406             : 
     407             : bool
     408           0 : GeckoChildProcessHost::LaunchAndWaitForProcessHandle(StringVector aExtraOpts)
     409             : {
     410           0 :   PrepareLaunch();
     411             : 
     412           0 :   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
     413           0 :   ioLoop->PostTask(NewNonOwningRunnableMethod<std::vector<std::string>>(
     414             :     "ipc::GeckoChildProcessHost::RunPerformAsyncLaunch",
     415             :     this,
     416             :     &GeckoChildProcessHost::RunPerformAsyncLaunch,
     417           0 :     aExtraOpts));
     418             : 
     419           0 :   MonitorAutoLock lock(mMonitor);
     420           0 :   while (mProcessState < PROCESS_CREATED) {
     421           0 :     lock.Wait();
     422             :   }
     423           0 :   MOZ_ASSERT(mProcessState == PROCESS_ERROR || mChildProcessHandle);
     424             : 
     425           0 :   return mProcessState < PROCESS_ERROR;
     426             : }
     427             : 
     428             : void
     429           0 : GeckoChildProcessHost::InitializeChannel()
     430             : {
     431           0 :   CreateChannel();
     432             : 
     433           0 :   MonitorAutoLock lock(mMonitor);
     434           0 :   mProcessState = CHANNEL_INITIALIZED;
     435           0 :   lock.Notify();
     436           0 : }
     437             : 
     438             : void
     439           0 : GeckoChildProcessHost::Join()
     440             : {
     441           0 :   AssertIOThread();
     442             : 
     443           0 :   if (!mChildProcessHandle) {
     444             :     return;
     445             :   }
     446             : 
     447             :   // If this fails, there's nothing we can do.
     448           0 :   base::KillProcess(mChildProcessHandle, 0, /*wait*/true);
     449           0 :   SetAlreadyDead();
     450             : }
     451             : 
     452             : void
     453           0 : GeckoChildProcessHost::SetAlreadyDead()
     454             : {
     455           0 :   if (mChildProcessHandle &&
     456             :       mChildProcessHandle != kInvalidProcessHandle) {
     457           0 :     base::CloseProcessHandle(mChildProcessHandle);
     458             :   }
     459             : 
     460           0 :   mChildProcessHandle = 0;
     461           0 : }
     462             : 
     463             : int32_t GeckoChildProcessHost::mChildCounter = 0;
     464             : 
     465             : void
     466           0 : GeckoChildProcessHost::GetChildLogName(const char* origLogName,
     467             :                                        nsACString &buffer)
     468             : {
     469             : #ifdef XP_WIN
     470             :   // On Windows we must expand relative paths because sandboxing rules
     471             :   // bound only to full paths.  fopen fowards to NtCreateFile which checks
     472             :   // the path against the sanboxing rules as passed to fopen (left relative).
     473             :   char absPath[MAX_PATH + 2];
     474             :   if (_fullpath(absPath, origLogName, sizeof(absPath))) {
     475             : #ifdef MOZ_SANDBOX
     476             :     // We need to make sure the child log name doesn't contain any junction
     477             :     // points or symlinks or the sandbox will reject rules to allow writing.
     478             :     std::wstring resolvedPath(NS_ConvertUTF8toUTF16(absPath).get());
     479             :     if (widget::WinUtils::ResolveJunctionPointsAndSymLinks(resolvedPath)) {
     480             :       AppendUTF16toUTF8(resolvedPath.c_str(), buffer);
     481             :     } else
     482             : #endif
     483             :     {
     484             :       buffer.Append(absPath);
     485             :     }
     486             :   } else
     487             : #endif
     488             :   {
     489           0 :     buffer.Append(origLogName);
     490             :   }
     491             : 
     492             :   // Append child-specific postfix to name
     493           0 :   buffer.AppendLiteral(".child-");
     494           0 :   buffer.AppendInt(mChildCounter);
     495           0 : }
     496             : 
     497             : bool
     498           0 : GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts)
     499             : {
     500             : #ifdef MOZ_GECKO_PROFILER
     501           0 :   AutoSetProfilerEnvVarsForChildProcess profilerEnvironment;
     502             : #endif
     503             : 
     504             :   // - Note: this code is not called re-entrantly, nor are restoreOrig*LogName
     505             :   //   or mChildCounter touched by any other thread, so this is safe.
     506           0 :   ++mChildCounter;
     507             : 
     508           0 :   const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
     509           0 :   const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
     510             : 
     511           0 :   if (origNSPRLogName) {
     512           0 :     nsAutoCString nsprLogName;
     513           0 :     GetChildLogName(origNSPRLogName, nsprLogName);
     514           0 :     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("NSPR_LOG_FILE")]
     515           0 :         = ENVIRONMENT_STRING(nsprLogName);
     516             :   }
     517           0 :   if (origMozLogName) {
     518           0 :     nsAutoCString mozLogName;
     519           0 :     GetChildLogName(origMozLogName, mozLogName);
     520           0 :     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MOZ_LOG_FILE")]
     521           0 :         = ENVIRONMENT_STRING(mozLogName);
     522             :   }
     523             : 
     524             :   // `RUST_LOG_CHILD` is meant for logging child processes only.
     525           0 :   nsAutoCString childRustLog(PR_GetEnv("RUST_LOG_CHILD"));
     526           0 :   if (!childRustLog.IsEmpty()) {
     527           0 :     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("RUST_LOG")]
     528           0 :         = ENVIRONMENT_STRING(childRustLog);
     529             :   }
     530             : 
     531             : #if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
     532             :   if (!mTmpDirName.IsEmpty()) {
     533             :     // Point a bunch of things that might want to write from content to our
     534             :     // shiny new content-process specific tmpdir
     535             :     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("TMPDIR")] =
     536             :       ENVIRONMENT_STRING(mTmpDirName);
     537             :     // Partial fix for bug 1380051 (not persistent - should be)
     538             :     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
     539             :       ENVIRONMENT_STRING(mTmpDirName);
     540             :   }
     541             : #endif
     542             : 
     543           0 :   return PerformAsyncLaunchInternal(aExtraOpts);
     544             : }
     545             : 
     546             : bool
     547           0 : GeckoChildProcessHost::RunPerformAsyncLaunch(std::vector<std::string> aExtraOpts)
     548             : {
     549           0 :   InitializeChannel();
     550             : 
     551           0 :   bool ok = PerformAsyncLaunch(aExtraOpts);
     552           0 :   if (!ok) {
     553             :     // WaitUntilConnected might be waiting for us to signal.
     554             :     // If something failed let's set the error state and notify.
     555           0 :     MonitorAutoLock lock(mMonitor);
     556           0 :     mProcessState = PROCESS_ERROR;
     557           0 :     lock.Notify();
     558             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     559           0 :     OnProcessLaunchError();
     560             : #endif
     561           0 :     CHROMIUM_LOG(ERROR) << "Failed to launch " <<
     562           0 :       XRE_ChildProcessTypeToString(mProcessType) << " subprocess";
     563             :     Telemetry::Accumulate(Telemetry::SUBPROCESS_LAUNCH_FAILURE,
     564           0 :       nsDependentCString(XRE_ChildProcessTypeToString(mProcessType)));
     565             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     566             :   } else {
     567           0 :     OnProcessHandleReady(mChildProcessHandle);
     568             : #endif
     569             :   }
     570           0 :   return ok;
     571             : }
     572             : 
     573             : void
     574             : #if defined(XP_WIN)
     575             : AddAppDirToCommandLine(CommandLine& aCmdLine)
     576             : #else
     577           0 : AddAppDirToCommandLine(std::vector<std::string>& aCmdLine)
     578             : #endif
     579             : {
     580             :   // Content processes need access to application resources, so pass
     581             :   // the full application directory path to the child process.
     582           0 :   if (ShouldHaveDirectoryService()) {
     583           0 :     nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
     584           0 :     NS_ASSERTION(directoryService, "Expected XPCOM to be available");
     585           0 :     if (directoryService) {
     586           0 :       nsCOMPtr<nsIFile> appDir;
     587             :       // NS_XPCOM_CURRENT_PROCESS_DIR really means the app dir, not the
     588             :       // current process dir.
     589           0 :       nsresult rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
     590             :                                           NS_GET_IID(nsIFile),
     591           0 :                                           getter_AddRefs(appDir));
     592           0 :       if (NS_SUCCEEDED(rv)) {
     593             : #if defined(XP_WIN)
     594             :         nsString path;
     595             :         MOZ_ALWAYS_SUCCEEDS(appDir->GetPath(path));
     596             :         aCmdLine.AppendLooseValue(UTF8ToWide("-appdir"));
     597             :         std::wstring wpath(path.get());
     598             :         aCmdLine.AppendLooseValue(wpath);
     599             : #else
     600           0 :         nsAutoCString path;
     601           0 :         MOZ_ALWAYS_SUCCEEDS(appDir->GetNativePath(path));
     602           0 :         aCmdLine.push_back("-appdir");
     603           0 :         aCmdLine.push_back(path.get());
     604             : #endif
     605             :       }
     606             : 
     607             : #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
     608             :       // Full path to the profile dir
     609             :       nsCOMPtr<nsIFile> profileDir;
     610             :       rv = directoryService->Get(NS_APP_USER_PROFILE_50_DIR,
     611             :                                  NS_GET_IID(nsIFile),
     612             :                                  getter_AddRefs(profileDir));
     613             :       if (NS_SUCCEEDED(rv)) {
     614             :         nsAutoCString path;
     615             :         MOZ_ALWAYS_SUCCEEDS(profileDir->GetNativePath(path));
     616             :         aCmdLine.push_back("-profile");
     617             :         aCmdLine.push_back(path.get());
     618             :       }
     619             : #endif
     620             :     }
     621             :   }
     622           0 : }
     623             : 
     624             : bool
     625           0 : GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts)
     626             : {
     627             :   // We rely on the fact that InitializeChannel() has already been processed
     628             :   // on the IO thread before this point is reached.
     629           0 :   if (!GetChannel()) {
     630             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     631           0 :     MOZ_RELEASE_ASSERT(1 == 2);
     632             : #endif
     633             :     return false;
     634             :   }
     635             : 
     636           2 :   base::ProcessHandle process = 0;
     637             : 
     638             :   // send the child the PID so that it can open a ProcessHandle back to us.
     639             :   // probably don't want to do this in the long run
     640             :   char pidstring[32];
     641           0 :   SprintfLiteral(pidstring, "%d", base::GetCurrentProcId());
     642             : 
     643             :   const char* const childProcessType =
     644           2 :       XRE_ChildProcessTypeToString(mProcessType);
     645             : 
     646             :   PRFileDesc* crashAnnotationReadPipe;
     647             :   PRFileDesc* crashAnnotationWritePipe;
     648           2 :   if (PR_CreatePipe(&crashAnnotationReadPipe, &crashAnnotationWritePipe) != PR_SUCCESS) {
     649             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     650           0 :     MOZ_RELEASE_ASSERT(2 == 3);
     651             : #endif
     652             :     return false;
     653             :   }
     654             : 
     655             : //--------------------------------------------------
     656             : #if defined(OS_POSIX)
     657             :   // For POSIX, we have to be extremely anal about *not* using
     658             :   // std::wstring in code compiled with Mozilla's -fshort-wchar
     659             :   // configuration, because chromium is compiled with -fno-short-wchar
     660             :   // and passing wstrings from one config to the other is unsafe.  So
     661             :   // we split the logic here.
     662             : 
     663             : # if defined(OS_POSIX)
     664             : #  if defined(MOZ_WIDGET_GTK)
     665           2 :   if (mProcessType == GeckoProcessType_Content) {
     666             :     // disable IM module to avoid sandbox violation
     667           6 :     mLaunchOptions->env_map["GTK_IM_MODULE"] = "gtk-im-context-simple";
     668             : 
     669             :     // Disable ATK accessibility code in content processes because it conflicts
     670             :     // with the sandbox, and we proxy that information through the main process
     671             :     // anyway.
     672           6 :     mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
     673             :   }
     674             : #  endif // defined(MOZ_WIDGET_GTK)
     675             : 
     676             :   // XPCOM may not be initialized in some subprocesses.  We don't want
     677             :   // to initialize XPCOM just for the directory service, especially
     678             :   // since LD_LIBRARY_PATH is already set correctly in subprocesses
     679             :   // (meaning that we don't need to set that up in the environment).
     680           0 :   if (ShouldHaveDirectoryService()) {
     681           2 :     MOZ_ASSERT(gGREBinPath);
     682           4 :     nsCString path;
     683           0 :     NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
     684             : #  if defined(OS_LINUX) || defined(OS_BSD)
     685           0 :     const char *ld_library_path = PR_GetEnv("LD_LIBRARY_PATH");
     686           4 :     nsCString new_ld_lib_path(path.get());
     687             : 
     688             : #   ifdef MOZ_WIDGET_GTK
     689           0 :     if (mProcessType == GeckoProcessType_Plugin) {
     690           0 :       new_ld_lib_path.AppendLiteral("/gtk2:");
     691           0 :       new_ld_lib_path.Append(path.get());
     692             :     }
     693             : #   endif // MOZ_WIDGET_GTK
     694           2 :     if (ld_library_path && *ld_library_path) {
     695           0 :       new_ld_lib_path.Append(':');
     696           0 :       new_ld_lib_path.Append(ld_library_path);
     697             :     }
     698           6 :     mLaunchOptions->env_map["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
     699             : 
     700             : #  elif OS_MACOSX // defined(OS_LINUX) || defined(OS_BSD)
     701             :     mLaunchOptions->env_map["DYLD_LIBRARY_PATH"] = path.get();
     702             :     // XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin
     703             :     //     process, and has no effect on other subprocesses (the hooks in
     704             :     //     libplugin_child_interpose.dylib become noops).  But currently it
     705             :     //     gets set when launching any kind of subprocess.
     706             :     //
     707             :     // Trigger "dyld interposing" for the dylib that contains
     708             :     // plugin_child_interpose.mm.  This allows us to hook OS calls in the
     709             :     // plugin process (ones that don't work correctly in a background
     710             :     // process).  Don't break any other "dyld interposing" that has already
     711             :     // been set up by whatever may have launched the browser.
     712             :     const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
     713             :     nsCString interpose;
     714             :     if (prevInterpose && strlen(prevInterpose) > 0) {
     715             :       interpose.Assign(prevInterpose);
     716             :       interpose.Append(':');
     717             :     }
     718             :     interpose.Append(path.get());
     719             :     interpose.AppendLiteral("/libplugin_child_interpose.dylib");
     720             :     mLaunchOptions->env_map["DYLD_INSERT_LIBRARIES"] = interpose.get();
     721             : #  endif // defined(OS_LINUX) || defined(OS_BSD)
     722             :   }
     723             : # endif // defined(OS_POSIX)
     724             : 
     725           0 :   FilePath exePath;
     726           0 :   BinaryPathType pathType = GetPathToBinary(exePath, mProcessType);
     727             : 
     728             :   // remap the IPC socket fd to a well-known int, as the OS does for
     729             :   // STDOUT_FILENO, for example
     730             :   int srcChannelFd, dstChannelFd;
     731           4 :   channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd);
     732           0 :   mLaunchOptions->fds_to_remap
     733           6 :     .push_back(std::pair<int,int>(srcChannelFd, dstChannelFd));
     734             : 
     735             :   // no need for kProcessChannelID, the child process inherits the
     736             :   // other end of the socketpair() from us
     737             : 
     738           3 :   std::vector<std::string> childArgv;
     739             : 
     740           0 :   childArgv.push_back(exePath.value());
     741             : 
     742           0 :   if (pathType == BinaryPathType::Self) {
     743           8 :     childArgv.push_back("-contentproc");
     744             :   }
     745             : 
     746           0 :   childArgv.insert(childArgv.end(), aExtraOpts.begin(), aExtraOpts.end());
     747             : 
     748           0 :   if (Omnijar::IsInitialized()) {
     749             :     // Make sure that child processes can find the omnijar
     750             :     // See XRE_InitCommandLine in nsAppRunner.cpp
     751           0 :     nsAutoCString path;
     752           0 :     nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
     753           0 :     if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
     754           0 :       childArgv.push_back("-greomni");
     755           8 :       childArgv.push_back(path.get());
     756             :     }
     757           2 :     file = Omnijar::GetPath(Omnijar::APP);
     758           2 :     if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
     759           0 :       childArgv.push_back("-appomni");
     760           8 :       childArgv.push_back(path.get());
     761             :     }
     762             :   }
     763             : 
     764             :   // Add the application directory path (-appdir path)
     765           1 :   AddAppDirToCommandLine(childArgv);
     766             : 
     767             :   // Tmp dir that the GPU process should use for crash reports. This arg is
     768             :   // always populated (but possibly with an empty value) for a GPU child process.
     769           2 :   if (mProcessType == GeckoProcessType_GPU) {
     770           0 :     nsCOMPtr<nsIFile> file;
     771           0 :     CrashReporter::GetChildProcessTmpDir(getter_AddRefs(file));
     772           0 :     nsAutoCString path;
     773           0 :     if (file) {
     774           0 :       file->GetNativePath(path);
     775             :     }
     776           0 :     childArgv.push_back(path.get());
     777             :   }
     778             : 
     779           8 :   childArgv.push_back(pidstring);
     780             : 
     781             :   if (!CrashReporter::IsDummy()) {
     782             : #if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
     783             :     int childCrashFd, childCrashRemapFd;
     784           0 :     if (!CrashReporter::CreateNotificationPipeForChild(&childCrashFd,
     785             :                                                        &childCrashRemapFd)) {
     786           0 :       return false;
     787             :     }
     788             : 
     789           2 :     if (0 <= childCrashFd) {
     790           1 :       mLaunchOptions->fds_to_remap
     791           6 :         .push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd));
     792             :       // "true" == crash reporting enabled
     793           8 :       childArgv.push_back("true");
     794             :     } else {
     795             :       // "false" == crash reporting disabled
     796           0 :       childArgv.push_back("false");
     797             :     }
     798             : #elif defined(MOZ_WIDGET_COCOA) // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
     799             :     childArgv.push_back(CrashReporter::GetChildNotificationPipe());
     800             : #endif  // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
     801             :   }
     802             : 
     803           2 :   int fd = PR_FileDesc2NativeHandle(crashAnnotationWritePipe);
     804           2 :   mLaunchOptions->fds_to_remap.push_back(
     805           6 :     std::make_pair(fd, CrashReporter::GetAnnotationTimeCrashFd()));
     806             : 
     807             : # ifdef MOZ_WIDGET_COCOA
     808             :   // Add a mach port to the command line so the child can communicate its
     809             :   // 'task_t' back to the parent.
     810             :   //
     811             :   // Put a random number into the channel name, so that a compromised renderer
     812             :   // can't pretend being the child that's forked off.
     813             :   std::string mach_connection_name = StringPrintf("org.mozilla.machname.%d",
     814             :                                                   base::RandInt(0, std::numeric_limits<int>::max()));
     815             :   childArgv.push_back(mach_connection_name.c_str());
     816             : # endif // MOZ_WIDGET_COCOA
     817             : 
     818           0 :   childArgv.push_back(childProcessType);
     819             : 
     820             : # if defined(MOZ_WIDGET_ANDROID)
     821             :   LaunchAndroidService(childProcessType, childArgv,
     822             :                        mLaunchOptions->fds_to_remap, &process);
     823             : # else // goes with defined(MOZ_WIDGET_ANDROID)
     824           0 :   base::LaunchApp(childArgv, *mLaunchOptions, &process);
     825             : # endif // defined(MOZ_WIDGET_ANDROID)
     826             : 
     827             :   // We're in the parent and the child was launched. Close the child FD in the
     828             :   // parent as soon as possible, which will allow the parent to detect when the
     829             :   // child closes its FD (either due to normal exit or due to crash).
     830           1 :   GetChannel()->CloseClientFileDescriptor();
     831             : 
     832             : # ifdef MOZ_WIDGET_COCOA
     833             :   // Wait for the child process to send us its 'task_t' data.
     834             :   const int kTimeoutMs = 10000;
     835             : 
     836             :   MachReceiveMessage child_message;
     837             :   ReceivePort parent_recv_port(mach_connection_name.c_str());
     838             :   kern_return_t err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs);
     839             :   if (err != KERN_SUCCESS) {
     840             :     std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
     841             :     CHROMIUM_LOG(ERROR) << "parent WaitForMessage() failed: " << errString;
     842             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     843             :     MOZ_RELEASE_ASSERT(3 == 4);
     844             : #endif
     845             :     return false;
     846             :   }
     847             : 
     848             :   task_t child_task = child_message.GetTranslatedPort(0);
     849             :   if (child_task == MACH_PORT_NULL) {
     850             :     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
     851             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     852             :     MOZ_RELEASE_ASSERT(4 == 5);
     853             : #endif
     854             :     return false;
     855             :   }
     856             : 
     857             :   if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
     858             :     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(1) failed.";
     859             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     860             :     MOZ_RELEASE_ASSERT(5 == 6);
     861             : #endif
     862             :     return false;
     863             :   }
     864             :   MachPortSender parent_sender(child_message.GetTranslatedPort(1));
     865             : 
     866             :   if (child_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
     867             :     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(2) failed.";
     868             :   }
     869             :   auto* parent_recv_port_memory_ack = new MachPortSender(child_message.GetTranslatedPort(2));
     870             : 
     871             :   if (child_message.GetTranslatedPort(3) == MACH_PORT_NULL) {
     872             :     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(3) failed.";
     873             :   }
     874             :   auto* parent_send_port_memory = new MachPortSender(child_message.GetTranslatedPort(3));
     875             : 
     876             :   MachSendMessage parent_message(/* id= */0);
     877             :   if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) {
     878             :     CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed.";
     879             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     880             :     MOZ_RELEASE_ASSERT(6 == 7);
     881             : #endif
     882             :     return false;
     883             :   }
     884             : 
     885             :   auto* parent_recv_port_memory = new ReceivePort();
     886             :   if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_recv_port_memory->GetPort()))) {
     887             :     CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_recv_port_memory->GetPort() << ") failed.";
     888             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     889             :     MOZ_RELEASE_ASSERT(7 == 8);
     890             : #endif
     891             :     return false;
     892             :   }
     893             : 
     894             :   auto* parent_send_port_memory_ack = new ReceivePort();
     895             :   if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_send_port_memory_ack->GetPort()))) {
     896             :     CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_send_port_memory_ack->GetPort() << ") failed.";
     897             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     898             :     MOZ_RELEASE_ASSERT(8 == 9);
     899             : #endif
     900             :     return false;
     901             :   }
     902             : 
     903             :   err = parent_sender.SendMessage(parent_message, kTimeoutMs);
     904             :   if (err != KERN_SUCCESS) {
     905             :     std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
     906             :     CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString;
     907             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     908             :     MOZ_RELEASE_ASSERT(9 == 10);
     909             : #endif
     910             :     return false;
     911             :   }
     912             : 
     913             :   SharedMemoryBasic::SetupMachMemory(process, parent_recv_port_memory, parent_recv_port_memory_ack,
     914             :                                      parent_send_port_memory, parent_send_port_memory_ack, false);
     915             : 
     916             : # endif // MOZ_WIDGET_COCOA
     917             : 
     918             : //--------------------------------------------------
     919             : #elif defined(OS_WIN) // defined(OS_POSIX)
     920             : 
     921             :   FilePath exePath;
     922             :   BinaryPathType pathType = GetPathToBinary(exePath, mProcessType);
     923             : 
     924             :   CommandLine cmdLine(exePath.ToWStringHack());
     925             : 
     926             :   if (pathType == BinaryPathType::Self) {
     927             :     cmdLine.AppendLooseValue(UTF8ToWide("-contentproc"));
     928             :   }
     929             : 
     930             :   cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id());
     931             : 
     932             :   for (std::vector<std::string>::iterator it = aExtraOpts.begin();
     933             :        it != aExtraOpts.end();
     934             :        ++it) {
     935             :       cmdLine.AppendLooseValue(UTF8ToWide(*it));
     936             :   }
     937             : 
     938             :   if (Omnijar::IsInitialized()) {
     939             :     // Make sure the child process can find the omnijar
     940             :     // See XRE_InitCommandLine in nsAppRunner.cpp
     941             :     nsAutoString path;
     942             :     nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
     943             :     if (file && NS_SUCCEEDED(file->GetPath(path))) {
     944             :       cmdLine.AppendLooseValue(UTF8ToWide("-greomni"));
     945             :       cmdLine.AppendLooseValue(path.get());
     946             :     }
     947             :     file = Omnijar::GetPath(Omnijar::APP);
     948             :     if (file && NS_SUCCEEDED(file->GetPath(path))) {
     949             :       cmdLine.AppendLooseValue(UTF8ToWide("-appomni"));
     950             :       cmdLine.AppendLooseValue(path.get());
     951             :     }
     952             :   }
     953             : 
     954             : # if defined(MOZ_SANDBOX)
     955             :   bool shouldSandboxCurrentProcess = false;
     956             : 
     957             :   // XXX: Bug 1124167: We should get rid of the process specific logic for
     958             :   // sandboxing in this class at some point. Unfortunately it will take a bit
     959             :   // of reorganizing so I don't think this patch is the right time.
     960             :   switch (mProcessType) {
     961             :     case GeckoProcessType_Content:
     962             : #  if defined(MOZ_CONTENT_SANDBOX)
     963             :       if (mSandboxLevel > 0) {
     964             :         // For now we treat every failure as fatal in SetSecurityLevelForContentProcess
     965             :         // and just crash there right away. Should this change in the future then we
     966             :         // should also handle the error here.
     967             :         mSandboxBroker.SetSecurityLevelForContentProcess(mSandboxLevel,
     968             :                                                          mIsFileContent);
     969             :         shouldSandboxCurrentProcess = true;
     970             :       }
     971             : #  endif // defined(MOZ_CONTENT_SANDBOX)
     972             :       break;
     973             :     case GeckoProcessType_Plugin:
     974             :       if (mSandboxLevel > 0 &&
     975             :           !PR_GetEnv("MOZ_DISABLE_NPAPI_SANDBOX")) {
     976             :         bool ok = mSandboxBroker.SetSecurityLevelForPluginProcess(mSandboxLevel);
     977             :         if (!ok) {
     978             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     979             :           MOZ_RELEASE_ASSERT(10 == 11);
     980             : #endif
     981             :           return false;
     982             :         }
     983             :         shouldSandboxCurrentProcess = true;
     984             :       }
     985             :       break;
     986             : #ifdef MOZ_ENABLE_SKIA_PDF
     987             :     case GeckoProcessType_PDFium:
     988             :       if (!PR_GetEnv("MOZ_DISABLE_PDFIUM_SANDBOX")) {
     989             :         bool ok = mSandboxBroker.SetSecurityLevelForPDFiumProcess();
     990             :         if (!ok) {
     991             : #ifdef ASYNC_CONTENTPROC_LAUNCH
     992             :           MOZ_RELEASE_ASSERT(11 == 12);
     993             : #endif
     994             :           return false;
     995             :         }
     996             :         shouldSandboxCurrentProcess = true;
     997             :       }
     998             :       break;
     999             : #endif
    1000             :     case GeckoProcessType_IPDLUnitTest:
    1001             :       // XXX: We don't sandbox this process type yet
    1002             :       break;
    1003             :     case GeckoProcessType_GMPlugin:
    1004             :       if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
    1005             :         // The Widevine CDM on Windows can only load at USER_RESTRICTED,
    1006             :         // not at USER_LOCKDOWN. So look in the command line arguments
    1007             :         // to see if we're loading the path to the Widevine CDM, and if
    1008             :         // so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
    1009             :         bool isWidevine = std::any_of(aExtraOpts.begin(), aExtraOpts.end(),
    1010             :           [](const std::string arg) { return arg.find("gmp-widevinecdm") != std::string::npos; });
    1011             :         auto level = isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
    1012             :         bool ok = mSandboxBroker.SetSecurityLevelForGMPlugin(level);
    1013             :         if (!ok) {
    1014             : #ifdef ASYNC_CONTENTPROC_LAUNCH
    1015             :           MOZ_RELEASE_ASSERT(12 == 13);
    1016             : #endif
    1017             :           return false;
    1018             :         }
    1019             :         shouldSandboxCurrentProcess = true;
    1020             :       }
    1021             :       break;
    1022             :     case GeckoProcessType_GPU:
    1023             :       if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) {
    1024             :         // For now we treat every failure as fatal in SetSecurityLevelForGPUProcess
    1025             :         // and just crash there right away. Should this change in the future then we
    1026             :         // should also handle the error here.
    1027             :         mSandboxBroker.SetSecurityLevelForGPUProcess(mSandboxLevel);
    1028             :         shouldSandboxCurrentProcess = true;
    1029             :       }
    1030             :       break;
    1031             :     case GeckoProcessType_Default:
    1032             :     default:
    1033             :       MOZ_CRASH("Bad process type in GeckoChildProcessHost");
    1034             :       break;
    1035             :   };
    1036             : 
    1037             :   if (shouldSandboxCurrentProcess) {
    1038             :     for (auto it = mAllowedFilesRead.begin();
    1039             :          it != mAllowedFilesRead.end();
    1040             :          ++it) {
    1041             :       mSandboxBroker.AllowReadFile(it->c_str());
    1042             :     }
    1043             :   }
    1044             : # endif // defined(MOZ_SANDBOX)
    1045             : 
    1046             :   // Add the application directory path (-appdir path)
    1047             :   AddAppDirToCommandLine(cmdLine);
    1048             : 
    1049             :   // XXX Command line params past this point are expected to be at
    1050             :   // the end of the command line string, and in a specific order.
    1051             :   // See XRE_InitChildProcess in nsEmbedFunction.
    1052             : 
    1053             :   // Win app model id
    1054             :   cmdLine.AppendLooseValue(mGroupId.get());
    1055             : 
    1056             :   // Tmp dir that the GPU process should use for crash reports. This arg is
    1057             :   // always populated (but possibly with an empty value) for a GPU child process.
    1058             :   if (mProcessType == GeckoProcessType_GPU) {
    1059             :     nsCOMPtr<nsIFile> file;
    1060             :     CrashReporter::GetChildProcessTmpDir(getter_AddRefs(file));
    1061             :     nsString path;
    1062             :     if (file) {
    1063             :       MOZ_ALWAYS_SUCCEEDS(file->GetPath(path));
    1064             :     }
    1065             :     std::wstring wpath(path.get());
    1066             :     cmdLine.AppendLooseValue(wpath);
    1067             :   }
    1068             : 
    1069             :   // Process id
    1070             :   cmdLine.AppendLooseValue(UTF8ToWide(pidstring));
    1071             : 
    1072             :   cmdLine.AppendLooseValue(
    1073             :     UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
    1074             : 
    1075             :   if (!CrashReporter::IsDummy()) {
    1076             :     PROsfd h = PR_FileDesc2NativeHandle(crashAnnotationWritePipe);
    1077             :     mLaunchOptions->handles_to_inherit.push_back(reinterpret_cast<HANDLE>(h));
    1078             :     std::string hStr = std::to_string(h);
    1079             :     cmdLine.AppendLooseValue(UTF8ToWide(hStr));
    1080             :   }
    1081             : 
    1082             :   // Process type
    1083             :   cmdLine.AppendLooseValue(UTF8ToWide(childProcessType));
    1084             : 
    1085             : # if defined(MOZ_SANDBOX)
    1086             :   if (shouldSandboxCurrentProcess) {
    1087             :     // Mark the handles to inherit as inheritable.
    1088             :     for (HANDLE h : mLaunchOptions->handles_to_inherit) {
    1089             :       mSandboxBroker.AddHandleToShare(h);
    1090             :     }
    1091             : 
    1092             :     if (mSandboxBroker.LaunchApp(cmdLine.program().c_str(),
    1093             :                                  cmdLine.command_line_string().c_str(),
    1094             :                                  mLaunchOptions->env_map,
    1095             :                                  mProcessType,
    1096             :                                  mEnableSandboxLogging,
    1097             :                                  &process)) {
    1098             :       EnvironmentLog("MOZ_PROCESS_LOG").print(
    1099             :         "==> process %d launched child process %d (%S)\n",
    1100             :         base::GetCurrentProcId(), base::GetProcId(process),
    1101             :         cmdLine.command_line_string().c_str());
    1102             :     }
    1103             :   } else
    1104             : # endif // defined(MOZ_SANDBOX)
    1105             :   {
    1106             :     base::LaunchApp(cmdLine, *mLaunchOptions, &process);
    1107             : 
    1108             : # ifdef MOZ_SANDBOX
    1109             :     // We need to be able to duplicate handles to some types of non-sandboxed
    1110             :     // child processes.
    1111             :     if (mProcessType == GeckoProcessType_Content ||
    1112             :         mProcessType == GeckoProcessType_GPU ||
    1113             :         mProcessType == GeckoProcessType_GMPlugin) {
    1114             :       if (!mSandboxBroker.AddTargetPeer(process)) {
    1115             :         NS_WARNING("Failed to add content process as target peer.");
    1116             :       }
    1117             :     }
    1118             : # endif // MOZ_SANDBOX
    1119             :   }
    1120             : 
    1121             : #else // goes with defined(OS_POSIX)
    1122             : #  error Sorry
    1123             : #endif // defined(OS_POSIX)
    1124             : 
    1125           1 :   if (!process) {
    1126             : #ifdef ASYNC_CONTENTPROC_LAUNCH
    1127           0 :     MOZ_RELEASE_ASSERT(13 == 14);
    1128             : #endif
    1129             :     return false;
    1130             :   }
    1131             :   // NB: on OS X, we block much longer than we need to in order to
    1132             :   // reach this call, waiting for the child process's task_t.  The
    1133             :   // best way to fix that is to refactor this file, hard.
    1134             : #if defined(MOZ_WIDGET_COCOA)
    1135             :   mChildTask = child_task;
    1136             : #endif // defined(MOZ_WIDGET_COCOA)
    1137             : 
    1138           0 :   if (!OpenPrivilegedHandle(base::GetProcId(process))
    1139             : #ifdef XP_WIN
    1140             :       // If we failed in opening the process handle, try harder by duplicating
    1141             :       // one.
    1142             :       && !::DuplicateHandle(::GetCurrentProcess(), process,
    1143             :                             ::GetCurrentProcess(), &mChildProcessHandle,
    1144             :                             PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
    1145             :                             PROCESS_QUERY_INFORMATION | PROCESS_VM_READ |
    1146             :                             SYNCHRONIZE,
    1147             :                             FALSE, 0)
    1148             : #endif // XP_WIN
    1149             :      ) {
    1150           0 :     MOZ_CRASH("cannot open handle to child process");
    1151             :   }
    1152             : #if defined(XP_WIN)
    1153             :   CrashReporter::RegisterChildCrashAnnotationFileDescriptor(
    1154             :     base::GetProcId(process), crashAnnotationReadPipe);
    1155             : #else
    1156             :   CrashReporter::RegisterChildCrashAnnotationFileDescriptor(process,
    1157           0 :                                                             crashAnnotationReadPipe);
    1158             : #endif
    1159           1 :   PR_Close(crashAnnotationWritePipe);
    1160             : 
    1161           0 :   MonitorAutoLock lock(mMonitor);
    1162           1 :   mProcessState = PROCESS_CREATED;
    1163           1 :   lock.Notify();
    1164             : 
    1165           0 :   mLaunchOptions = nullptr;
    1166             :   return true;
    1167             : }
    1168             : 
    1169             : bool
    1170           2 : GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid)
    1171             : {
    1172           2 :   if (mChildProcessHandle) {
    1173           1 :     MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
    1174             :     return true;
    1175             :   }
    1176             : 
    1177           1 :   return base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle);
    1178             : }
    1179             : 
    1180             : void
    1181           1 : GeckoChildProcessHost::OnProcessHandleReady(ProcessHandle aProcessHandle)
    1182           1 : {}
    1183             : 
    1184             : void
    1185           0 : GeckoChildProcessHost::OnProcessLaunchError()
    1186           0 : {}
    1187             : 
    1188             : void
    1189           1 : GeckoChildProcessHost::OnChannelConnected(int32_t peer_pid)
    1190             : {
    1191             :   if (!OpenPrivilegedHandle(peer_pid)) {
    1192             :     MOZ_CRASH("can't open handle to child process");
    1193             :   }
    1194             :   MonitorAutoLock lock(mMonitor);
    1195             :   mProcessState = PROCESS_CONNECTED;
    1196             :   lock.Notify();
    1197             : }
    1198             : 
    1199             : void
    1200             : GeckoChildProcessHost::OnMessageReceived(IPC::Message&& aMsg)
    1201             : {
    1202             :   // We never process messages ourself, just save them up for the next
    1203             :   // listener.
    1204             :   mQueue.push(std::move(aMsg));
    1205             : }
    1206             : 
    1207             : void
    1208             : GeckoChildProcessHost::OnChannelError()
    1209             : {
    1210             :   // Update the process state to an error state if we have a channel
    1211             :   // error before we're connected. This fixes certain failures,
    1212             :   // but does not address the full range of possible issues described
    1213             :   // in the FIXME comment below.
    1214             :   MonitorAutoLock lock(mMonitor);
    1215             :   if (mProcessState < PROCESS_CONNECTED) {
    1216             :     mProcessState = PROCESS_ERROR;
    1217             :     lock.Notify();
    1218             :   }
    1219             :   // FIXME/bug 773925: save up this error for the next listener.
    1220             : }
    1221             : 
    1222             : void
    1223             : GeckoChildProcessHost::GetQueuedMessages(std::queue<IPC::Message>& queue)
    1224             : {
    1225             :   // If this is called off the IO thread, bad things will happen.
    1226             :   DCHECK(MessageLoopForIO::current());
    1227             :   swap(queue, mQueue);
    1228             :   // We expect the next listener to take over processing of our queue.
    1229             : }
    1230             : 
    1231             : bool GeckoChildProcessHost::sRunSelfAsContentProc(false);
    1232             : 
    1233             : #ifdef MOZ_WIDGET_ANDROID
    1234             : void
    1235             : GeckoChildProcessHost::LaunchAndroidService(const char* type,
    1236             :                                             const std::vector<std::string>& argv,
    1237             :                                             const base::file_handle_mapping_vector& fds_to_remap,
    1238             :                                             ProcessHandle* process_handle)
    1239             : {
    1240             :   MOZ_RELEASE_ASSERT((2 <= fds_to_remap.size()) && (fds_to_remap.size() <= 4));
    1241             :   JNIEnv* const env = mozilla::jni::GetEnvForThread();
    1242             :   MOZ_ASSERT(env);
    1243             : 
    1244             :   const int argvSize = argv.size();
    1245             :   jni::ObjectArray::LocalRef jargs = jni::ObjectArray::New<jni::String>(argvSize);
    1246             :   for (int ix = 0; ix < argvSize; ix++) {
    1247             :     jargs->SetElement(ix, jni::StringParam(argv[ix].c_str(), env));
    1248             :   }
    1249             : 
    1250             :   // XXX: this processing depends entirely on the internals of
    1251             :   // ContentParent::LaunchSubprocess()
    1252             :   // GeckoChildProcessHost::PerformAsyncLaunchInternal(), and the order in
    1253             :   // which they append to fds_to_remap. There must be a better way to do it.
    1254             :   // See bug 1440207.
    1255             :   int32_t prefsFd = fds_to_remap[0].first;
    1256             :   int32_t ipcFd = fds_to_remap[1].first;
    1257             :   int32_t crashFd = -1;
    1258             :   int32_t crashAnnotationFd = -1;
    1259             :   if (fds_to_remap.size() == 3) {
    1260             :     crashAnnotationFd = fds_to_remap[2].first;
    1261             :   }
    1262             :   if (fds_to_remap.size() == 4) {
    1263             :     crashFd = fds_to_remap[2].first;
    1264             :     crashAnnotationFd = fds_to_remap[3].first;
    1265             :   }
    1266             : 
    1267             :   int32_t handle = java::GeckoProcessManager::Start(type, jargs, prefsFd, ipcFd, crashFd, crashAnnotationFd);
    1268             : 
    1269             :   if (process_handle) {
    1270             :     *process_handle = handle;
    1271             :   }
    1272             : }
    1273             : #endif

Generated by: LCOV version 1.13-14-ga5dd952