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

Generated by: LCOV version 1.13