Bug 1578501 [wpt PR 18803] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / ipc / glue / GeckoChildProcessHost.cpp
blob2311b4e6b99d46bde708d12ed0edfb5cc78b6805
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/. */
7 #include "GeckoChildProcessHost.h"
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
21 #include "MainThreadUtils.h"
22 #include "mozilla/Sprintf.h"
23 #include "prenv.h"
24 #include "nsXPCOMPrivate.h"
26 #if defined(MOZ_SANDBOX)
27 # include "mozilla/SandboxSettings.h"
28 # include "nsAppDirectoryServiceDefs.h"
29 #endif
31 #include "nsExceptionHandler.h"
33 #include "nsDirectoryService.h"
34 #include "nsDirectoryServiceDefs.h"
35 #include "nsIFile.h"
36 #include "nsPrintfCString.h"
37 #include "nsIObserverService.h"
39 #include "mozilla/ipc/BrowserProcessSubThread.h"
40 #include "mozilla/ipc/EnvironmentMap.h"
41 #include "mozilla/LinkedList.h"
42 #include "mozilla/Logging.h"
43 #include "mozilla/Maybe.h"
44 #include "mozilla/Omnijar.h"
45 #include "mozilla/RecordReplay.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>
56 #ifdef XP_WIN
57 # include "nsIWinTaskbar.h"
58 # include <stdlib.h>
59 # define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
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 #endif
71 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
72 # include "mozilla/SandboxLaunch.h"
73 #endif
75 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
76 # include "GMPProcessParent.h"
77 # include "nsMacUtilsImpl.h"
78 #endif
80 #include "nsTArray.h"
81 #include "nsClassHashtable.h"
82 #include "nsHashKeys.h"
83 #include "nsNativeCharsetUtils.h"
84 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
85 #include "private/pprio.h"
87 using mozilla::MonitorAutoLock;
88 using mozilla::Preferences;
89 using mozilla::StaticMutexAutoLock;
91 namespace mozilla {
92 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc,
93 PR_Close)
96 using mozilla::ScopedPRFileDesc;
98 #ifdef MOZ_WIDGET_ANDROID
99 # include "AndroidBridge.h"
100 # include "GeneratedJNIWrappers.h"
101 # include "mozilla/jni/Refs.h"
102 # include "mozilla/jni/Utils.h"
103 #endif
105 static bool ShouldHaveDirectoryService() {
106 return GeckoProcessType_Default == XRE_GetProcessType();
109 namespace mozilla {
110 namespace ipc {
112 static Atomic<int32_t> gChildCounter;
114 static inline nsISerialEventTarget* IOThread() {
115 return XRE_GetIOMessageLoop()->SerialEventTarget();
118 class BaseProcessLauncher {
119 public:
120 BaseProcessLauncher(GeckoChildProcessHost* aHost,
121 std::vector<std::string>&& aExtraOpts)
122 : mProcessType(aHost->mProcessType),
123 mLaunchOptions(std::move(aHost->mLaunchOptions)),
124 mExtraOpts(std::move(aExtraOpts)),
125 #ifdef XP_WIN
126 mGroupId(aHost->mGroupId),
127 #endif
128 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
129 mAllowedFilesRead(aHost->mAllowedFilesRead),
130 mSandboxLevel(aHost->mSandboxLevel),
131 mIsFileContent(aHost->mIsFileContent),
132 mEnableSandboxLogging(aHost->mEnableSandboxLogging),
133 #endif
134 mTmpDirName(aHost->mTmpDirName),
135 mChildId(++gChildCounter) {
136 SprintfLiteral(mPidString, "%d", base::GetCurrentProcId());
138 // Compute the serial event target we'll use for launching.
139 if (mozilla::recordreplay::IsMiddleman()) {
140 // During Web Replay, the middleman process launches the actual content
141 // processes, and doesn't initialize enough of XPCOM to use thread pools.
142 mLaunchThread = IOThread();
143 } else {
144 nsCOMPtr<nsIEventTarget> threadOrPool = GetIPCLauncher();
145 mLaunchThread = new TaskQueue(threadOrPool.forget());
147 if (ShouldHaveDirectoryService()) {
148 // "Current process directory" means the app dir, not the current
149 // working dir or similar.
150 mozilla::Unused
151 << nsDirectoryService::gService->GetCurrentProcessDirectory(
152 getter_AddRefs(mAppDir));
156 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseProcessLauncher);
158 RefPtr<ProcessLaunchPromise> Launch(GeckoChildProcessHost*);
160 protected:
161 virtual ~BaseProcessLauncher() = default;
163 RefPtr<ProcessLaunchPromise> PerformAsyncLaunch();
164 RefPtr<ProcessLaunchPromise> FinishLaunch();
166 // Overrideable hooks. If superclass behavior is invoked, it's always at the
167 // top of the override.
168 virtual bool DoSetup();
169 virtual RefPtr<ProcessHandlePromise> DoLaunch() = 0;
170 virtual bool DoFinishLaunch() { return true; };
172 void MapChildLogging();
174 static BinPathType GetPathToBinary(FilePath&, GeckoProcessType);
176 void GetChildLogName(const char* origLogName, nsACString& buffer);
178 const char* ChildProcessType() {
179 return XRE_ChildProcessTypeToString(mProcessType);
182 nsCOMPtr<nsIEventTarget> GetIPCLauncher();
184 nsCOMPtr<nsISerialEventTarget> mLaunchThread;
185 GeckoProcessType mProcessType;
186 UniquePtr<base::LaunchOptions> mLaunchOptions;
187 std::vector<std::string> mExtraOpts;
188 #ifdef XP_WIN
189 nsString mGroupId;
190 #endif
191 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
192 std::vector<std::wstring> mAllowedFilesRead;
193 int32_t mSandboxLevel;
194 bool mIsFileContent;
195 bool mEnableSandboxLogging;
196 #endif
197 nsCString mTmpDirName;
198 LaunchResults mResults = LaunchResults();
199 int32_t mChildId;
200 TimeStamp mStartTimeStamp = TimeStamp::Now();
201 char mPidString[32];
203 // Set during launch.
204 IPC::Channel* mChannel = nullptr;
205 std::wstring mChannelId;
206 ScopedPRFileDesc mCrashAnnotationReadPipe;
207 ScopedPRFileDesc mCrashAnnotationWritePipe;
208 nsCOMPtr<nsIFile> mAppDir;
211 #ifdef XP_WIN
212 class WindowsProcessLauncher : public BaseProcessLauncher {
213 public:
214 WindowsProcessLauncher(GeckoChildProcessHost* aHost,
215 std::vector<std::string>&& aExtraOpts)
216 : BaseProcessLauncher(aHost, std::move(aExtraOpts)) {}
218 protected:
219 virtual bool DoSetup() override;
220 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
221 virtual bool DoFinishLaunch() override;
223 mozilla::Maybe<CommandLine> mCmdLine;
224 bool mUseSandbox = false;
226 typedef WindowsProcessLauncher ProcessLauncher;
227 #endif // XP_WIN
229 #ifdef OS_POSIX
230 class PosixProcessLauncher : public BaseProcessLauncher {
231 public:
232 PosixProcessLauncher(GeckoChildProcessHost* aHost,
233 std::vector<std::string>&& aExtraOpts)
234 : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
235 mProfileDir(aHost->mProfileDir) {}
237 protected:
238 virtual bool DoSetup() override;
239 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
240 virtual bool DoFinishLaunch() override;
242 nsCOMPtr<nsIFile> mProfileDir;
244 std::vector<std::string> mChildArgv;
247 # if defined(XP_MACOSX)
248 class MacProcessLauncher : public PosixProcessLauncher {
249 public:
250 MacProcessLauncher(GeckoChildProcessHost* aHost,
251 std::vector<std::string>&& aExtraOpts)
252 : PosixProcessLauncher(aHost, std::move(aExtraOpts)),
253 // Put a random number into the channel name, so that
254 // a compromised renderer can't pretend being the child
255 // that's forked off.
256 mMachConnectionName(
257 StringPrintf("org.mozilla.machname.%d",
258 base::RandInt(0, std::numeric_limits<int>::max()))),
259 mParentRecvPort(mMachConnectionName.c_str()) {}
261 protected:
262 virtual bool DoFinishLaunch() override;
264 std::string mMachConnectionName;
265 // We add a mach port to the command line so the child can communicate its
266 // 'task_t' back to the parent.
267 ReceivePort mParentRecvPort;
269 friend class PosixProcessLauncher;
271 typedef MacProcessLauncher ProcessLauncher;
272 # elif defined(MOZ_WIDGET_ANDROID)
273 class AndroidProcessLauncher : public PosixProcessLauncher {
274 public:
275 AndroidProcessLauncher(GeckoChildProcessHost* aHost,
276 std::vector<std::string>&& aExtraOpts)
277 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
279 protected:
280 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
281 RefPtr<ProcessHandlePromise> LaunchAndroidService(
282 const char* type, const std::vector<std::string>& argv,
283 const base::file_handle_mapping_vector& fds_to_remap);
285 typedef AndroidProcessLauncher ProcessLauncher;
286 // NB: Technically Android is linux (i.e. XP_LINUX is defined), but we want
287 // orthogonal IPC machinery there. Conversely, there are tier-3 non-Linux
288 // platforms (BSD and Solaris) where we want the "linux" IPC machinery. So
289 // we use MOZ_WIDGET_* to choose the platform backend.
290 # elif defined(MOZ_WIDGET_GTK)
291 class LinuxProcessLauncher : public PosixProcessLauncher {
292 public:
293 LinuxProcessLauncher(GeckoChildProcessHost* aHost,
294 std::vector<std::string>&& aExtraOpts)
295 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
297 protected:
298 virtual bool DoSetup() override;
300 typedef LinuxProcessLauncher ProcessLauncher;
301 # elif
302 # error "Unknown platform"
303 # endif
304 #endif // OS_POSIX
306 using base::ProcessHandle;
307 using mozilla::ipc::BaseProcessLauncher;
308 using mozilla::ipc::ProcessLauncher;
310 mozilla::StaticAutoPtr<mozilla::LinkedList<GeckoChildProcessHost>>
311 GeckoChildProcessHost::sGeckoChildProcessHosts;
313 mozilla::StaticMutex GeckoChildProcessHost::sMutex;
315 GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
316 bool aIsFileContent)
317 : mProcessType(aProcessType),
318 mIsFileContent(aIsFileContent),
319 mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
320 mLaunchOptions(MakeUnique<base::LaunchOptions>()),
321 mProcessState(CREATING_CHANNEL),
322 #ifdef XP_WIN
323 mGroupId(u"-"),
324 #endif
325 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
326 mEnableSandboxLogging(false),
327 mSandboxLevel(0),
328 #endif
329 mChildProcessHandle(0),
330 #if defined(MOZ_WIDGET_COCOA)
331 mChildTask(MACH_PORT_NULL),
332 #endif
333 mDestroying(false) {
334 MOZ_COUNT_CTOR(GeckoChildProcessHost);
335 StaticMutexAutoLock lock(sMutex);
336 if (!sGeckoChildProcessHosts) {
337 sGeckoChildProcessHosts = new mozilla::LinkedList<GeckoChildProcessHost>();
339 sGeckoChildProcessHosts->insertBack(this);
340 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
341 // The content process needs the content temp dir:
342 if (aProcessType == GeckoProcessType_Content) {
343 nsCOMPtr<nsIFile> contentTempDir;
344 nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
345 getter_AddRefs(contentTempDir));
346 if (NS_SUCCEEDED(rv)) {
347 contentTempDir->GetNativePath(mTmpDirName);
350 #endif
353 GeckoChildProcessHost::~GeckoChildProcessHost()
356 AssertIOThread();
357 MOZ_RELEASE_ASSERT(mDestroying);
359 MOZ_COUNT_DTOR(GeckoChildProcessHost);
361 if (mChildProcessHandle != 0) {
362 #if defined(MOZ_WIDGET_COCOA)
363 SharedMemoryBasic::CleanupForPid(mChildProcessHandle);
364 #endif
365 ProcessWatcher::EnsureProcessTerminated(
366 mChildProcessHandle
367 #ifdef NS_FREE_PERMANENT_DATA
368 // If we're doing leak logging, shutdown can be slow.
370 false // don't "force"
371 #endif
375 #if defined(MOZ_WIDGET_COCOA)
376 if (mChildTask != MACH_PORT_NULL)
377 mach_port_deallocate(mach_task_self(), mChildTask);
378 #endif
380 if (mChildProcessHandle != 0) {
381 #if defined(XP_WIN)
382 CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
383 base::GetProcId(mChildProcessHandle));
384 #else
385 CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
386 mChildProcessHandle);
387 #endif
389 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
390 if (mSandboxBroker) {
391 mSandboxBroker->Shutdown();
392 mSandboxBroker = nullptr;
394 #endif
397 void GeckoChildProcessHost::RemoveFromProcessList() {
398 StaticMutexAutoLock lock(sMutex);
399 if (!sGeckoChildProcessHosts) {
400 return;
402 LinkedListElement<GeckoChildProcessHost>::removeFrom(
403 *sGeckoChildProcessHosts);
406 void GeckoChildProcessHost::Destroy() {
407 MOZ_RELEASE_ASSERT(!mDestroying);
408 // We can remove from the list before it's really destroyed
409 RemoveFromProcessList();
410 RefPtr<ProcessHandlePromise> whenReady = mHandlePromise;
412 if (!whenReady) {
413 // AsyncLaunch not called yet, so dispatch immediately.
414 whenReady = ProcessHandlePromise::CreateAndReject(LaunchError{}, __func__);
417 using Value = ProcessHandlePromise::ResolveOrRejectValue;
418 mDestroying = true;
419 whenReady->Then(XRE_GetIOMessageLoop()->SerialEventTarget(), __func__,
420 [this](const Value&) { delete this; });
423 // static
424 mozilla::BinPathType BaseProcessLauncher::GetPathToBinary(
425 FilePath& exePath, GeckoProcessType processType) {
426 BinPathType pathType = XRE_GetChildProcBinPathType(processType);
428 if (pathType == BinPathType::Self) {
429 #if defined(OS_WIN)
430 wchar_t exePathBuf[MAXPATHLEN];
431 if (!::GetModuleFileNameW(nullptr, exePathBuf, MAXPATHLEN)) {
432 MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
434 # if defined(MOZ_SANDBOX)
435 // We need to start the child process using the real path, so that the
436 // sandbox policy rules will match for DLLs loaded from the bin dir after
437 // we have lowered the sandbox.
438 std::wstring exePathStr = exePathBuf;
439 if (widget::WinUtils::ResolveJunctionPointsAndSymLinks(exePathStr)) {
440 exePath = FilePath::FromWStringHack(exePathStr);
441 } else
442 # endif
444 exePath = FilePath::FromWStringHack(exePathBuf);
446 #elif defined(OS_POSIX)
447 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
448 #else
449 # error Sorry; target OS not supported yet.
450 #endif
451 return pathType;
454 if (ShouldHaveDirectoryService()) {
455 MOZ_ASSERT(gGREBinPath);
456 #ifdef OS_WIN
457 exePath = FilePath(char16ptr_t(gGREBinPath));
458 #elif MOZ_WIDGET_COCOA
459 nsCOMPtr<nsIFile> childProcPath;
460 NS_NewLocalFile(nsDependentString(gGREBinPath), false,
461 getter_AddRefs(childProcPath));
463 // We need to use an App Bundle on OS X so that we can hide
464 // the dock icon. See Bug 557225.
465 childProcPath->AppendNative(NS_LITERAL_CSTRING("plugin-container.app"));
466 childProcPath->AppendNative(NS_LITERAL_CSTRING("Contents"));
467 childProcPath->AppendNative(NS_LITERAL_CSTRING("MacOS"));
468 nsCString tempCPath;
469 childProcPath->GetNativePath(tempCPath);
470 exePath = FilePath(tempCPath.get());
471 #else
472 nsCString path;
473 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
474 exePath = FilePath(path.get());
475 #endif
478 if (exePath.empty()) {
479 #ifdef OS_WIN
480 exePath =
481 FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
482 #else
483 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
484 #endif
485 exePath = exePath.DirName();
488 exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
490 return pathType;
493 #ifdef MOZ_WIDGET_COCOA
494 class AutoCFTypeObject {
495 public:
496 explicit AutoCFTypeObject(CFTypeRef object) { mObject = object; }
497 ~AutoCFTypeObject() { ::CFRelease(mObject); }
499 private:
500 CFTypeRef mObject;
502 #endif
504 // We start the unique IDs at 1 so that 0 can be used to mean that
505 // a component has no unique ID assigned to it.
506 uint32_t GeckoChildProcessHost::sNextUniqueID = 1;
508 /* static */
509 uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID++; }
511 void GeckoChildProcessHost::PrepareLaunch() {
512 if (CrashReporter::GetEnabled()) {
513 CrashReporter::OOPInit();
516 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
517 SandboxLaunchPrepare(mProcessType, mLaunchOptions.get());
518 #endif
520 #ifdef XP_WIN
521 if (mProcessType == GeckoProcessType_Plugin) {
522 InitWindowsGroupID();
525 # if defined(MOZ_SANDBOX)
526 // We need to get the pref here as the process is launched off main thread.
527 if (mProcessType == GeckoProcessType_Content) {
528 mSandboxLevel = GetEffectiveContentSandboxLevel();
529 mEnableSandboxLogging =
530 Preferences::GetBool("security.sandbox.logging.enabled");
532 // We currently have to whitelist certain paths for tests to work in some
533 // development configurations.
534 nsAutoString readPaths;
535 nsresult rv = Preferences::GetString(
536 "security.sandbox.content.read_path_whitelist", readPaths);
537 if (NS_SUCCEEDED(rv)) {
538 for (const nsAString& readPath : readPaths.Split(',')) {
539 nsString trimmedPath(readPath);
540 trimmedPath.Trim(" ", true, true);
541 std::wstring resolvedPath(trimmedPath.Data());
542 // Before resolving check if path ends with '\' as this indicates we
543 // want to give read access to a directory and so it needs a wildcard.
544 bool addWildcard = (resolvedPath.back() == L'\\');
545 if (!widget::WinUtils::ResolveJunctionPointsAndSymLinks(resolvedPath)) {
546 NS_ERROR("Failed to resolve test read policy rule.");
547 continue;
550 if (addWildcard) {
551 resolvedPath.append(L"\\*");
553 mAllowedFilesRead.push_back(resolvedPath);
557 # endif
559 # if defined(MOZ_SANDBOX)
560 // For other process types we can't rely on them being launched on main
561 // thread and they may not have access to prefs in the child process, so allow
562 // them to turn on logging via an environment variable.
563 mEnableSandboxLogging =
564 mEnableSandboxLogging || !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
565 # endif
566 #elif defined(XP_MACOSX)
567 # if defined(MOZ_SANDBOX)
568 if (ShouldHaveDirectoryService() &&
569 mProcessType != GeckoProcessType_GMPlugin) {
570 mozilla::Unused << NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
571 getter_AddRefs(mProfileDir));
573 # endif
574 #endif
577 #ifdef XP_WIN
578 void GeckoChildProcessHost::InitWindowsGroupID() {
579 // On Win7+, pass the application user model to the child, so it can
580 // register with it. This insures windows created by the container
581 // properly group with the parent app on the Win7 taskbar.
582 nsCOMPtr<nsIWinTaskbar> taskbarInfo = do_GetService(NS_TASKBAR_CONTRACTID);
583 if (taskbarInfo) {
584 bool isSupported = false;
585 taskbarInfo->GetAvailable(&isSupported);
586 nsAutoString appId;
587 if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
588 MOZ_ASSERT(mGroupId.EqualsLiteral("-"));
589 mGroupId.Assign(appId);
593 #endif
595 bool GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts,
596 int aTimeoutMs) {
597 if (!AsyncLaunch(std::move(aExtraOpts))) {
598 return false;
600 return WaitUntilConnected(aTimeoutMs);
603 // Note: for most process types, we currently call AsyncLaunch, and therefore
604 // the *ProcessLauncher constructor, on the main thread, while the
605 // ProcessLauncher methods to actually execute the launch are called on the IO
606 // or IPC launcher thread. GMP processes are an exception - the GMP code
607 // invokes GeckoChildProcessHost from non-main-threads, and therefore we cannot
608 // rely on having access to mainthread-only services (like the directory
609 // service) from this code if we're launching that type of process.
610 bool GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts) {
611 PrepareLaunch();
613 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
614 if (IsMacSandboxLaunchEnabled() && !AppendMacSandboxParams(aExtraOpts)) {
615 return false;
617 #endif
619 RefPtr<BaseProcessLauncher> launcher =
620 new ProcessLauncher(this, std::move(aExtraOpts));
622 // Note: Destroy() waits on mHandlePromise to delete |this|. As such, we want
623 // to be sure that all of our post-launch processing on |this| happens before
624 // mHandlePromise notifies.
625 MOZ_ASSERT(mHandlePromise == nullptr);
626 RefPtr<ProcessHandlePromise::Private> p =
627 new ProcessHandlePromise::Private(__func__);
628 mHandlePromise = p;
630 mozilla::InvokeAsync<GeckoChildProcessHost*>(
631 IOThread(), launcher.get(), __func__, &BaseProcessLauncher::Launch, this)
632 ->Then(
633 IOThread(), __func__,
634 [this, p](const LaunchResults aResults) {
636 if (!OpenPrivilegedHandle(base::GetProcId(aResults.mHandle))
637 #ifdef XP_WIN
638 // If we failed in opening the process handle, try harder by
639 // duplicating one.
640 && !::DuplicateHandle(::GetCurrentProcess(), aResults.mHandle,
641 ::GetCurrentProcess(),
642 &mChildProcessHandle,
643 PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
644 PROCESS_QUERY_INFORMATION |
645 PROCESS_VM_READ | SYNCHRONIZE,
646 FALSE, 0)
647 #endif // XP_WIN
649 MOZ_CRASH("cannot open handle to child process");
652 #ifdef XP_MACOSX
653 this->mChildTask = aResults.mChildTask;
654 #endif
655 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
656 this->mSandboxBroker = aResults.mSandboxBroker;
657 #endif
659 MonitorAutoLock lock(mMonitor);
660 // The OnChannel{Connected,Error} may have already advanced the
661 // state.
662 if (mProcessState < PROCESS_CREATED) {
663 mProcessState = PROCESS_CREATED;
665 lock.Notify();
667 p->Resolve(aResults.mHandle, __func__);
669 [this, p](const LaunchError aError) {
670 // WaitUntilConnected might be waiting for us to signal.
671 // If something failed let's set the error state and notify.
672 CHROMIUM_LOG(ERROR)
673 << "Failed to launch "
674 << XRE_ChildProcessTypeToString(mProcessType) << " subprocess";
675 Telemetry::Accumulate(
676 Telemetry::SUBPROCESS_LAUNCH_FAILURE,
677 nsDependentCString(XRE_ChildProcessTypeToString(mProcessType)));
679 MonitorAutoLock lock(mMonitor);
680 mProcessState = PROCESS_ERROR;
681 lock.Notify();
683 p->Reject(aError, __func__);
685 return true;
688 bool GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs) {
689 AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER);
691 // NB: this uses a different mechanism than the chromium parent
692 // class.
693 TimeDuration timeout = (aTimeoutMs > 0)
694 ? TimeDuration::FromMilliseconds(aTimeoutMs)
695 : TimeDuration::Forever();
697 MonitorAutoLock lock(mMonitor);
698 TimeStamp waitStart = TimeStamp::Now();
699 TimeStamp current;
701 // We'll receive several notifications, we need to exit when we
702 // have either successfully launched or have timed out.
703 while (mProcessState != PROCESS_CONNECTED) {
704 // If there was an error then return it, don't wait out the timeout.
705 if (mProcessState == PROCESS_ERROR) {
706 break;
709 CVStatus status = lock.Wait(timeout);
710 if (status == CVStatus::Timeout) {
711 break;
714 if (timeout != TimeDuration::Forever()) {
715 current = TimeStamp::Now();
716 timeout -= current - waitStart;
717 waitStart = current;
721 return mProcessState == PROCESS_CONNECTED;
724 bool GeckoChildProcessHost::LaunchAndWaitForProcessHandle(
725 StringVector aExtraOpts) {
726 if (!AsyncLaunch(std::move(aExtraOpts))) {
727 return false;
730 MonitorAutoLock lock(mMonitor);
731 while (mProcessState < PROCESS_CREATED) {
732 lock.Wait();
734 MOZ_ASSERT(mProcessState == PROCESS_ERROR || mChildProcessHandle);
736 return mProcessState < PROCESS_ERROR;
739 void GeckoChildProcessHost::InitializeChannel() {
740 CreateChannel();
742 MonitorAutoLock lock(mMonitor);
743 mProcessState = CHANNEL_INITIALIZED;
744 lock.Notify();
747 void GeckoChildProcessHost::Join() {
748 AssertIOThread();
750 if (!mChildProcessHandle) {
751 return;
754 // If this fails, there's nothing we can do.
755 base::KillProcess(mChildProcessHandle, 0, /*wait*/ true);
756 SetAlreadyDead();
759 void GeckoChildProcessHost::SetAlreadyDead() {
760 if (mChildProcessHandle && mChildProcessHandle != kInvalidProcessHandle) {
761 base::CloseProcessHandle(mChildProcessHandle);
764 mChildProcessHandle = 0;
767 void BaseProcessLauncher::GetChildLogName(const char* origLogName,
768 nsACString& buffer) {
769 #ifdef XP_WIN
770 // On Windows we must expand relative paths because sandboxing rules
771 // bound only to full paths. fopen fowards to NtCreateFile which checks
772 // the path against the sanboxing rules as passed to fopen (left relative).
773 char absPath[MAX_PATH + 2];
774 if (_fullpath(absPath, origLogName, sizeof(absPath))) {
775 # ifdef MOZ_SANDBOX
776 // We need to make sure the child log name doesn't contain any junction
777 // points or symlinks or the sandbox will reject rules to allow writing.
778 std::wstring resolvedPath(NS_ConvertUTF8toUTF16(absPath).get());
779 if (widget::WinUtils::ResolveJunctionPointsAndSymLinks(resolvedPath)) {
780 AppendUTF16toUTF8(
781 MakeSpan(reinterpret_cast<const char16_t*>(resolvedPath.data()),
782 resolvedPath.size()),
783 buffer);
784 } else
785 # endif
787 buffer.Append(absPath);
789 } else
790 #endif
792 buffer.Append(origLogName);
795 // Remove .moz_log extension to avoid its duplication, it will be added
796 // automatically by the logging backend
797 static NS_NAMED_LITERAL_CSTRING(kMozLogExt, MOZ_LOG_FILE_EXTENSION);
798 if (StringEndsWith(buffer, kMozLogExt)) {
799 buffer.Truncate(buffer.Length() - kMozLogExt.Length());
802 // Append child-specific postfix to name
803 buffer.AppendLiteral(".child-");
804 buffer.AppendInt(gChildCounter);
807 // Windows needs a single dedicated thread for process launching,
808 // because of thread-safety restrictions/assertions in the sandbox
809 // code.
811 // Android also needs a single dedicated thread to simplify thread
812 // safety in java.
813 #if defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID)
815 static mozilla::StaticMutex gIPCLaunchThreadMutex;
816 static mozilla::StaticRefPtr<nsIThread> gIPCLaunchThread;
818 class IPCLaunchThreadObserver final : public nsIObserver {
819 public:
820 NS_DECL_ISUPPORTS
821 NS_DECL_NSIOBSERVER
822 protected:
823 virtual ~IPCLaunchThreadObserver() = default;
826 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver, nsIObserver, nsISupports)
828 NS_IMETHODIMP
829 IPCLaunchThreadObserver::Observe(nsISupports* aSubject, const char* aTopic,
830 const char16_t* aData) {
831 MOZ_RELEASE_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0);
832 StaticMutexAutoLock lock(gIPCLaunchThreadMutex);
834 nsresult rv = NS_OK;
835 if (gIPCLaunchThread) {
836 rv = gIPCLaunchThread->Shutdown();
837 gIPCLaunchThread = nullptr;
839 mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
840 return rv;
843 nsCOMPtr<nsIEventTarget> BaseProcessLauncher::GetIPCLauncher() {
844 StaticMutexAutoLock lock(gIPCLaunchThreadMutex);
845 if (!gIPCLaunchThread) {
846 nsCOMPtr<nsIThread> thread;
847 nsresult rv = NS_NewNamedThread(NS_LITERAL_CSTRING("IPC Launch"),
848 getter_AddRefs(thread));
849 if (!NS_WARN_IF(NS_FAILED(rv))) {
850 NS_DispatchToMainThread(
851 NS_NewRunnableFunction("GeckoChildProcessHost::GetIPCLauncher", [] {
852 nsCOMPtr<nsIObserverService> obsService =
853 mozilla::services::GetObserverService();
854 nsCOMPtr<nsIObserver> obs = new IPCLaunchThreadObserver();
855 obsService->AddObserver(obs, "xpcom-shutdown-threads", false);
856 }));
857 gIPCLaunchThread = thread.forget();
861 nsCOMPtr<nsIEventTarget> thread = gIPCLaunchThread.get();
862 MOZ_DIAGNOSTIC_ASSERT(thread);
863 return thread;
866 #else // defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID)
868 // Other platforms use an on-demand thread pool.
870 nsCOMPtr<nsIEventTarget> BaseProcessLauncher::GetIPCLauncher() {
871 nsCOMPtr<nsIEventTarget> pool =
872 mozilla::SharedThreadPool::Get(NS_LITERAL_CSTRING("IPC Launch"));
873 MOZ_DIAGNOSTIC_ASSERT(pool);
874 return pool;
877 #endif // XP_WIN
879 void
880 #if defined(XP_WIN)
881 AddAppDirToCommandLine(CommandLine& aCmdLine, nsIFile* aAppDir)
882 #else
883 AddAppDirToCommandLine(std::vector<std::string>& aCmdLine, nsIFile* aAppDir,
884 nsIFile* aProfileDir)
885 #endif
887 // Content processes need access to application resources, so pass
888 // the full application directory path to the child process.
889 if (aAppDir) {
890 #if defined(XP_WIN)
891 nsString path;
892 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetPath(path));
893 aCmdLine.AppendLooseValue(UTF8ToWide("-appdir"));
894 std::wstring wpath(path.get());
895 aCmdLine.AppendLooseValue(wpath);
896 #else
897 nsAutoCString path;
898 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetNativePath(path));
899 aCmdLine.push_back("-appdir");
900 aCmdLine.push_back(path.get());
901 #endif
903 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
904 // Full path to the profile dir
905 if (aProfileDir) {
906 // If the profile doesn't exist, normalization will
907 // fail. But we don't return an error here because some
908 // tests require startup with a missing profile dir.
909 // For users, almost universally, the profile will be in
910 // the home directory and normalization isn't required.
911 mozilla::Unused << aProfileDir->Normalize();
912 nsAutoCString path;
913 MOZ_ALWAYS_SUCCEEDS(aProfileDir->GetNativePath(path));
914 aCmdLine.push_back("-profile");
915 aCmdLine.push_back(path.get());
917 #endif
921 #if defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
922 static bool Contains(const std::vector<std::string>& aExtraOpts,
923 const char* aValue) {
924 return std::any_of(aExtraOpts.begin(), aExtraOpts.end(),
925 [&](const std::string arg) {
926 return arg.find(aValue) != std::string::npos;
929 #endif // defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
931 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::PerformAsyncLaunch() {
932 if (!DoSetup()) {
933 return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
935 RefPtr<BaseProcessLauncher> self = this;
936 return DoLaunch()->Then(
937 mLaunchThread, __func__,
938 [self](base::ProcessHandle aHandle) {
939 self->mResults.mHandle = aHandle;
940 return self->FinishLaunch();
942 [](LaunchError aError) {
943 return ProcessLaunchPromise::CreateAndReject(aError, __func__);
947 bool BaseProcessLauncher::DoSetup() {
948 #ifdef MOZ_GECKO_PROFILER
949 RefPtr<BaseProcessLauncher> self = this;
950 GetProfilerEnvVarsForChildProcess([self](const char* key, const char* value) {
951 self->mLaunchOptions->env_map[ENVIRONMENT_STRING(key)] =
952 ENVIRONMENT_STRING(value);
954 #endif
956 MapChildLogging();
958 return PR_CreatePipe(&mCrashAnnotationReadPipe.rwget(),
959 &mCrashAnnotationWritePipe.rwget()) == PR_SUCCESS;
962 void BaseProcessLauncher::MapChildLogging() {
963 const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
964 const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
966 if (origNSPRLogName) {
967 nsAutoCString nsprLogName;
968 GetChildLogName(origNSPRLogName, nsprLogName);
969 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("NSPR_LOG_FILE")] =
970 ENVIRONMENT_STRING(nsprLogName.get());
972 if (origMozLogName) {
973 nsAutoCString mozLogName;
974 GetChildLogName(origMozLogName, mozLogName);
975 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MOZ_LOG_FILE")] =
976 ENVIRONMENT_STRING(mozLogName.get());
979 // `RUST_LOG_CHILD` is meant for logging child processes only.
980 nsAutoCString childRustLog(PR_GetEnv("RUST_LOG_CHILD"));
981 if (!childRustLog.IsEmpty()) {
982 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("RUST_LOG")] =
983 ENVIRONMENT_STRING(childRustLog.get());
987 #if defined(MOZ_WIDGET_GTK)
988 bool LinuxProcessLauncher::DoSetup() {
989 if (!PosixProcessLauncher::DoSetup()) {
990 return false;
993 if (mProcessType == GeckoProcessType_Content) {
994 // disable IM module to avoid sandbox violation
995 mLaunchOptions->env_map["GTK_IM_MODULE"] = "gtk-im-context-simple";
997 // Disable ATK accessibility code in content processes because it conflicts
998 // with the sandbox, and we proxy that information through the main process
999 // anyway.
1000 mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
1003 # ifdef MOZ_SANDBOX
1004 if (!mTmpDirName.IsEmpty()) {
1005 // Point a bunch of things that might want to write from content to our
1006 // shiny new content-process specific tmpdir
1007 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("TMPDIR")] =
1008 ENVIRONMENT_STRING(mTmpDirName.get());
1009 // Partial fix for bug 1380051 (not persistent - should be)
1010 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
1011 ENVIRONMENT_STRING(mTmpDirName.get());
1013 # endif // MOZ_SANDBOX
1015 return true;
1017 #endif // MOZ_WIDGET_GTK
1019 #ifdef OS_POSIX
1020 bool PosixProcessLauncher::DoSetup() {
1021 if (!BaseProcessLauncher::DoSetup()) {
1022 return false;
1025 // XPCOM may not be initialized in some subprocesses. We don't want
1026 // to initialize XPCOM just for the directory service, especially
1027 // since LD_LIBRARY_PATH is already set correctly in subprocesses
1028 // (meaning that we don't need to set that up in the environment).
1029 if (ShouldHaveDirectoryService()) {
1030 MOZ_ASSERT(gGREBinPath);
1031 nsCString path;
1032 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
1033 # if defined(OS_LINUX) || defined(OS_BSD)
1034 const char* ld_library_path = PR_GetEnv("LD_LIBRARY_PATH");
1035 nsCString new_ld_lib_path(path.get());
1037 # ifdef MOZ_WIDGET_GTK
1038 if (mProcessType == GeckoProcessType_Plugin) {
1039 new_ld_lib_path.AppendLiteral("/gtk2:");
1040 new_ld_lib_path.Append(path.get());
1042 # endif // MOZ_WIDGET_GTK
1043 if (ld_library_path && *ld_library_path) {
1044 new_ld_lib_path.Append(':');
1045 new_ld_lib_path.Append(ld_library_path);
1047 mLaunchOptions->env_map["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
1049 # elif OS_MACOSX // defined(OS_LINUX) || defined(OS_BSD)
1050 mLaunchOptions->env_map["DYLD_LIBRARY_PATH"] = path.get();
1051 // XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin
1052 // process, and has no effect on other subprocesses (the hooks in
1053 // libplugin_child_interpose.dylib become noops). But currently it
1054 // gets set when launching any kind of subprocess.
1056 // Trigger "dyld interposing" for the dylib that contains
1057 // plugin_child_interpose.mm. This allows us to hook OS calls in the
1058 // plugin process (ones that don't work correctly in a background
1059 // process). Don't break any other "dyld interposing" that has already
1060 // been set up by whatever may have launched the browser.
1061 const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
1062 nsCString interpose;
1063 if (prevInterpose && strlen(prevInterpose) > 0) {
1064 interpose.Assign(prevInterpose);
1065 interpose.Append(':');
1067 interpose.Append(path.get());
1068 interpose.AppendLiteral("/libplugin_child_interpose.dylib");
1069 mLaunchOptions->env_map["DYLD_INSERT_LIBRARIES"] = interpose.get();
1070 # endif // defined(OS_LINUX) || defined(OS_BSD)
1073 FilePath exePath;
1074 BinPathType pathType = GetPathToBinary(exePath, mProcessType);
1076 // remap the IPC socket fd to a well-known int, as the OS does for
1077 // STDOUT_FILENO, for example
1078 int srcChannelFd, dstChannelFd;
1079 mChannel->GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd);
1080 mLaunchOptions->fds_to_remap.push_back(
1081 std::pair<int, int>(srcChannelFd, dstChannelFd));
1083 // no need for kProcessChannelID, the child process inherits the
1084 // other end of the socketpair() from us
1086 mChildArgv.push_back(exePath.value());
1088 if (pathType == BinPathType::Self) {
1089 mChildArgv.push_back("-contentproc");
1092 mChildArgv.insert(mChildArgv.end(), mExtraOpts.begin(), mExtraOpts.end());
1094 if (mProcessType != GeckoProcessType_GMPlugin) {
1095 if (Omnijar::IsInitialized()) {
1096 // Make sure that child processes can find the omnijar
1097 // See XRE_InitCommandLine in nsAppRunner.cpp
1098 nsAutoCString path;
1099 nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
1100 if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
1101 mChildArgv.push_back("-greomni");
1102 mChildArgv.push_back(path.get());
1104 file = Omnijar::GetPath(Omnijar::APP);
1105 if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
1106 mChildArgv.push_back("-appomni");
1107 mChildArgv.push_back(path.get());
1110 // Add the application directory path (-appdir path)
1111 # ifdef XP_MACOSX
1112 AddAppDirToCommandLine(mChildArgv, mAppDir, mProfileDir);
1113 # else
1114 AddAppDirToCommandLine(mChildArgv, mAppDir, nullptr);
1115 # endif
1118 mChildArgv.push_back(mPidString);
1120 if (!CrashReporter::IsDummy()) {
1121 # if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
1122 int childCrashFd, childCrashRemapFd;
1123 if (!CrashReporter::CreateNotificationPipeForChild(&childCrashFd,
1124 &childCrashRemapFd)) {
1125 return false;
1128 if (0 <= childCrashFd) {
1129 mLaunchOptions->fds_to_remap.push_back(
1130 std::pair<int, int>(childCrashFd, childCrashRemapFd));
1131 // "true" == crash reporting enabled
1132 mChildArgv.push_back("true");
1133 } else {
1134 // "false" == crash reporting disabled
1135 mChildArgv.push_back("false");
1137 # elif defined(MOZ_WIDGET_COCOA) /* defined(OS_LINUX) || defined(OS_BSD) || \
1138 defined(OS_SOLARIS) */
1139 mChildArgv.push_back(CrashReporter::GetChildNotificationPipe());
1140 # endif // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
1143 int fd = PR_FileDesc2NativeHandle(mCrashAnnotationWritePipe);
1144 mLaunchOptions->fds_to_remap.push_back(
1145 std::make_pair(fd, CrashReporter::GetAnnotationTimeCrashFd()));
1147 # ifdef MOZ_WIDGET_COCOA
1148 mChildArgv.push_back(
1149 static_cast<MacProcessLauncher*>(this)->mMachConnectionName.c_str());
1150 # endif // MOZ_WIDGET_COCOA
1152 mChildArgv.push_back(ChildProcessType());
1154 return true;
1156 #endif // OS_POSIX
1158 #if defined(MOZ_WIDGET_ANDROID)
1159 RefPtr<ProcessHandlePromise> AndroidProcessLauncher::DoLaunch() {
1160 return LaunchAndroidService(ChildProcessType(), mChildArgv,
1161 mLaunchOptions->fds_to_remap);
1163 #endif // MOZ_WIDGET_ANDROID
1165 #ifdef OS_POSIX
1166 RefPtr<ProcessHandlePromise> PosixProcessLauncher::DoLaunch() {
1167 ProcessHandle handle = 0;
1168 if (!base::LaunchApp(mChildArgv, *mLaunchOptions, &handle)) {
1169 return ProcessHandlePromise::CreateAndReject(LaunchError{}, __func__);
1171 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1174 bool PosixProcessLauncher::DoFinishLaunch() {
1175 if (!BaseProcessLauncher::DoFinishLaunch()) {
1176 return false;
1179 // We're in the parent and the child was launched. Close the child FD in the
1180 // parent as soon as possible, which will allow the parent to detect when the
1181 // child closes its FD (either due to normal exit or due to crash).
1182 mChannel->CloseClientFileDescriptor();
1184 return true;
1186 #endif // OS_POSIX
1188 #ifdef XP_MACOSX
1189 bool MacProcessLauncher::DoFinishLaunch() {
1190 // Wait for the child process to send us its 'task_t' data.
1191 const int kTimeoutMs = 10000;
1193 MachReceiveMessage child_message;
1194 kern_return_t err =
1195 mParentRecvPort.WaitForMessage(&child_message, kTimeoutMs);
1196 if (err != KERN_SUCCESS) {
1197 std::string errString =
1198 StringPrintf("0x%x %s", err, mach_error_string(err));
1199 CHROMIUM_LOG(ERROR) << "parent WaitForMessage() failed: " << errString;
1200 return false;
1203 task_t child_task = child_message.GetTranslatedPort(0);
1204 if (child_task == MACH_PORT_NULL) {
1205 CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
1206 return false;
1209 if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
1210 CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(1) failed.";
1211 return false;
1213 MachPortSender parent_sender(child_message.GetTranslatedPort(1));
1215 if (child_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
1216 CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(2) failed.";
1218 auto* parent_recv_port_memory_ack =
1219 new MachPortSender(child_message.GetTranslatedPort(2));
1221 if (child_message.GetTranslatedPort(3) == MACH_PORT_NULL) {
1222 CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(3) failed.";
1224 auto* parent_send_port_memory =
1225 new MachPortSender(child_message.GetTranslatedPort(3));
1227 MachSendMessage parent_message(/* id= */ 0);
1228 if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) {
1229 CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port
1230 << ") failed.";
1231 return false;
1234 auto* parent_recv_port_memory = new ReceivePort();
1235 if (!parent_message.AddDescriptor(
1236 MachMsgPortDescriptor(parent_recv_port_memory->GetPort()))) {
1237 CHROMIUM_LOG(ERROR) << "parent AddDescriptor("
1238 << parent_recv_port_memory->GetPort() << ") failed.";
1239 return false;
1242 auto* parent_send_port_memory_ack = new ReceivePort();
1243 if (!parent_message.AddDescriptor(
1244 MachMsgPortDescriptor(parent_send_port_memory_ack->GetPort()))) {
1245 CHROMIUM_LOG(ERROR) << "parent AddDescriptor("
1246 << parent_send_port_memory_ack->GetPort()
1247 << ") failed.";
1248 return false;
1251 err = parent_sender.SendMessage(parent_message, kTimeoutMs);
1252 if (err != KERN_SUCCESS) {
1253 std::string errString =
1254 StringPrintf("0x%x %s", err, mach_error_string(err));
1255 CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString;
1256 return false;
1259 SharedMemoryBasic::SetupMachMemory(
1260 mResults.mHandle, parent_recv_port_memory, parent_recv_port_memory_ack,
1261 parent_send_port_memory, parent_send_port_memory_ack, false);
1263 // NB: on OS X, we block much longer than we need to in order to
1264 // reach this call, waiting for the child process's task_t. The
1265 // best way to fix that is to refactor this file, hard.
1266 mResults.mChildTask = child_task;
1268 return true;
1270 #endif // XP_MACOSX
1272 #ifdef XP_WIN
1273 bool WindowsProcessLauncher::DoSetup() {
1274 if (!BaseProcessLauncher::DoSetup()) {
1275 return false;
1278 FilePath exePath;
1279 BinPathType pathType = GetPathToBinary(exePath, mProcessType);
1281 # if defined(MOZ_SANDBOX) || defined(_ARM64_)
1282 const bool isGMP = mProcessType == GeckoProcessType_GMPlugin;
1283 const bool isWidevine = isGMP && Contains(mExtraOpts, "gmp-widevinecdm");
1284 # if defined(_ARM64_)
1285 const bool isClearKey = isGMP && Contains(mExtraOpts, "gmp-clearkey");
1286 const bool isSandboxBroker =
1287 mProcessType == GeckoProcessType_RemoteSandboxBroker;
1288 if (isClearKey || isWidevine || isSandboxBroker) {
1289 // On Windows on ARM64 for ClearKey and Widevine, and for the sandbox
1290 // launcher process, we want to run the x86 plugin-container.exe in
1291 // the "i686" subdirectory, instead of the aarch64 plugin-container.exe.
1292 // So insert "i686" into the exePath.
1293 exePath = exePath.DirName().AppendASCII("i686").Append(exePath.BaseName());
1295 # endif // if defined(_ARM64_)
1296 # endif // defined(MOZ_SANDBOX) || defined(_ARM64_)
1298 mCmdLine.emplace(exePath.ToWStringHack());
1300 if (pathType == BinPathType::Self) {
1301 mCmdLine->AppendLooseValue(UTF8ToWide("-contentproc"));
1304 mCmdLine->AppendSwitchWithValue(switches::kProcessChannelID, mChannelId);
1306 for (std::vector<std::string>::iterator it = mExtraOpts.begin();
1307 it != mExtraOpts.end(); ++it) {
1308 mCmdLine->AppendLooseValue(UTF8ToWide(*it));
1311 if (Omnijar::IsInitialized()) {
1312 // Make sure the child process can find the omnijar
1313 // See XRE_InitCommandLine in nsAppRunner.cpp
1314 nsAutoString path;
1315 nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
1316 if (file && NS_SUCCEEDED(file->GetPath(path))) {
1317 mCmdLine->AppendLooseValue(UTF8ToWide("-greomni"));
1318 mCmdLine->AppendLooseValue(path.get());
1320 file = Omnijar::GetPath(Omnijar::APP);
1321 if (file && NS_SUCCEEDED(file->GetPath(path))) {
1322 mCmdLine->AppendLooseValue(UTF8ToWide("-appomni"));
1323 mCmdLine->AppendLooseValue(path.get());
1327 # if defined(MOZ_SANDBOX)
1328 # if defined(_ARM64_)
1329 if (isClearKey || isWidevine)
1330 mResults.mSandboxBroker = new RemoteSandboxBroker();
1331 else
1332 # endif // if defined(_ARM64_)
1333 mResults.mSandboxBroker = new SandboxBroker();
1335 // XXX: Bug 1124167: We should get rid of the process specific logic for
1336 // sandboxing in this class at some point. Unfortunately it will take a bit
1337 // of reorganizing so I don't think this patch is the right time.
1338 switch (mProcessType) {
1339 case GeckoProcessType_Content:
1340 if (mSandboxLevel > 0) {
1341 // For now we treat every failure as fatal in
1342 // SetSecurityLevelForContentProcess and just crash there right away.
1343 // Should this change in the future then we should also handle the error
1344 // here.
1345 mResults.mSandboxBroker->SetSecurityLevelForContentProcess(
1346 mSandboxLevel, mIsFileContent);
1347 mUseSandbox = true;
1349 break;
1350 case GeckoProcessType_Plugin:
1351 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_NPAPI_SANDBOX")) {
1352 if (!mResults.mSandboxBroker->SetSecurityLevelForPluginProcess(
1353 mSandboxLevel)) {
1354 return false;
1356 mUseSandbox = true;
1358 break;
1359 case GeckoProcessType_IPDLUnitTest:
1360 // XXX: We don't sandbox this process type yet
1361 break;
1362 case GeckoProcessType_GMPlugin:
1363 if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
1364 // The Widevine CDM on Windows can only load at USER_RESTRICTED,
1365 // not at USER_LOCKDOWN. So look in the command line arguments
1366 // to see if we're loading the path to the Widevine CDM, and if
1367 // so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
1368 auto level =
1369 isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
1370 if (!mResults.mSandboxBroker->SetSecurityLevelForGMPlugin(level)) {
1371 return false;
1373 mUseSandbox = true;
1375 break;
1376 case GeckoProcessType_GPU:
1377 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) {
1378 // For now we treat every failure as fatal in
1379 // SetSecurityLevelForGPUProcess and just crash there right away. Should
1380 // this change in the future then we should also handle the error here.
1381 mResults.mSandboxBroker->SetSecurityLevelForGPUProcess(mSandboxLevel);
1382 mUseSandbox = true;
1384 break;
1385 case GeckoProcessType_VR:
1386 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
1387 // TODO: Implement sandbox for VR process, Bug 1430043.
1389 break;
1390 case GeckoProcessType_RDD:
1391 if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
1392 if (!mResults.mSandboxBroker->SetSecurityLevelForRDDProcess()) {
1393 return false;
1395 mUseSandbox = true;
1397 break;
1398 case GeckoProcessType_Socket:
1399 // TODO - setup sandboxing for the socket process.
1400 break;
1401 case GeckoProcessType_RemoteSandboxBroker:
1402 // We don't sandbox the sandbox launcher...
1403 break;
1404 case GeckoProcessType_Default:
1405 default:
1406 MOZ_CRASH("Bad process type in GeckoChildProcessHost");
1407 break;
1410 if (mUseSandbox) {
1411 for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end();
1412 ++it) {
1413 mResults.mSandboxBroker->AllowReadFile(it->c_str());
1416 # endif // defined(MOZ_SANDBOX)
1418 // Add the application directory path (-appdir path)
1419 AddAppDirToCommandLine(mCmdLine.ref(), mAppDir);
1421 // XXX Command line params past this point are expected to be at
1422 // the end of the command line string, and in a specific order.
1423 // See XRE_InitChildProcess in nsEmbedFunction.
1425 // Win app model id
1426 mCmdLine->AppendLooseValue(mGroupId.get());
1428 // Process id
1429 mCmdLine->AppendLooseValue(UTF8ToWide(mPidString));
1431 mCmdLine->AppendLooseValue(
1432 UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
1434 if (!CrashReporter::IsDummy()) {
1435 PROsfd h = PR_FileDesc2NativeHandle(mCrashAnnotationWritePipe);
1436 mLaunchOptions->handles_to_inherit.push_back(reinterpret_cast<HANDLE>(h));
1437 std::string hStr = std::to_string(h);
1438 mCmdLine->AppendLooseValue(UTF8ToWide(hStr));
1441 // Process type
1442 mCmdLine->AppendLooseValue(UTF8ToWide(ChildProcessType()));
1444 # ifdef MOZ_SANDBOX
1445 if (mUseSandbox) {
1446 // Mark the handles to inherit as inheritable.
1447 for (HANDLE h : mLaunchOptions->handles_to_inherit) {
1448 mResults.mSandboxBroker->AddHandleToShare(h);
1451 # endif // MOZ_SANDBOX
1453 return true;
1456 RefPtr<ProcessHandlePromise> WindowsProcessLauncher::DoLaunch() {
1457 ProcessHandle handle = 0;
1458 # ifdef MOZ_SANDBOX
1459 if (mUseSandbox) {
1460 if (mResults.mSandboxBroker->LaunchApp(
1461 mCmdLine->program().c_str(),
1462 mCmdLine->command_line_string().c_str(), mLaunchOptions->env_map,
1463 mProcessType, mEnableSandboxLogging, &handle)) {
1464 EnvironmentLog("MOZ_PROCESS_LOG")
1465 .print("==> process %d launched child process %d (%S)\n",
1466 base::GetCurrentProcId(), base::GetProcId(handle),
1467 mCmdLine->command_line_string().c_str());
1468 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1470 return ProcessHandlePromise::CreateAndReject(LaunchError{}, __func__);
1472 # endif // defined(MOZ_SANDBOX)
1474 if (!base::LaunchApp(mCmdLine.ref(), *mLaunchOptions, &handle)) {
1475 return ProcessHandlePromise::CreateAndReject(LaunchError{}, __func__);
1477 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1480 bool WindowsProcessLauncher::DoFinishLaunch() {
1481 if (!BaseProcessLauncher::DoFinishLaunch()) {
1482 return false;
1485 # ifdef MOZ_SANDBOX
1486 // We need to be able to duplicate handles to some types of non-sandboxed
1487 // child processes.
1488 switch (mProcessType) {
1489 case GeckoProcessType_Default:
1490 MOZ_CRASH("shouldn't be launching a parent process");
1491 case GeckoProcessType_Plugin:
1492 case GeckoProcessType_IPDLUnitTest:
1493 // No handle duplication necessary.
1494 break;
1495 default:
1496 if (!SandboxBroker::AddTargetPeer(mResults.mHandle)) {
1497 NS_WARNING("Failed to add child process as target peer.");
1499 break;
1501 # endif // MOZ_SANDBOX
1503 return true;
1505 #endif // XP_WIN
1507 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::FinishLaunch() {
1508 if (!DoFinishLaunch()) {
1509 return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
1512 MOZ_DIAGNOSTIC_ASSERT(mResults.mHandle);
1514 CrashReporter::RegisterChildCrashAnnotationFileDescriptor(
1515 base::GetProcId(mResults.mHandle), mCrashAnnotationReadPipe.forget());
1517 Telemetry::AccumulateTimeDelta(Telemetry::CHILD_PROCESS_LAUNCH_MS,
1518 mStartTimeStamp);
1520 return ProcessLaunchPromise::CreateAndResolve(mResults, __func__);
1523 bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid) {
1524 if (mChildProcessHandle) {
1525 MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
1526 return true;
1529 return base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle);
1532 void GeckoChildProcessHost::OnChannelConnected(int32_t peer_pid) {
1533 if (!OpenPrivilegedHandle(peer_pid)) {
1534 MOZ_CRASH("can't open handle to child process");
1536 MonitorAutoLock lock(mMonitor);
1537 mProcessState = PROCESS_CONNECTED;
1538 lock.Notify();
1541 void GeckoChildProcessHost::OnMessageReceived(IPC::Message&& aMsg) {
1542 // We never process messages ourself, just save them up for the next
1543 // listener.
1544 mQueue.push(std::move(aMsg));
1547 void GeckoChildProcessHost::OnChannelError() {
1548 // Update the process state to an error state if we have a channel
1549 // error before we're connected. This fixes certain failures,
1550 // but does not address the full range of possible issues described
1551 // in the FIXME comment below.
1552 MonitorAutoLock lock(mMonitor);
1553 if (mProcessState < PROCESS_CONNECTED) {
1554 mProcessState = PROCESS_ERROR;
1555 lock.Notify();
1557 // FIXME/bug 773925: save up this error for the next listener.
1560 RefPtr<ProcessHandlePromise> GeckoChildProcessHost::WhenProcessHandleReady() {
1561 MOZ_ASSERT(mHandlePromise != nullptr);
1562 return mHandlePromise;
1565 void GeckoChildProcessHost::GetQueuedMessages(std::queue<IPC::Message>& queue) {
1566 // If this is called off the IO thread, bad things will happen.
1567 DCHECK(MessageLoopForIO::current());
1568 swap(queue, mQueue);
1569 // We expect the next listener to take over processing of our queue.
1572 #ifdef MOZ_WIDGET_ANDROID
1573 RefPtr<ProcessHandlePromise> AndroidProcessLauncher::LaunchAndroidService(
1574 const char* type, const std::vector<std::string>& argv,
1575 const base::file_handle_mapping_vector& fds_to_remap) {
1576 MOZ_RELEASE_ASSERT((2 <= fds_to_remap.size()) && (fds_to_remap.size() <= 5));
1577 JNIEnv* const env = mozilla::jni::GetEnvForThread();
1578 MOZ_ASSERT(env);
1580 const int argvSize = argv.size();
1581 jni::ObjectArray::LocalRef jargs =
1582 jni::ObjectArray::New<jni::String>(argvSize);
1583 for (int ix = 0; ix < argvSize; ix++) {
1584 jargs->SetElement(ix, jni::StringParam(argv[ix].c_str(), env));
1587 // XXX: this processing depends entirely on the internals of
1588 // ContentParent::LaunchSubprocess()
1589 // GeckoChildProcessHost::PerformAsyncLaunch(), and the order in
1590 // which they append to fds_to_remap. There must be a better way to do it.
1591 // See bug 1440207.
1592 int32_t prefsFd = fds_to_remap[0].first;
1593 int32_t prefMapFd = fds_to_remap[1].first;
1594 int32_t ipcFd = fds_to_remap[2].first;
1595 int32_t crashFd = -1;
1596 int32_t crashAnnotationFd = -1;
1597 if (fds_to_remap.size() == 4) {
1598 crashAnnotationFd = fds_to_remap[3].first;
1600 if (fds_to_remap.size() == 5) {
1601 crashFd = fds_to_remap[3].first;
1602 crashAnnotationFd = fds_to_remap[4].first;
1605 auto genericResult = java::GeckoProcessManager::Start(
1606 type, jargs, prefsFd, prefMapFd, ipcFd, crashFd, crashAnnotationFd);
1607 auto typedResult = java::GeckoResult::LocalRef(std::move(genericResult));
1608 return ProcessHandlePromise::FromGeckoResult(typedResult);
1610 #endif
1612 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1613 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector& aArgs) {
1614 MacSandboxInfo info;
1615 if (!FillMacSandboxInfo(info)) {
1616 return false;
1618 info.AppendAsParams(aArgs);
1619 return true;
1622 // Fill |aInfo| with the flags needed to launch the utility sandbox
1623 /* static */
1624 bool GeckoChildProcessHost::StaticFillMacSandboxInfo(MacSandboxInfo& aInfo) {
1625 aInfo.type = GetDefaultMacSandboxType();
1626 aInfo.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled") ||
1627 PR_GetEnv("MOZ_SANDBOX_LOGGING");
1629 nsAutoCString appPath;
1630 if (!nsMacUtilsImpl::GetAppPath(appPath)) {
1631 MOZ_CRASH("Failed to get app path");
1633 aInfo.appPath.assign(appPath.get());
1634 return true;
1637 bool GeckoChildProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
1638 return GeckoChildProcessHost::StaticFillMacSandboxInfo(aInfo);
1642 // If early sandbox startup is enabled for this process type, map the
1643 // process type to the sandbox type and enable the sandbox. Returns true
1644 // if no errors were encountered or if early sandbox startup is not
1645 // enabled for this process. Returns false if an error was encountered.
1647 /* static */
1648 bool GeckoChildProcessHost::StartMacSandbox(int aArgc, char** aArgv,
1649 std::string& aErrorMessage) {
1650 MacSandboxType sandboxType = MacSandboxType_Invalid;
1651 switch (XRE_GetProcessType()) {
1652 // For now, only support early sandbox startup for content,
1653 // RDD, and GMP processes. Add case statements for the additional
1654 // process types once early sandbox startup is implemented for them.
1655 case GeckoProcessType_Content:
1656 // Content processes don't use GeckoChildProcessHost
1657 // to configure sandboxing so hard code the sandbox type.
1658 sandboxType = MacSandboxType_Content;
1659 break;
1660 case GeckoProcessType_RDD:
1661 sandboxType = RDDProcessHost::GetMacSandboxType();
1662 break;
1663 case GeckoProcessType_GMPlugin:
1664 sandboxType = gmp::GMPProcessParent::GetMacSandboxType();
1665 break;
1666 default:
1667 return true;
1669 return mozilla::StartMacSandboxIfEnabled(sandboxType, aArgc, aArgv,
1670 aErrorMessage);
1673 #endif /* XP_MACOSX && MOZ_SANDBOX */
1675 /* static */
1676 void GeckoChildProcessHost::GetAll(const GeckoProcessCallback& aCallback) {
1677 StaticMutexAutoLock lock(sMutex);
1678 for (GeckoChildProcessHost* gp = sGeckoChildProcessHosts->getFirst(); gp;
1679 gp = static_cast<mozilla::LinkedListElement<GeckoChildProcessHost>*>(gp)
1680 ->getNext()) {
1681 aCallback(gp);
1685 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::Launch(
1686 GeckoChildProcessHost* aHost) {
1687 AssertIOThread();
1689 // Initializing the channel needs to happen on the I/O thread, but everything
1690 // else can run on the launcher thread (or pool), to avoid blocking IPC
1691 // messages.
1693 // We avoid passing the host to the launcher thread to reduce the chances of
1694 // data races with the IO thread (where e.g. OnChannelConnected may run
1695 // concurrently). The pool currently needs access to the channel, which is not
1696 // great.
1698 // It's also unfortunate that we need to work with raw pointers to both the
1699 // host and the channel. The assumption here is that the host (and therefore
1700 // the channel) are never torn down until the return promise is resolved or
1701 // rejected.
1702 aHost->InitializeChannel();
1703 mChannel = aHost->GetChannel();
1704 if (!mChannel) {
1705 return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
1707 mChannelId = aHost->GetChannelId();
1709 return InvokeAsync(mLaunchThread, this, __func__,
1710 &BaseProcessLauncher::PerformAsyncLaunch);
1713 } // namespace ipc
1714 } // namespace mozilla