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