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 "SharedMemoryBasic.h"
16 #  include "base/rand_util.h"
17 #  include "chrome/common/mach_ipc_mac.h"
18 #  include "nsILocalFileMac.h"
19 #endif
20 
21 #include "GeckoProfiler.h"
22 #include "MainThreadUtils.h"
23 #include "mozilla/Preferences.h"
24 #include "mozilla/Sprintf.h"
25 #include "nsXPCOMPrivate.h"
26 #include "prenv.h"
27 
28 #if defined(MOZ_SANDBOX)
29 #  include "mozilla/SandboxSettings.h"
30 #  include "nsAppDirectoryServiceDefs.h"
31 #endif
32 
33 #include <sys/stat.h>
34 
35 #include "ProtocolUtils.h"
36 #include "mozilla/LinkedList.h"
37 #include "mozilla/Logging.h"
38 #include "mozilla/Maybe.h"
39 #include "mozilla/Omnijar.h"
40 #include "mozilla/RDDProcessHost.h"
41 #include "mozilla/Scoped.h"
42 #include "mozilla/Services.h"
43 #include "mozilla/SharedThreadPool.h"
44 #include "mozilla/StaticMutex.h"
45 #include "mozilla/TaskQueue.h"
46 #include "mozilla/Telemetry.h"
47 #include "mozilla/ipc/BrowserProcessSubThread.h"
48 #include "mozilla/ipc/EnvironmentMap.h"
49 #include "mozilla/ipc/NodeController.h"
50 #include "mozilla/net/SocketProcessHost.h"
51 #include "nsDirectoryService.h"
52 #include "nsDirectoryServiceDefs.h"
53 #include "nsExceptionHandler.h"
54 #include "nsIFile.h"
55 #include "nsIObserverService.h"
56 #include "nsPrintfCString.h"
57 
58 #ifdef XP_WIN
59 #  include <stdlib.h>
60 
61 #  include "nsIWinTaskbar.h"
62 #  define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
63 
64 #  if defined(MOZ_SANDBOX)
65 #    include "WinUtils.h"
66 #    include "mozilla/Preferences.h"
67 #    include "mozilla/sandboxing/sandboxLogging.h"
68 #    if defined(_ARM64_)
69 #      include "mozilla/remoteSandboxBroker.h"
70 #    endif
71 #  endif
72 
73 #  include "mozilla/NativeNt.h"
74 #  include "mozilla/CacheNtDllThunk.h"
75 #endif
76 
77 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
78 #  include "mozilla/SandboxLaunch.h"
79 #endif
80 
81 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
82 #  include "GMPProcessParent.h"
83 #  include "nsMacUtilsImpl.h"
84 #endif
85 
86 #include "nsClassHashtable.h"
87 #include "nsHashKeys.h"
88 #include "nsNativeCharsetUtils.h"
89 #include "nsTArray.h"
90 #include "nscore.h"  // for NS_FREE_PERMANENT_DATA
91 #include "private/pprio.h"
92 #include "nsIThread.h"
93 
94 using mozilla::MonitorAutoLock;
95 using mozilla::Preferences;
96 using mozilla::StaticMutexAutoLock;
97 
98 namespace mozilla {
99 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc,
100                                           PR_Close)
101 }
102 
103 using mozilla::ScopedPRFileDesc;
104 
105 #ifdef MOZ_WIDGET_ANDROID
106 #  include "AndroidBridge.h"
107 #  include "mozilla/java/GeckoProcessManagerWrappers.h"
108 #  include "mozilla/java/GeckoProcessTypeWrappers.h"
109 #  include "mozilla/java/GeckoResultWrappers.h"
110 #  include "mozilla/jni/Refs.h"
111 #  include "mozilla/jni/Utils.h"
112 #endif
113 
114 #ifdef MOZ_ENABLE_FORKSERVER
115 #  include "mozilla/ipc/ForkServiceChild.h"
116 #endif
117 
ShouldHaveDirectoryService()118 static bool ShouldHaveDirectoryService() {
119   return GeckoProcessType_Default == XRE_GetProcessType();
120 }
121 
122 namespace mozilla {
123 namespace ipc {
124 
125 static Atomic<int32_t> gChildCounter;
126 
IOThread()127 static inline nsISerialEventTarget* IOThread() {
128   return XRE_GetIOMessageLoop()->SerialEventTarget();
129 }
130 
131 class BaseProcessLauncher {
132  public:
BaseProcessLauncher(GeckoChildProcessHost * aHost,std::vector<std::string> && aExtraOpts)133   BaseProcessLauncher(GeckoChildProcessHost* aHost,
134                       std::vector<std::string>&& aExtraOpts)
135       : mProcessType(aHost->mProcessType),
136         mLaunchOptions(std::move(aHost->mLaunchOptions)),
137         mExtraOpts(std::move(aExtraOpts)),
138 #ifdef XP_WIN
139         mGroupId(aHost->mGroupId),
140 #endif
141 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
142         mAllowedFilesRead(aHost->mAllowedFilesRead),
143         mSandboxLevel(aHost->mSandboxLevel),
144         mIsFileContent(aHost->mIsFileContent),
145         mEnableSandboxLogging(aHost->mEnableSandboxLogging),
146 #endif
147 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
148         mDisableOSActivityMode(aHost->mDisableOSActivityMode),
149 #endif
150         mTmpDirName(aHost->mTmpDirName),
151         mChildId(++gChildCounter) {
152     SprintfLiteral(mPidString, "%d", base::GetCurrentProcId());
153 
154     // Compute the serial event target we'll use for launching.
155     nsCOMPtr<nsIEventTarget> threadOrPool = GetIPCLauncher();
156     mLaunchThread = new TaskQueue(threadOrPool.forget());
157 
158     if (ShouldHaveDirectoryService()) {
159       // "Current process directory" means the app dir, not the current
160       // working dir or similar.
161       mozilla::Unused
162           << nsDirectoryService::gService->GetCurrentProcessDirectory(
163                  getter_AddRefs(mAppDir));
164     }
165   }
166 
167   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseProcessLauncher);
168 
169   RefPtr<ProcessLaunchPromise> Launch(GeckoChildProcessHost*);
170 
171  protected:
172   virtual ~BaseProcessLauncher() = default;
173 
174   RefPtr<ProcessLaunchPromise> PerformAsyncLaunch();
175   RefPtr<ProcessLaunchPromise> FinishLaunch();
176 
177   // Overrideable hooks. If superclass behavior is invoked, it's always at the
178   // top of the override.
179   virtual bool SetChannel(IPC::Channel*) = 0;
180   virtual bool DoSetup();
181   virtual RefPtr<ProcessHandlePromise> DoLaunch() = 0;
DoFinishLaunch()182   virtual bool DoFinishLaunch() { return true; };
183 
184   void MapChildLogging();
185 
186   static BinPathType GetPathToBinary(FilePath&, GeckoProcessType);
187 
188   void GetChildLogName(const char* origLogName, nsACString& buffer);
189 
ChildProcessType()190   const char* ChildProcessType() {
191     return XRE_GeckoProcessTypeToString(mProcessType);
192   }
193 
194   nsCOMPtr<nsISerialEventTarget> mLaunchThread;
195   GeckoProcessType mProcessType;
196   UniquePtr<base::LaunchOptions> mLaunchOptions;
197   std::vector<std::string> mExtraOpts;
198 #ifdef XP_WIN
199   nsString mGroupId;
200 #endif
201 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
202   std::vector<std::wstring> mAllowedFilesRead;
203   int32_t mSandboxLevel;
204   bool mIsFileContent;
205   bool mEnableSandboxLogging;
206 #endif
207 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
208   // Controls whether or not the process will be launched with
209   // environment variable OS_ACTIVITY_MODE set to "disabled".
210   bool mDisableOSActivityMode;
211 #endif
212   nsCString mTmpDirName;
213   LaunchResults mResults = LaunchResults();
214   int32_t mChildId;
215   TimeStamp mStartTimeStamp = TimeStamp::Now();
216   char mPidString[32];
217 
218   // Set during launch.
219   IPC::Channel::ChannelId mChannelId;
220   ScopedPRFileDesc mCrashAnnotationReadPipe;
221   ScopedPRFileDesc mCrashAnnotationWritePipe;
222   nsCOMPtr<nsIFile> mAppDir;
223 };
224 
225 #ifdef XP_WIN
226 class WindowsProcessLauncher : public BaseProcessLauncher {
227  public:
WindowsProcessLauncher(GeckoChildProcessHost * aHost,std::vector<std::string> && aExtraOpts)228   WindowsProcessLauncher(GeckoChildProcessHost* aHost,
229                          std::vector<std::string>&& aExtraOpts)
230       : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
231         mProfileDir(aHost->mProfileDir),
232         mCachedNtdllThunk(GetCachedNtDllThunk()),
233         mWerDataPointer(&(aHost->mWerData)) {}
234 
235  protected:
SetChannel(IPC::Channel *)236   bool SetChannel(IPC::Channel*) override { return true; }
237   virtual bool DoSetup() override;
238   virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
239   virtual bool DoFinishLaunch() override;
240 
241   mozilla::Maybe<CommandLine> mCmdLine;
242   bool mUseSandbox = false;
243 
244   nsCOMPtr<nsIFile> mProfileDir;
245 
246   const Buffer<IMAGE_THUNK_DATA>* mCachedNtdllThunk;
247   CrashReporter::WindowsErrorReportingData const* mWerDataPointer;
248 };
249 typedef WindowsProcessLauncher ProcessLauncher;
250 #endif  // XP_WIN
251 
252 #ifdef OS_POSIX
253 class PosixProcessLauncher : public BaseProcessLauncher {
254  public:
PosixProcessLauncher(GeckoChildProcessHost * aHost,std::vector<std::string> && aExtraOpts)255   PosixProcessLauncher(GeckoChildProcessHost* aHost,
256                        std::vector<std::string>&& aExtraOpts)
257       : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
258         mProfileDir(aHost->mProfileDir) {}
259 
260  protected:
SetChannel(IPC::Channel * aChannel)261   bool SetChannel(IPC::Channel* aChannel) override {
262     // The source fd is owned by the channel; take ownership by
263     // dup()ing it and closing the channel's copy.  The destination fd
264     // is with respect to the not-yet-launched child process, so for
265     // this purpose it's just a number.
266     int origSrcFd;
267     aChannel->GetClientFileDescriptorMapping(&origSrcFd, &mChannelDstFd);
268     mChannelSrcFd.reset(dup(origSrcFd));
269     if (!mChannelSrcFd) {
270       return false;
271     }
272     aChannel->CloseClientFileDescriptor();
273     return true;
274   }
275 
276   virtual bool DoSetup() override;
277   virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
278   virtual bool DoFinishLaunch() override;
279 
280   nsCOMPtr<nsIFile> mProfileDir;
281 
282   std::vector<std::string> mChildArgv;
283   UniqueFileHandle mChannelSrcFd;
284   int mChannelDstFd;
285 };
286 
287 #  if defined(XP_MACOSX)
288 class MacProcessLauncher : public PosixProcessLauncher {
289  public:
MacProcessLauncher(GeckoChildProcessHost * aHost,std::vector<std::string> && aExtraOpts)290   MacProcessLauncher(GeckoChildProcessHost* aHost,
291                      std::vector<std::string>&& aExtraOpts)
292       : PosixProcessLauncher(aHost, std::move(aExtraOpts)),
293         // Put a random number into the channel name, so that
294         // a compromised renderer can't pretend being the child
295         // that's forked off.
296         mMachConnectionName(
297             StringPrintf("org.mozilla.machname.%d",
298                          base::RandInt(0, std::numeric_limits<int>::max()))),
299         mParentRecvPort(mMachConnectionName.c_str()) {}
300 
301  protected:
302   virtual bool DoFinishLaunch() override;
303 
304   std::string mMachConnectionName;
305   // We add a mach port to the command line so the child can communicate its
306   // 'task_t' back to the parent.
307   ReceivePort mParentRecvPort;
308 
309   friend class PosixProcessLauncher;
310 };
311 typedef MacProcessLauncher ProcessLauncher;
312 #  elif defined(MOZ_WIDGET_ANDROID)
313 class AndroidProcessLauncher : public PosixProcessLauncher {
314  public:
AndroidProcessLauncher(GeckoChildProcessHost * aHost,std::vector<std::string> && aExtraOpts)315   AndroidProcessLauncher(GeckoChildProcessHost* aHost,
316                          std::vector<std::string>&& aExtraOpts)
317       : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
318 
319  protected:
320   virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
321   RefPtr<ProcessHandlePromise> LaunchAndroidService(
322       const GeckoProcessType aType, const std::vector<std::string>& argv,
323       const base::file_handle_mapping_vector& fds_to_remap);
324 };
325 typedef AndroidProcessLauncher ProcessLauncher;
326 // NB: Technically Android is linux (i.e. XP_LINUX is defined), but we want
327 // orthogonal IPC machinery there. Conversely, there are tier-3 non-Linux
328 // platforms (BSD and Solaris) where we want the "linux" IPC machinery. So
329 // we use MOZ_WIDGET_* to choose the platform backend.
330 #  elif defined(MOZ_WIDGET_GTK)
331 class LinuxProcessLauncher : public PosixProcessLauncher {
332  public:
LinuxProcessLauncher(GeckoChildProcessHost * aHost,std::vector<std::string> && aExtraOpts)333   LinuxProcessLauncher(GeckoChildProcessHost* aHost,
334                        std::vector<std::string>&& aExtraOpts)
335       : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
336 
337  protected:
338   virtual bool DoSetup() override;
339 };
340 typedef LinuxProcessLauncher ProcessLauncher;
341 #  elif
342 #    error "Unknown platform"
343 #  endif
344 #endif  // OS_POSIX
345 
346 using base::ProcessHandle;
347 using mozilla::ipc::BaseProcessLauncher;
348 using mozilla::ipc::ProcessLauncher;
349 
350 mozilla::StaticAutoPtr<mozilla::LinkedList<GeckoChildProcessHost>>
351     GeckoChildProcessHost::sGeckoChildProcessHosts;
352 
353 mozilla::StaticMutex GeckoChildProcessHost::sMutex;
354 
GeckoChildProcessHost(GeckoProcessType aProcessType,bool aIsFileContent)355 GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
356                                              bool aIsFileContent)
357     : mProcessType(aProcessType),
358       mIsFileContent(aIsFileContent),
359       mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
360       mLaunchOptions(MakeUnique<base::LaunchOptions>()),
361       mProcessState(CREATING_CHANNEL),
362 #ifdef XP_WIN
363       mGroupId(u"-"),
364       mWerData{.mWerNotifyProc = CrashReporter::WerNotifyProc,
365                .mChildPid = 0,
366                .mMinidumpFile = {}},
367 #endif
368 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
369       mEnableSandboxLogging(false),
370       mSandboxLevel(0),
371 #endif
372       mChildProcessHandle(0),
373 #if defined(MOZ_WIDGET_COCOA)
374       mChildTask(MACH_PORT_NULL),
375 #endif
376 #if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
377       mDisableOSActivityMode(false),
378 #endif
379       mDestroying(false) {
380   MOZ_COUNT_CTOR(GeckoChildProcessHost);
381   StaticMutexAutoLock lock(sMutex);
382   if (!sGeckoChildProcessHosts) {
383     sGeckoChildProcessHosts = new mozilla::LinkedList<GeckoChildProcessHost>();
384   }
385   sGeckoChildProcessHosts->insertBack(this);
386 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
387   // The content process needs the content temp dir:
388   if (aProcessType == GeckoProcessType_Content) {
389     nsCOMPtr<nsIFile> contentTempDir;
390     nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
391                                          getter_AddRefs(contentTempDir));
392     if (NS_SUCCEEDED(rv)) {
393       contentTempDir->GetNativePath(mTmpDirName);
394     }
395   }
396 #endif
397 #if defined(MOZ_ENABLE_FORKSERVER)
398   if (aProcessType == GeckoProcessType_Content && ForkServiceChild::Get()) {
399     mLaunchOptions->use_forkserver = true;
400   }
401 #endif
402 }
403 
~GeckoChildProcessHost()404 GeckoChildProcessHost::~GeckoChildProcessHost()
405 
406 {
407   AssertIOThread();
408   MOZ_RELEASE_ASSERT(mDestroying);
409 
410   MOZ_COUNT_DTOR(GeckoChildProcessHost);
411 
412   if (mChildProcessHandle != 0) {
413 #if defined(MOZ_WIDGET_COCOA)
414     SharedMemoryBasic::CleanupForPidWithLock(mChildProcessHandle);
415 #endif
416     ProcessWatcher::EnsureProcessTerminated(
417         mChildProcessHandle
418 #ifdef NS_FREE_PERMANENT_DATA
419         // If we're doing leak logging, shutdown can be slow.
420         ,
421         false  // don't "force"
422 #endif
423     );
424   }
425 
426 #if defined(MOZ_WIDGET_COCOA)
427   if (mChildTask != MACH_PORT_NULL)
428     mach_port_deallocate(mach_task_self(), mChildTask);
429 #endif
430 
431   if (mChildProcessHandle != 0) {
432 #if defined(XP_WIN)
433     CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
434         base::GetProcId(mChildProcessHandle));
435 #else
436     CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
437         mChildProcessHandle);
438 #endif
439   }
440 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
441   if (mSandboxBroker) {
442     mSandboxBroker->Shutdown();
443     mSandboxBroker = nullptr;
444   }
445 #endif
446 }
447 
RemoveFromProcessList()448 void GeckoChildProcessHost::RemoveFromProcessList() {
449   StaticMutexAutoLock lock(sMutex);
450   if (!sGeckoChildProcessHosts) {
451     return;
452   }
453   LinkedListElement<GeckoChildProcessHost>::removeFrom(
454       *sGeckoChildProcessHosts);
455 }
456 
Destroy()457 void GeckoChildProcessHost::Destroy() {
458   MOZ_RELEASE_ASSERT(!mDestroying);
459   // We can remove from the list before it's really destroyed
460   RemoveFromProcessList();
461   RefPtr<ProcessHandlePromise> whenReady = mHandlePromise;
462 
463   if (!whenReady) {
464     // AsyncLaunch not called yet, so dispatch immediately.
465     whenReady = ProcessHandlePromise::CreateAndReject(LaunchError{}, __func__);
466   }
467 
468   using Value = ProcessHandlePromise::ResolveOrRejectValue;
469   mDestroying = true;
470   whenReady->Then(XRE_GetIOMessageLoop()->SerialEventTarget(), __func__,
471                   [this](const Value&) { delete this; });
472 }
473 
474 // static
GetPathToBinary(FilePath & exePath,GeckoProcessType processType)475 mozilla::BinPathType BaseProcessLauncher::GetPathToBinary(
476     FilePath& exePath, GeckoProcessType processType) {
477   BinPathType pathType = XRE_GetChildProcBinPathType(processType);
478 
479   if (pathType == BinPathType::Self) {
480 #if defined(OS_WIN)
481     wchar_t exePathBuf[MAXPATHLEN];
482     if (!::GetModuleFileNameW(nullptr, exePathBuf, MAXPATHLEN)) {
483       MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
484     }
485 #  if defined(MOZ_SANDBOX)
486     // We need to start the child process using the real path, so that the
487     // sandbox policy rules will match for DLLs loaded from the bin dir after
488     // we have lowered the sandbox.
489     std::wstring exePathStr = exePathBuf;
490     if (widget::WinUtils::ResolveJunctionPointsAndSymLinks(exePathStr)) {
491       exePath = FilePath::FromWStringHack(exePathStr);
492     } else
493 #  endif
494     {
495       exePath = FilePath::FromWStringHack(exePathBuf);
496     }
497 #elif defined(OS_POSIX)
498     exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
499 #else
500 #  error Sorry; target OS not supported yet.
501 #endif
502     return pathType;
503   }
504 
505   if (ShouldHaveDirectoryService()) {
506     MOZ_ASSERT(gGREBinPath);
507 #ifdef OS_WIN
508     exePath = FilePath(char16ptr_t(gGREBinPath));
509 #elif MOZ_WIDGET_COCOA
510     nsCOMPtr<nsIFile> childProcPath;
511     NS_NewLocalFile(nsDependentString(gGREBinPath), false,
512                     getter_AddRefs(childProcPath));
513 
514     // We need to use an App Bundle on OS X so that we can hide
515     // the dock icon. See Bug 557225.
516     childProcPath->AppendNative("plugin-container.app"_ns);
517     childProcPath->AppendNative("Contents"_ns);
518     childProcPath->AppendNative("MacOS"_ns);
519     nsCString tempCPath;
520     childProcPath->GetNativePath(tempCPath);
521     exePath = FilePath(tempCPath.get());
522 #else
523     nsCString path;
524     NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
525     exePath = FilePath(path.get());
526 #endif
527   }
528 
529   if (exePath.empty()) {
530 #ifdef OS_WIN
531     exePath =
532         FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
533 #else
534     exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
535 #endif
536     exePath = exePath.DirName();
537   }
538 
539   exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
540 
541   return pathType;
542 }
543 
544 #ifdef MOZ_WIDGET_COCOA
545 class AutoCFTypeObject {
546  public:
AutoCFTypeObject(CFTypeRef object)547   explicit AutoCFTypeObject(CFTypeRef object) { mObject = object; }
~AutoCFTypeObject()548   ~AutoCFTypeObject() { ::CFRelease(mObject); }
549 
550  private:
551   CFTypeRef mObject;
552 };
553 #endif
554 
555 // We start the unique IDs at 1 so that 0 can be used to mean that
556 // a component has no unique ID assigned to it.
557 uint32_t GeckoChildProcessHost::sNextUniqueID = 1;
558 
559 /* static */
GetUniqueID()560 uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID++; }
561 
562 /* static */
SetEnv(const char * aKey,const char * aValue)563 void GeckoChildProcessHost::SetEnv(const char* aKey, const char* aValue) {
564   MOZ_ASSERT(mLaunchOptions);
565   mLaunchOptions->env_map[ENVIRONMENT_STRING(aKey)] =
566       ENVIRONMENT_STRING(aValue);
567 }
568 
PrepareLaunch()569 void GeckoChildProcessHost::PrepareLaunch() {
570   if (CrashReporter::GetEnabled()) {
571     CrashReporter::OOPInit();
572   }
573 
574 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
575   SandboxLaunchPrepare(mProcessType, mLaunchOptions.get());
576 #endif
577 
578 #ifdef XP_WIN
579 
580 #  if defined(MOZ_SANDBOX)
581   // We need to get the pref here as the process is launched off main thread.
582   if (mProcessType == GeckoProcessType_Content) {
583     mSandboxLevel = GetEffectiveContentSandboxLevel();
584     mEnableSandboxLogging =
585         Preferences::GetBool("security.sandbox.logging.enabled");
586 
587     // We currently have to whitelist certain paths for tests to work in some
588     // development configurations.
589     nsAutoString readPaths;
590     nsresult rv = Preferences::GetString(
591         "security.sandbox.content.read_path_whitelist", readPaths);
592     if (NS_SUCCEEDED(rv)) {
593       for (const nsAString& readPath : readPaths.Split(',')) {
594         nsString trimmedPath(readPath);
595         trimmedPath.Trim(" ", true, true);
596         std::wstring resolvedPath(trimmedPath.Data());
597         // Before resolving check if path ends with '\' as this indicates we
598         // want to give read access to a directory and so it needs a wildcard.
599         bool addWildcard = (resolvedPath.back() == L'\\');
600         if (!widget::WinUtils::ResolveJunctionPointsAndSymLinks(resolvedPath)) {
601           NS_ERROR("Failed to resolve test read policy rule.");
602           continue;
603         }
604 
605         if (addWildcard) {
606           resolvedPath.append(L"\\*");
607         }
608         mAllowedFilesRead.push_back(resolvedPath);
609       }
610     }
611   }
612 #  endif
613 
614 #  if defined(MOZ_SANDBOX)
615   // For other process types we can't rely on them being launched on main
616   // thread and they may not have access to prefs in the child process, so allow
617   // them to turn on logging via an environment variable.
618   mEnableSandboxLogging =
619       mEnableSandboxLogging || !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
620 
621   if (ShouldHaveDirectoryService() && mProcessType == GeckoProcessType_GPU) {
622     mozilla::Unused << NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
623                                               getter_AddRefs(mProfileDir));
624   }
625 #  endif
626 #elif defined(XP_MACOSX)
627 #  if defined(MOZ_SANDBOX)
628   if (ShouldHaveDirectoryService() &&
629       mProcessType != GeckoProcessType_GMPlugin) {
630     mozilla::Unused << NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
631                                               getter_AddRefs(mProfileDir));
632   }
633 #  endif
634 #endif
635 }
636 
637 #ifdef XP_WIN
InitWindowsGroupID()638 void GeckoChildProcessHost::InitWindowsGroupID() {
639   // On Win7+, pass the application user model to the child, so it can
640   // register with it. This insures windows created by the container
641   // properly group with the parent app on the Win7 taskbar.
642   nsCOMPtr<nsIWinTaskbar> taskbarInfo = do_GetService(NS_TASKBAR_CONTRACTID);
643   if (taskbarInfo) {
644     bool isSupported = false;
645     taskbarInfo->GetAvailable(&isSupported);
646     nsAutoString appId;
647     if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
648       MOZ_ASSERT(mGroupId.EqualsLiteral("-"));
649       mGroupId.Assign(appId);
650     }
651   }
652 }
653 #endif
654 
SyncLaunch(std::vector<std::string> aExtraOpts,int aTimeoutMs)655 bool GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts,
656                                        int aTimeoutMs) {
657   if (!AsyncLaunch(std::move(aExtraOpts))) {
658     return false;
659   }
660   return WaitUntilConnected(aTimeoutMs);
661 }
662 
663 // Note: for most process types, we currently call AsyncLaunch, and therefore
664 // the *ProcessLauncher constructor, on the main thread, while the
665 // ProcessLauncher methods to actually execute the launch are called on the IO
666 // or IPC launcher thread. GMP processes are an exception - the GMP code
667 // invokes GeckoChildProcessHost from non-main-threads, and therefore we cannot
668 // rely on having access to mainthread-only services (like the directory
669 // service) from this code if we're launching that type of process.
AsyncLaunch(std::vector<std::string> aExtraOpts)670 bool GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts) {
671   PrepareLaunch();
672 
673 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
674   if (IsMacSandboxLaunchEnabled() && !AppendMacSandboxParams(aExtraOpts)) {
675     return false;
676   }
677 #endif
678 
679   RefPtr<BaseProcessLauncher> launcher =
680       new ProcessLauncher(this, std::move(aExtraOpts));
681 
682   // Note: Destroy() waits on mHandlePromise to delete |this|. As such, we want
683   // to be sure that all of our post-launch processing on |this| happens before
684   // mHandlePromise notifies.
685   MOZ_ASSERT(mHandlePromise == nullptr);
686   mHandlePromise =
687       mozilla::InvokeAsync<GeckoChildProcessHost*>(
688           IOThread(), launcher.get(), __func__, &BaseProcessLauncher::Launch,
689           this)
690           ->Then(
691               IOThread(), __func__,
692               [this](const LaunchResults& aResults) {
693                 {
694                   if (!OpenPrivilegedHandle(base::GetProcId(aResults.mHandle))
695 #ifdef XP_WIN
696                       // If we failed in opening the process handle, try harder
697                       // by duplicating one.
698                       && !::DuplicateHandle(
699                              ::GetCurrentProcess(), aResults.mHandle,
700                              ::GetCurrentProcess(), &mChildProcessHandle,
701                              PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
702                                  PROCESS_QUERY_INFORMATION | PROCESS_VM_READ |
703                                  SYNCHRONIZE,
704                              FALSE, 0)
705 #endif  // XP_WIN
706                   ) {
707                     MOZ_CRASH("cannot open handle to child process");
708                   }
709 
710 #ifdef XP_MACOSX
711                   this->mChildTask = aResults.mChildTask;
712 #endif
713 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
714                   this->mSandboxBroker = aResults.mSandboxBroker;
715 #endif
716 
717                   MonitorAutoLock lock(mMonitor);
718                   // The OnChannel{Connected,Error} may have already advanced
719                   // the state.
720                   if (mProcessState < PROCESS_CREATED) {
721                     mProcessState = PROCESS_CREATED;
722                   }
723                   lock.Notify();
724                 }
725                 return ProcessHandlePromise::CreateAndResolve(aResults.mHandle,
726                                                               __func__);
727               },
728               [this](const LaunchError aError) {
729                 // WaitUntilConnected might be waiting for us to signal.
730                 // If something failed let's set the error state and notify.
731                 CHROMIUM_LOG(ERROR)
732                     << "Failed to launch "
733                     << XRE_GeckoProcessTypeToString(mProcessType)
734                     << " subprocess";
735                 Telemetry::Accumulate(
736                     Telemetry::SUBPROCESS_LAUNCH_FAILURE,
737                     nsDependentCString(
738                         XRE_GeckoProcessTypeToString(mProcessType)));
739                 {
740                   MonitorAutoLock lock(mMonitor);
741                   mProcessState = PROCESS_ERROR;
742                   lock.Notify();
743                 }
744                 return ProcessHandlePromise::CreateAndReject(aError, __func__);
745               });
746   return true;
747 }
748 
WaitUntilConnected(int32_t aTimeoutMs)749 bool GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs) {
750   AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER);
751 
752   // NB: this uses a different mechanism than the chromium parent
753   // class.
754   TimeDuration timeout = (aTimeoutMs > 0)
755                              ? TimeDuration::FromMilliseconds(aTimeoutMs)
756                              : TimeDuration::Forever();
757 
758   MonitorAutoLock lock(mMonitor);
759   TimeStamp waitStart = TimeStamp::Now();
760   TimeStamp current;
761 
762   // We'll receive several notifications, we need to exit when we
763   // have either successfully launched or have timed out.
764   while (mProcessState != PROCESS_CONNECTED) {
765     // If there was an error then return it, don't wait out the timeout.
766     if (mProcessState == PROCESS_ERROR) {
767       break;
768     }
769 
770     CVStatus status = lock.Wait(timeout);
771     if (status == CVStatus::Timeout) {
772       break;
773     }
774 
775     if (timeout != TimeDuration::Forever()) {
776       current = TimeStamp::Now();
777       timeout -= current - waitStart;
778       waitStart = current;
779     }
780   }
781 
782   return mProcessState == PROCESS_CONNECTED;
783 }
784 
WaitForProcessHandle()785 bool GeckoChildProcessHost::WaitForProcessHandle() {
786   MonitorAutoLock lock(mMonitor);
787   while (mProcessState < PROCESS_CREATED) {
788     lock.Wait();
789   }
790   MOZ_ASSERT(mProcessState == PROCESS_ERROR || mChildProcessHandle);
791 
792   return mProcessState < PROCESS_ERROR;
793 }
794 
LaunchAndWaitForProcessHandle(StringVector aExtraOpts)795 bool GeckoChildProcessHost::LaunchAndWaitForProcessHandle(
796     StringVector aExtraOpts) {
797   if (!AsyncLaunch(std::move(aExtraOpts))) {
798     return false;
799   }
800   return WaitForProcessHandle();
801 }
802 
InitializeChannel(const std::function<void (IPC::Channel *)> & aChannelReady)803 void GeckoChildProcessHost::InitializeChannel(
804     const std::function<void(IPC::Channel*)>& aChannelReady) {
805   CreateChannel();
806 
807   aChannelReady(GetChannel());
808 
809   if (mProcessType != GeckoProcessType_ForkServer) {
810     RefPtr<NodeController> node = NodeController::GetSingleton();
811     mInitialPort = node->InviteChildProcess(TakeChannel());
812   }
813 
814   MonitorAutoLock lock(mMonitor);
815   mProcessState = CHANNEL_INITIALIZED;
816   lock.Notify();
817 }
818 
Join()819 void GeckoChildProcessHost::Join() {
820   AssertIOThread();
821 
822   if (!mChildProcessHandle) {
823     return;
824   }
825 
826   // If this fails, there's nothing we can do.
827   base::KillProcess(mChildProcessHandle, 0, /*wait*/ true);
828   SetAlreadyDead();
829 }
830 
SetAlreadyDead()831 void GeckoChildProcessHost::SetAlreadyDead() {
832   if (mChildProcessHandle && mChildProcessHandle != kInvalidProcessHandle) {
833     base::CloseProcessHandle(mChildProcessHandle);
834   }
835 
836   mChildProcessHandle = 0;
837 }
838 
GetChildLogName(const char * origLogName,nsACString & buffer)839 void BaseProcessLauncher::GetChildLogName(const char* origLogName,
840                                           nsACString& buffer) {
841 #ifdef XP_WIN
842   // On Windows we must expand relative paths because sandboxing rules
843   // bound only to full paths.  fopen fowards to NtCreateFile which checks
844   // the path against the sanboxing rules as passed to fopen (left relative).
845   char absPath[MAX_PATH + 2];
846   if (_fullpath(absPath, origLogName, sizeof(absPath))) {
847 #  ifdef MOZ_SANDBOX
848     // We need to make sure the child log name doesn't contain any junction
849     // points or symlinks or the sandbox will reject rules to allow writing.
850     std::wstring resolvedPath(NS_ConvertUTF8toUTF16(absPath).get());
851     if (widget::WinUtils::ResolveJunctionPointsAndSymLinks(resolvedPath)) {
852       AppendUTF16toUTF8(
853           Span(reinterpret_cast<const char16_t*>(resolvedPath.data()),
854                resolvedPath.size()),
855           buffer);
856     } else
857 #  endif
858     {
859       buffer.Append(absPath);
860     }
861   } else
862 #endif
863   {
864     buffer.Append(origLogName);
865   }
866 
867   // Remove .moz_log extension to avoid its duplication, it will be added
868   // automatically by the logging backend
869   static constexpr auto kMozLogExt = nsLiteralCString{MOZ_LOG_FILE_EXTENSION};
870   if (StringEndsWith(buffer, kMozLogExt)) {
871     buffer.Truncate(buffer.Length() - kMozLogExt.Length());
872   }
873 
874   // Append child-specific postfix to name
875   buffer.AppendLiteral(".child-");
876   buffer.AppendInt(gChildCounter);
877 }
878 
879 // Windows needs a single dedicated thread for process launching,
880 // because of thread-safety restrictions/assertions in the sandbox
881 // code.
882 //
883 // Android also needs a single dedicated thread to simplify thread
884 // safety in java.
885 //
886 // Fork server needs a dedicated thread for accessing
887 // |ForkServiceChild|.
888 #if defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID) || \
889     defined(MOZ_ENABLE_FORKSERVER)
890 
891 static mozilla::StaticMutex gIPCLaunchThreadMutex;
892 static mozilla::StaticRefPtr<nsIThread> gIPCLaunchThread;
893 
894 class IPCLaunchThreadObserver final : public nsIObserver {
895  public:
896   NS_DECL_ISUPPORTS
897   NS_DECL_NSIOBSERVER
898  protected:
899   virtual ~IPCLaunchThreadObserver() = default;
900 };
901 
NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver,nsIObserver,nsISupports)902 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver, nsIObserver, nsISupports)
903 
904 NS_IMETHODIMP
905 IPCLaunchThreadObserver::Observe(nsISupports* aSubject, const char* aTopic,
906                                  const char16_t* aData) {
907   MOZ_RELEASE_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0);
908   StaticMutexAutoLock lock(gIPCLaunchThreadMutex);
909 
910   nsresult rv = NS_OK;
911   if (gIPCLaunchThread) {
912     rv = gIPCLaunchThread->Shutdown();
913     gIPCLaunchThread = nullptr;
914   }
915   mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
916   return rv;
917 }
918 
GetIPCLauncher()919 nsCOMPtr<nsIEventTarget> GetIPCLauncher() {
920   StaticMutexAutoLock lock(gIPCLaunchThreadMutex);
921   if (!gIPCLaunchThread) {
922     nsCOMPtr<nsIThread> thread;
923     nsresult rv = NS_NewNamedThread("IPC Launch"_ns, getter_AddRefs(thread));
924     if (!NS_WARN_IF(NS_FAILED(rv))) {
925       NS_DispatchToMainThread(
926           NS_NewRunnableFunction("GeckoChildProcessHost::GetIPCLauncher", [] {
927             nsCOMPtr<nsIObserverService> obsService =
928                 mozilla::services::GetObserverService();
929             nsCOMPtr<nsIObserver> obs = new IPCLaunchThreadObserver();
930             obsService->AddObserver(obs, "xpcom-shutdown-threads", false);
931           }));
932       gIPCLaunchThread = thread.forget();
933     }
934   }
935 
936   nsCOMPtr<nsIEventTarget> thread = gIPCLaunchThread.get();
937   MOZ_DIAGNOSTIC_ASSERT(thread);
938   return thread;
939 }
940 
941 #else  // defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID) ||
942        // defined(MOZ_ENABLE_FORKSERVER)
943 
944 // Other platforms use an on-demand thread pool.
945 
GetIPCLauncher()946 nsCOMPtr<nsIEventTarget> GetIPCLauncher() {
947   nsCOMPtr<nsIEventTarget> pool =
948       mozilla::SharedThreadPool::Get("IPC Launch"_ns);
949   MOZ_DIAGNOSTIC_ASSERT(pool);
950   return pool;
951 }
952 
953 #endif  // XP_WIN || MOZ_WIDGET_ANDROID || MOZ_ENABLE_FORKSERVER
954 
955 void
956 #if defined(XP_WIN)
AddAppDirToCommandLine(CommandLine & aCmdLine,nsIFile * aAppDir)957 AddAppDirToCommandLine(CommandLine& aCmdLine, nsIFile* aAppDir)
958 #else
959 AddAppDirToCommandLine(std::vector<std::string>& aCmdLine, nsIFile* aAppDir,
960     nsIFile* aProfileDir)
961 #endif
962 {
963   // Content processes need access to application resources, so pass
964   // the full application directory path to the child process.
965   if (aAppDir) {
966 #if defined(XP_WIN)
967     nsString path;
968     MOZ_ALWAYS_SUCCEEDS(aAppDir->GetPath(path));
969     aCmdLine.AppendLooseValue(UTF8ToWide("-appdir"));
970     std::wstring wpath(path.get());
971     aCmdLine.AppendLooseValue(wpath);
972 #else
973     nsAutoCString path;
974     MOZ_ALWAYS_SUCCEEDS(aAppDir->GetNativePath(path));
975     aCmdLine.push_back("-appdir");
976     aCmdLine.push_back(path.get());
977 #endif
978 
979 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
980     // Full path to the profile dir
981     if (aProfileDir) {
982       // If the profile doesn't exist, normalization will
983       // fail. But we don't return an error here because some
984       // tests require startup with a missing profile dir.
985       // For users, almost universally, the profile will be in
986       // the home directory and normalization isn't required.
987       mozilla::Unused << aProfileDir->Normalize();
988       nsAutoCString path;
989       MOZ_ALWAYS_SUCCEEDS(aProfileDir->GetNativePath(path));
990       aCmdLine.push_back("-profile");
991       aCmdLine.push_back(path.get());
992     }
993 #endif
994   }
995 }
996 
997 #if defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
Contains(const std::vector<std::string> & aExtraOpts,const char * aValue)998 static bool Contains(const std::vector<std::string>& aExtraOpts,
999                      const char* aValue) {
1000   return std::any_of(aExtraOpts.begin(), aExtraOpts.end(),
1001                      [&](const std::string arg) {
1002                        return arg.find(aValue) != std::string::npos;
1003                      });
1004 }
1005 #endif  // defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
1006 
PerformAsyncLaunch()1007 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::PerformAsyncLaunch() {
1008   if (!DoSetup()) {
1009     return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
1010   }
1011   RefPtr<BaseProcessLauncher> self = this;
1012   return DoLaunch()->Then(
1013       mLaunchThread, __func__,
1014       [self](base::ProcessHandle aHandle) {
1015         self->mResults.mHandle = aHandle;
1016         return self->FinishLaunch();
1017       },
1018       [](LaunchError aError) {
1019         return ProcessLaunchPromise::CreateAndReject(aError, __func__);
1020       });
1021 }
1022 
DoSetup()1023 bool BaseProcessLauncher::DoSetup() {
1024 #if defined(MOZ_GECKO_PROFILER) || defined(MOZ_MEMORY)
1025   RefPtr<BaseProcessLauncher> self = this;
1026 #  ifdef MOZ_GECKO_PROFILER
1027   GetProfilerEnvVarsForChildProcess([self](const char* key, const char* value) {
1028     self->mLaunchOptions->env_map[ENVIRONMENT_STRING(key)] =
1029         ENVIRONMENT_STRING(value);
1030   });
1031 #  endif
1032 #  ifdef MOZ_MEMORY
1033   if (mProcessType == GeckoProcessType_Content) {
1034     nsAutoCString mallocOpts(PR_GetEnv("MALLOC_OPTIONS"));
1035     // Disable randomization of small arenas in content.
1036     mallocOpts.Append("r");
1037     self->mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MALLOC_OPTIONS")] =
1038         ENVIRONMENT_STRING(mallocOpts.get());
1039   }
1040 #  endif
1041 #endif
1042 
1043   MapChildLogging();
1044 
1045   return PR_CreatePipe(&mCrashAnnotationReadPipe.rwget(),
1046                        &mCrashAnnotationWritePipe.rwget()) == PR_SUCCESS;
1047 }
1048 
MapChildLogging()1049 void BaseProcessLauncher::MapChildLogging() {
1050   const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
1051   const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
1052 
1053   if (origNSPRLogName) {
1054     nsAutoCString nsprLogName;
1055     GetChildLogName(origNSPRLogName, nsprLogName);
1056     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("NSPR_LOG_FILE")] =
1057         ENVIRONMENT_STRING(nsprLogName.get());
1058   }
1059   if (origMozLogName) {
1060     nsAutoCString mozLogName;
1061     GetChildLogName(origMozLogName, mozLogName);
1062     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MOZ_LOG_FILE")] =
1063         ENVIRONMENT_STRING(mozLogName.get());
1064   }
1065 
1066   // `RUST_LOG_CHILD` is meant for logging child processes only.
1067   nsAutoCString childRustLog(PR_GetEnv("RUST_LOG_CHILD"));
1068   if (!childRustLog.IsEmpty()) {
1069     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("RUST_LOG")] =
1070         ENVIRONMENT_STRING(childRustLog.get());
1071   }
1072 }
1073 
1074 #if defined(MOZ_WIDGET_GTK)
DoSetup()1075 bool LinuxProcessLauncher::DoSetup() {
1076   if (!PosixProcessLauncher::DoSetup()) {
1077     return false;
1078   }
1079 
1080   if (mProcessType == GeckoProcessType_Content) {
1081     // disable IM module to avoid sandbox violation
1082     mLaunchOptions->env_map["GTK_IM_MODULE"] = "gtk-im-context-simple";
1083 
1084     // Disable ATK accessibility code in content processes because it conflicts
1085     // with the sandbox, and we proxy that information through the main process
1086     // anyway.
1087     mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
1088   }
1089 
1090 #  ifdef MOZ_SANDBOX
1091   if (!mTmpDirName.IsEmpty()) {
1092     // Point a bunch of things that might want to write from content to our
1093     // shiny new content-process specific tmpdir
1094     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("TMPDIR")] =
1095         ENVIRONMENT_STRING(mTmpDirName.get());
1096     // Partial fix for bug 1380051 (not persistent - should be)
1097     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
1098         ENVIRONMENT_STRING(mTmpDirName.get());
1099   }
1100 #  endif  // MOZ_SANDBOX
1101 
1102   return true;
1103 }
1104 #endif  // MOZ_WIDGET_GTK
1105 
1106 #ifdef OS_POSIX
DoSetup()1107 bool PosixProcessLauncher::DoSetup() {
1108   if (!BaseProcessLauncher::DoSetup()) {
1109     return false;
1110   }
1111 
1112   // XPCOM may not be initialized in some subprocesses.  We don't want
1113   // to initialize XPCOM just for the directory service, especially
1114   // since LD_LIBRARY_PATH is already set correctly in subprocesses
1115   // (meaning that we don't need to set that up in the environment).
1116   if (ShouldHaveDirectoryService()) {
1117     MOZ_ASSERT(gGREBinPath);
1118     nsCString path;
1119     NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
1120 #  if defined(OS_LINUX) || defined(OS_BSD)
1121     const char* ld_library_path = PR_GetEnv("LD_LIBRARY_PATH");
1122     nsCString new_ld_lib_path(path.get());
1123 
1124     if (ld_library_path && *ld_library_path) {
1125       new_ld_lib_path.Append(':');
1126       new_ld_lib_path.Append(ld_library_path);
1127     }
1128     mLaunchOptions->env_map["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
1129 
1130 #  elif OS_MACOSX  // defined(OS_LINUX) || defined(OS_BSD)
1131     mLaunchOptions->env_map["DYLD_LIBRARY_PATH"] = path.get();
1132 
1133     // DYLD_INSERT_LIBRARIES is currently unused by default but we allow
1134     // it to be set by the external environment.
1135     const char* interpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
1136     if (interpose && strlen(interpose) > 0) {
1137       mLaunchOptions->env_map["DYLD_INSERT_LIBRARIES"] = interpose;
1138     }
1139 
1140     // Prevent connection attempts to diagnosticd(8) to save cycles. Log
1141     // messages can trigger these connection attempts, but access to
1142     // diagnosticd is blocked in sandboxed child processes.
1143 #    ifdef MOZ_SANDBOX
1144     if (mDisableOSActivityMode) {
1145       mLaunchOptions->env_map["OS_ACTIVITY_MODE"] = "disable";
1146     }
1147 #    endif  // defined(MOZ_SANDBOX)
1148 #  endif    // defined(OS_LINUX) || defined(OS_BSD)
1149   }
1150 
1151   FilePath exePath;
1152   BinPathType pathType = GetPathToBinary(exePath, mProcessType);
1153 
1154   // remap the IPC socket fd to a well-known int, as the OS does for
1155   // STDOUT_FILENO, for example
1156   mLaunchOptions->fds_to_remap.push_back(
1157       std::pair<int, int>(mChannelSrcFd.get(), mChannelDstFd));
1158 
1159   // no need for kProcessChannelID, the child process inherits the
1160   // other end of the socketpair() from us
1161 
1162   mChildArgv.push_back(exePath.value());
1163 
1164   if (pathType == BinPathType::Self) {
1165     mChildArgv.push_back("-contentproc");
1166   }
1167 
1168   mChildArgv.insert(mChildArgv.end(), mExtraOpts.begin(), mExtraOpts.end());
1169 
1170   if (mProcessType != GeckoProcessType_GMPlugin) {
1171 #  if defined(MOZ_WIDGET_ANDROID)
1172     if (Omnijar::IsInitialized()) {
1173       // Make sure that child processes can find the omnijar
1174       // See XRE_InitCommandLine in nsAppRunner.cpp
1175       nsAutoCString path;
1176       nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
1177       if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
1178         mChildArgv.push_back("-greomni");
1179         mChildArgv.push_back(path.get());
1180       }
1181     }
1182 #  endif
1183     // Add the application directory path (-appdir path)
1184 #  ifdef XP_MACOSX
1185     AddAppDirToCommandLine(mChildArgv, mAppDir, mProfileDir);
1186 #  else
1187     AddAppDirToCommandLine(mChildArgv, mAppDir, nullptr);
1188 #  endif
1189   }
1190 
1191   mChildArgv.push_back(mPidString);
1192 
1193   if (!CrashReporter::IsDummy()) {
1194 #  if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
1195     int childCrashFd, childCrashRemapFd;
1196     if (!CrashReporter::CreateNotificationPipeForChild(&childCrashFd,
1197                                                        &childCrashRemapFd)) {
1198       return false;
1199     }
1200 
1201     if (0 <= childCrashFd) {
1202       mLaunchOptions->fds_to_remap.push_back(
1203           std::pair<int, int>(childCrashFd, childCrashRemapFd));
1204       // "true" == crash reporting enabled
1205       mChildArgv.push_back("true");
1206     } else {
1207       // "false" == crash reporting disabled
1208       mChildArgv.push_back("false");
1209     }
1210 #  elif defined(MOZ_WIDGET_COCOA) /* defined(OS_LINUX) || defined(OS_BSD) || \
1211                                      defined(OS_SOLARIS) */
1212     mChildArgv.push_back(CrashReporter::GetChildNotificationPipe());
1213 #  endif  // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
1214   }
1215 
1216   int fd = PR_FileDesc2NativeHandle(mCrashAnnotationWritePipe);
1217   mLaunchOptions->fds_to_remap.push_back(
1218       std::make_pair(fd, CrashReporter::GetAnnotationTimeCrashFd()));
1219 
1220 #  ifdef MOZ_WIDGET_COCOA
1221   mChildArgv.push_back(
1222       static_cast<MacProcessLauncher*>(this)->mMachConnectionName.c_str());
1223 #  endif  // MOZ_WIDGET_COCOA
1224 
1225   mChildArgv.push_back(ChildProcessType());
1226   return true;
1227 }
1228 #endif  // OS_POSIX
1229 
1230 #if defined(MOZ_WIDGET_ANDROID)
DoLaunch()1231 RefPtr<ProcessHandlePromise> AndroidProcessLauncher::DoLaunch() {
1232   return LaunchAndroidService(mProcessType, mChildArgv,
1233                               mLaunchOptions->fds_to_remap);
1234 }
1235 #endif  // MOZ_WIDGET_ANDROID
1236 
1237 #ifdef OS_POSIX
DoLaunch()1238 RefPtr<ProcessHandlePromise> PosixProcessLauncher::DoLaunch() {
1239   ProcessHandle handle = 0;
1240   if (!base::LaunchApp(mChildArgv, *mLaunchOptions, &handle)) {
1241     return ProcessHandlePromise::CreateAndReject(LaunchError{}, __func__);
1242   }
1243   return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1244 }
1245 
DoFinishLaunch()1246 bool PosixProcessLauncher::DoFinishLaunch() {
1247   if (!BaseProcessLauncher::DoFinishLaunch()) {
1248     return false;
1249   }
1250 
1251   // We're in the parent and the child was launched. Close the child FD in the
1252   // parent as soon as possible, which will allow the parent to detect when the
1253   // child closes its FD (either due to normal exit or due to crash).
1254   mChannelSrcFd = nullptr;
1255 
1256   return true;
1257 }
1258 #endif  // OS_POSIX
1259 
1260 #ifdef XP_MACOSX
DoFinishLaunch()1261 bool MacProcessLauncher::DoFinishLaunch() {
1262   if (!PosixProcessLauncher::DoFinishLaunch()) {
1263     return false;
1264   }
1265 
1266   // Wait for the child process to send us its 'task_t' data.
1267   const int kTimeoutMs = 10000;
1268 
1269   MachReceiveMessage child_message;
1270   kern_return_t err =
1271       mParentRecvPort.WaitForMessage(&child_message, kTimeoutMs);
1272   if (err != KERN_SUCCESS) {
1273     std::string errString =
1274         StringPrintf("0x%x %s", err, mach_error_string(err));
1275     CHROMIUM_LOG(ERROR) << "parent WaitForMessage() failed: " << errString;
1276     return false;
1277   }
1278 
1279   task_t child_task = child_message.GetTranslatedPort(0);
1280   if (child_task == MACH_PORT_NULL) {
1281     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
1282     return false;
1283   }
1284 
1285   if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
1286     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(1) failed.";
1287     return false;
1288   }
1289   MachPortSender parent_sender(child_message.GetTranslatedPort(1));
1290 
1291   if (child_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
1292     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(2) failed.";
1293   }
1294   auto* parent_recv_port_memory_ack =
1295       new MachPortSender(child_message.GetTranslatedPort(2));
1296 
1297   if (child_message.GetTranslatedPort(3) == MACH_PORT_NULL) {
1298     CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(3) failed.";
1299   }
1300   auto* parent_send_port_memory =
1301       new MachPortSender(child_message.GetTranslatedPort(3));
1302 
1303   MachSendMessage parent_message(/* id= */ 0);
1304   if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) {
1305     CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port
1306                         << ") failed.";
1307     return false;
1308   }
1309 
1310   auto* parent_recv_port_memory = new ReceivePort();
1311   if (!parent_message.AddDescriptor(
1312           MachMsgPortDescriptor(parent_recv_port_memory->GetPort()))) {
1313     CHROMIUM_LOG(ERROR) << "parent AddDescriptor("
1314                         << parent_recv_port_memory->GetPort() << ") failed.";
1315     return false;
1316   }
1317 
1318   auto* parent_send_port_memory_ack = new ReceivePort();
1319   if (!parent_message.AddDescriptor(
1320           MachMsgPortDescriptor(parent_send_port_memory_ack->GetPort()))) {
1321     CHROMIUM_LOG(ERROR) << "parent AddDescriptor("
1322                         << parent_send_port_memory_ack->GetPort()
1323                         << ") failed.";
1324     return false;
1325   }
1326 
1327   err = parent_sender.SendMessage(parent_message, kTimeoutMs);
1328   if (err != KERN_SUCCESS) {
1329     std::string errString =
1330         StringPrintf("0x%x %s", err, mach_error_string(err));
1331     CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString;
1332     return false;
1333   }
1334 
1335   SharedMemoryBasic::SetupMachMemory(
1336       mResults.mHandle, parent_recv_port_memory, parent_recv_port_memory_ack,
1337       parent_send_port_memory, parent_send_port_memory_ack, false);
1338 
1339   // NB: on OS X, we block much longer than we need to in order to
1340   // reach this call, waiting for the child process's task_t.  The
1341   // best way to fix that is to refactor this file, hard.
1342   mResults.mChildTask = child_task;
1343 
1344   return true;
1345 }
1346 #endif  // XP_MACOSX
1347 
1348 #ifdef XP_WIN
DoSetup()1349 bool WindowsProcessLauncher::DoSetup() {
1350   if (!BaseProcessLauncher::DoSetup()) {
1351     return false;
1352   }
1353 
1354   FilePath exePath;
1355   BinPathType pathType = GetPathToBinary(exePath, mProcessType);
1356 
1357 #  if defined(MOZ_SANDBOX) || defined(_ARM64_)
1358   const bool isGMP = mProcessType == GeckoProcessType_GMPlugin;
1359   const bool isWidevine = isGMP && Contains(mExtraOpts, "gmp-widevinecdm");
1360 #    if defined(_ARM64_)
1361   const bool isClearKey = isGMP && Contains(mExtraOpts, "gmp-clearkey");
1362   const bool isSandboxBroker =
1363       mProcessType == GeckoProcessType_RemoteSandboxBroker;
1364   if (isClearKey || isWidevine || isSandboxBroker) {
1365     // On Windows on ARM64 for ClearKey and Widevine, and for the sandbox
1366     // launcher process, we want to run the x86 plugin-container.exe in
1367     // the "i686" subdirectory, instead of the aarch64 plugin-container.exe.
1368     // So insert "i686" into the exePath.
1369     exePath = exePath.DirName().AppendASCII("i686").Append(exePath.BaseName());
1370   }
1371 #    endif  // if defined(_ARM64_)
1372 #  endif    // defined(MOZ_SANDBOX) || defined(_ARM64_)
1373 
1374   mCmdLine.emplace(exePath.ToWStringHack());
1375 
1376   if (pathType == BinPathType::Self) {
1377     mCmdLine->AppendLooseValue(UTF8ToWide("-contentproc"));
1378   }
1379 
1380   mCmdLine->AppendSwitchWithValue(switches::kProcessChannelID, mChannelId);
1381 
1382   for (std::vector<std::string>::iterator it = mExtraOpts.begin();
1383        it != mExtraOpts.end(); ++it) {
1384     mCmdLine->AppendLooseValue(UTF8ToWide(*it));
1385   }
1386 
1387 #  if defined(MOZ_SANDBOX)
1388 #    if defined(_ARM64_)
1389   if (isClearKey || isWidevine)
1390     mResults.mSandboxBroker = new RemoteSandboxBroker();
1391   else
1392 #    endif  // if defined(_ARM64_)
1393     mResults.mSandboxBroker = new SandboxBroker();
1394 
1395   // XXX: Bug 1124167: We should get rid of the process specific logic for
1396   // sandboxing in this class at some point. Unfortunately it will take a bit
1397   // of reorganizing so I don't think this patch is the right time.
1398   switch (mProcessType) {
1399     case GeckoProcessType_Content:
1400       if (mSandboxLevel > 0) {
1401         // For now we treat every failure as fatal in
1402         // SetSecurityLevelForContentProcess and just crash there right away.
1403         // Should this change in the future then we should also handle the error
1404         // here.
1405         mResults.mSandboxBroker->SetSecurityLevelForContentProcess(
1406             mSandboxLevel, mIsFileContent);
1407         mUseSandbox = true;
1408       }
1409       break;
1410     case GeckoProcessType_IPDLUnitTest:
1411       // XXX: We don't sandbox this process type yet
1412       break;
1413     case GeckoProcessType_GMPlugin:
1414       if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
1415         // The Widevine CDM on Windows can only load at USER_RESTRICTED,
1416         // not at USER_LOCKDOWN. So look in the command line arguments
1417         // to see if we're loading the path to the Widevine CDM, and if
1418         // so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
1419         auto level =
1420             isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
1421         if (!mResults.mSandboxBroker->SetSecurityLevelForGMPlugin(level)) {
1422           return false;
1423         }
1424         mUseSandbox = true;
1425       }
1426       break;
1427     case GeckoProcessType_GPU:
1428       if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) {
1429         // For now we treat every failure as fatal in
1430         // SetSecurityLevelForGPUProcess and just crash there right away. Should
1431         // this change in the future then we should also handle the error here.
1432         mResults.mSandboxBroker->SetSecurityLevelForGPUProcess(mSandboxLevel,
1433                                                                mProfileDir);
1434         mUseSandbox = true;
1435       }
1436       break;
1437     case GeckoProcessType_VR:
1438       if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
1439         // TODO: Implement sandbox for VR process, Bug 1430043.
1440       }
1441       break;
1442     case GeckoProcessType_RDD:
1443       if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
1444         if (!mResults.mSandboxBroker->SetSecurityLevelForRDDProcess()) {
1445           return false;
1446         }
1447         mUseSandbox = true;
1448       }
1449       break;
1450     case GeckoProcessType_Socket:
1451       if (!PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS_SANDBOX")) {
1452         if (!mResults.mSandboxBroker->SetSecurityLevelForSocketProcess()) {
1453           return false;
1454         }
1455         mUseSandbox = true;
1456       }
1457       break;
1458     case GeckoProcessType_RemoteSandboxBroker:
1459       // We don't sandbox the sandbox launcher...
1460       break;
1461     case GeckoProcessType_Default:
1462     default:
1463       MOZ_CRASH("Bad process type in GeckoChildProcessHost");
1464       break;
1465   };
1466 
1467   if (mUseSandbox) {
1468     for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end();
1469          ++it) {
1470       mResults.mSandboxBroker->AllowReadFile(it->c_str());
1471     }
1472   }
1473 #  endif  // defined(MOZ_SANDBOX)
1474 
1475   // Add the application directory path (-appdir path)
1476   AddAppDirToCommandLine(mCmdLine.ref(), mAppDir);
1477 
1478   // XXX Command line params past this point are expected to be at
1479   // the end of the command line string, and in a specific order.
1480   // See XRE_InitChildProcess in nsEmbedFunction.
1481 
1482   // Win app model id
1483   mCmdLine->AppendLooseValue(mGroupId.get());
1484 
1485   // Process id
1486   mCmdLine->AppendLooseValue(UTF8ToWide(mPidString));
1487 
1488   mCmdLine->AppendLooseValue(
1489       UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
1490 
1491   if (!CrashReporter::IsDummy()) {
1492     PROsfd h = PR_FileDesc2NativeHandle(mCrashAnnotationWritePipe);
1493     mLaunchOptions->handles_to_inherit.push_back(reinterpret_cast<HANDLE>(h));
1494     std::string hStr = std::to_string(h);
1495     mCmdLine->AppendLooseValue(UTF8ToWide(hStr));
1496 
1497     char werDataAddress[17] = {};
1498     SprintfLiteral(werDataAddress, "%p", mWerDataPointer);
1499     mCmdLine->AppendLooseValue(UTF8ToWide(werDataAddress));
1500   }
1501 
1502   // Process type
1503   mCmdLine->AppendLooseValue(UTF8ToWide(ChildProcessType()));
1504 
1505 #  ifdef MOZ_SANDBOX
1506   if (mUseSandbox) {
1507     // Mark the handles to inherit as inheritable.
1508     for (HANDLE h : mLaunchOptions->handles_to_inherit) {
1509       mResults.mSandboxBroker->AddHandleToShare(h);
1510     }
1511   }
1512 #  endif  // MOZ_SANDBOX
1513 
1514   return true;
1515 }
1516 
DoLaunch()1517 RefPtr<ProcessHandlePromise> WindowsProcessLauncher::DoLaunch() {
1518   ProcessHandle handle = 0;
1519 #  ifdef MOZ_SANDBOX
1520   if (mUseSandbox) {
1521     const IMAGE_THUNK_DATA* cachedNtdllThunk =
1522         mCachedNtdllThunk ? mCachedNtdllThunk->begin() : nullptr;
1523     if (mResults.mSandboxBroker->LaunchApp(
1524             mCmdLine->program().c_str(),
1525             mCmdLine->command_line_string().c_str(), mLaunchOptions->env_map,
1526             mProcessType, mEnableSandboxLogging, cachedNtdllThunk, &handle)) {
1527       EnvironmentLog("MOZ_PROCESS_LOG")
1528           .print("==> process %d launched child process %d (%S)\n",
1529                  base::GetCurrentProcId(), base::GetProcId(handle),
1530                  mCmdLine->command_line_string().c_str());
1531       return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1532     }
1533     return ProcessHandlePromise::CreateAndReject(LaunchError{}, __func__);
1534   }
1535 #  endif  // defined(MOZ_SANDBOX)
1536 
1537   if (!base::LaunchApp(mCmdLine.ref(), *mLaunchOptions, &handle)) {
1538     return ProcessHandlePromise::CreateAndReject(LaunchError{}, __func__);
1539   }
1540   return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1541 }
1542 
DoFinishLaunch()1543 bool WindowsProcessLauncher::DoFinishLaunch() {
1544   if (!BaseProcessLauncher::DoFinishLaunch()) {
1545     return false;
1546   }
1547 
1548 #  ifdef MOZ_SANDBOX
1549   if (!mUseSandbox) {
1550     // We need to be able to duplicate handles to some types of non-sandboxed
1551     // child processes.
1552     switch (mProcessType) {
1553       case GeckoProcessType_Default:
1554         MOZ_CRASH("shouldn't be launching a parent process");
1555       case GeckoProcessType_IPDLUnitTest:
1556         // No handle duplication necessary.
1557         break;
1558       default:
1559         if (!SandboxBroker::AddTargetPeer(mResults.mHandle)) {
1560           NS_WARNING("Failed to add child process as target peer.");
1561         }
1562         break;
1563     }
1564   }
1565 #  endif  // MOZ_SANDBOX
1566 
1567   return true;
1568 }
1569 #endif  // XP_WIN
1570 
FinishLaunch()1571 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::FinishLaunch() {
1572   if (!DoFinishLaunch()) {
1573     return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
1574   }
1575 
1576   MOZ_DIAGNOSTIC_ASSERT(mResults.mHandle);
1577 
1578   CrashReporter::RegisterChildCrashAnnotationFileDescriptor(
1579       base::GetProcId(mResults.mHandle), mCrashAnnotationReadPipe.forget());
1580 
1581   Telemetry::AccumulateTimeDelta(Telemetry::CHILD_PROCESS_LAUNCH_MS,
1582                                  mStartTimeStamp);
1583 
1584   return ProcessLaunchPromise::CreateAndResolve(mResults, __func__);
1585 }
1586 
OpenPrivilegedHandle(base::ProcessId aPid)1587 bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid) {
1588   if (mChildProcessHandle) {
1589     MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
1590     return true;
1591   }
1592 
1593   return base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle);
1594 }
1595 
OnChannelConnected(int32_t peer_pid)1596 void GeckoChildProcessHost::OnChannelConnected(int32_t peer_pid) {
1597   if (!OpenPrivilegedHandle(peer_pid)) {
1598     MOZ_CRASH("can't open handle to child process");
1599   }
1600   MonitorAutoLock lock(mMonitor);
1601   mProcessState = PROCESS_CONNECTED;
1602   lock.Notify();
1603 }
1604 
OnMessageReceived(IPC::Message && aMsg)1605 void GeckoChildProcessHost::OnMessageReceived(IPC::Message&& aMsg) {
1606   // We never process messages ourself, just save them up for the next
1607   // listener.
1608   mQueue.push(std::move(aMsg));
1609 }
1610 
OnChannelError()1611 void GeckoChildProcessHost::OnChannelError() {
1612   // Update the process state to an error state if we have a channel
1613   // error before we're connected. This fixes certain failures,
1614   // but does not address the full range of possible issues described
1615   // in the FIXME comment below.
1616   MonitorAutoLock lock(mMonitor);
1617   if (mProcessState < PROCESS_CONNECTED) {
1618     mProcessState = PROCESS_ERROR;
1619     lock.Notify();
1620   }
1621   // FIXME/bug 773925: save up this error for the next listener.
1622 }
1623 
WhenProcessHandleReady()1624 RefPtr<ProcessHandlePromise> GeckoChildProcessHost::WhenProcessHandleReady() {
1625   MOZ_ASSERT(mHandlePromise != nullptr);
1626   return mHandlePromise;
1627 }
1628 
GetQueuedMessages(std::queue<IPC::Message> & queue)1629 void GeckoChildProcessHost::GetQueuedMessages(std::queue<IPC::Message>& queue) {
1630   // If this is called off the IO thread, bad things will happen.
1631   DCHECK(MessageLoopForIO::current());
1632   swap(queue, mQueue);
1633   // We expect the next listener to take over processing of our queue.
1634 }
1635 
1636 #ifdef MOZ_WIDGET_ANDROID
LaunchAndroidService(const GeckoProcessType aType,const std::vector<std::string> & argv,const base::file_handle_mapping_vector & fds_to_remap)1637 RefPtr<ProcessHandlePromise> AndroidProcessLauncher::LaunchAndroidService(
1638     const GeckoProcessType aType, const std::vector<std::string>& argv,
1639     const base::file_handle_mapping_vector& fds_to_remap) {
1640   MOZ_RELEASE_ASSERT((2 <= fds_to_remap.size()) && (fds_to_remap.size() <= 5));
1641   JNIEnv* const env = mozilla::jni::GetEnvForThread();
1642   MOZ_ASSERT(env);
1643 
1644   const int argvSize = argv.size();
1645   jni::ObjectArray::LocalRef jargs =
1646       jni::ObjectArray::New<jni::String>(argvSize);
1647   for (int ix = 0; ix < argvSize; ix++) {
1648     jargs->SetElement(ix, jni::StringParam(argv[ix].c_str(), env));
1649   }
1650 
1651   // XXX: this processing depends entirely on the internals of
1652   // ContentParent::LaunchSubprocess()
1653   // GeckoChildProcessHost::PerformAsyncLaunch(), and the order in
1654   // which they append to fds_to_remap. There must be a better way to do it.
1655   // See bug 1440207.
1656   int32_t prefsFd = fds_to_remap[0].first;
1657   int32_t prefMapFd = fds_to_remap[1].first;
1658   int32_t ipcFd = fds_to_remap[2].first;
1659   int32_t crashFd = -1;
1660   int32_t crashAnnotationFd = -1;
1661   if (fds_to_remap.size() == 4) {
1662     crashAnnotationFd = fds_to_remap[3].first;
1663   }
1664   if (fds_to_remap.size() == 5) {
1665     crashFd = fds_to_remap[3].first;
1666     crashAnnotationFd = fds_to_remap[4].first;
1667   }
1668 
1669   auto type = java::GeckoProcessType::FromInt(aType);
1670   auto genericResult = java::GeckoProcessManager::Start(
1671       type, jargs, prefsFd, prefMapFd, ipcFd, crashFd, crashAnnotationFd);
1672   auto typedResult = java::GeckoResult::LocalRef(std::move(genericResult));
1673   return ProcessHandlePromise::FromGeckoResult(typedResult);
1674 }
1675 #endif
1676 
1677 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
AppendMacSandboxParams(StringVector & aArgs)1678 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector& aArgs) {
1679   MacSandboxInfo info;
1680   if (!FillMacSandboxInfo(info)) {
1681     return false;
1682   }
1683   info.AppendAsParams(aArgs);
1684   return true;
1685 }
1686 
1687 // Fill |aInfo| with the flags needed to launch the utility sandbox
FillMacSandboxInfo(MacSandboxInfo & aInfo)1688 bool GeckoChildProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
1689   aInfo.type = GetDefaultMacSandboxType();
1690   aInfo.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled") ||
1691                     PR_GetEnv("MOZ_SANDBOX_LOGGING");
1692 
1693   nsAutoCString appPath;
1694   if (!nsMacUtilsImpl::GetAppPath(appPath)) {
1695     MOZ_CRASH("Failed to get app path");
1696   }
1697   aInfo.appPath.assign(appPath.get());
1698   return true;
1699 }
1700 
DisableOSActivityMode()1701 void GeckoChildProcessHost::DisableOSActivityMode() {
1702   mDisableOSActivityMode = true;
1703 }
1704 
1705 //
1706 // If early sandbox startup is enabled for this process type, map the
1707 // process type to the sandbox type and enable the sandbox. Returns true
1708 // if no errors were encountered or if early sandbox startup is not
1709 // enabled for this process. Returns false if an error was encountered.
1710 //
1711 /* static */
StartMacSandbox(int aArgc,char ** aArgv,std::string & aErrorMessage)1712 bool GeckoChildProcessHost::StartMacSandbox(int aArgc, char** aArgv,
1713                                             std::string& aErrorMessage) {
1714   MacSandboxType sandboxType = MacSandboxType_Invalid;
1715   switch (XRE_GetProcessType()) {
1716     // For now, only support early sandbox startup for content,
1717     // RDD, and GMP processes. Add case statements for the additional
1718     // process types once early sandbox startup is implemented for them.
1719     case GeckoProcessType_Content:
1720       // Content processes don't use GeckoChildProcessHost
1721       // to configure sandboxing so hard code the sandbox type.
1722       sandboxType = MacSandboxType_Content;
1723       break;
1724     case GeckoProcessType_RDD:
1725       sandboxType = RDDProcessHost::GetMacSandboxType();
1726       break;
1727     case GeckoProcessType_Socket:
1728       sandboxType = net::SocketProcessHost::GetMacSandboxType();
1729       break;
1730     case GeckoProcessType_GMPlugin:
1731       sandboxType = gmp::GMPProcessParent::GetMacSandboxType();
1732       break;
1733     default:
1734       return true;
1735   }
1736   return mozilla::StartMacSandboxIfEnabled(sandboxType, aArgc, aArgv,
1737                                            aErrorMessage);
1738 }
1739 
1740 #endif /* XP_MACOSX && MOZ_SANDBOX */
1741 
1742 /* static */
GetAll(const GeckoProcessCallback & aCallback)1743 void GeckoChildProcessHost::GetAll(const GeckoProcessCallback& aCallback) {
1744   StaticMutexAutoLock lock(sMutex);
1745   if (!sGeckoChildProcessHosts) {
1746     return;
1747   }
1748   for (GeckoChildProcessHost* gp = sGeckoChildProcessHosts->getFirst(); gp;
1749        gp = static_cast<mozilla::LinkedListElement<GeckoChildProcessHost>*>(gp)
1750                 ->getNext()) {
1751     aCallback(gp);
1752   }
1753 }
1754 
Launch(GeckoChildProcessHost * aHost)1755 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::Launch(
1756     GeckoChildProcessHost* aHost) {
1757   AssertIOThread();
1758 
1759   // Initializing the channel needs to happen on the I/O thread, but everything
1760   // else can run on the launcher thread (or pool), to avoid blocking IPC
1761   // messages.
1762   //
1763   // We avoid passing the host to the launcher thread to reduce the chances of
1764   // data races with the IO thread (where e.g. OnChannelConnected may run
1765   // concurrently). The pool currently needs access to the channel, which is not
1766   // great.
1767   bool failed = false;
1768   aHost->InitializeChannel([&](IPC::Channel* channel) {
1769     if (!channel || !SetChannel(channel)) {
1770       failed = true;
1771     }
1772   });
1773   if (failed) {
1774     return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
1775   }
1776   mChannelId = aHost->GetChannelId();
1777 
1778   return InvokeAsync(mLaunchThread, this, __func__,
1779                      &BaseProcessLauncher::PerformAsyncLaunch);
1780 }
1781 
1782 }  // namespace ipc
1783 }  // namespace mozilla
1784