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"
21 #include "MainThreadUtils.h"
22 #include "mozilla/Sprintf.h"
24 #include "nsXPCOMPrivate.h"
26 #if defined(MOZ_SANDBOX)
27 # include "mozilla/SandboxSettings.h"
28 # include "nsAppDirectoryServiceDefs.h"
31 #include "nsExceptionHandler.h"
33 #include "nsDirectoryService.h"
34 #include "nsDirectoryServiceDefs.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"
57 # include "nsIWinTaskbar.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"
66 # include "mozilla/remoteSandboxBroker.h"
71 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
72 # include "mozilla/SandboxLaunch.h"
75 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
76 # include "GMPProcessParent.h"
77 # include "nsMacUtilsImpl.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
;
92 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc
, PRFileDesc
,
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"
105 static bool ShouldHaveDirectoryService() {
106 return GeckoProcessType_Default
== XRE_GetProcessType();
112 static Atomic
<int32_t> gChildCounter
;
114 static inline nsISerialEventTarget
* IOThread() {
115 return XRE_GetIOMessageLoop()->SerialEventTarget();
118 class BaseProcessLauncher
{
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
)),
126 mGroupId(aHost
->mGroupId
),
128 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
129 mAllowedFilesRead(aHost
->mAllowedFilesRead
),
130 mSandboxLevel(aHost
->mSandboxLevel
),
131 mIsFileContent(aHost
->mIsFileContent
),
132 mEnableSandboxLogging(aHost
->mEnableSandboxLogging
),
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();
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.
151 << nsDirectoryService::gService
->GetCurrentProcessDirectory(
152 getter_AddRefs(mAppDir
));
156 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseProcessLauncher
);
158 RefPtr
<ProcessLaunchPromise
> Launch(GeckoChildProcessHost
*);
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
;
191 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
192 std::vector
<std::wstring
> mAllowedFilesRead
;
193 int32_t mSandboxLevel
;
195 bool mEnableSandboxLogging
;
197 nsCString mTmpDirName
;
198 LaunchResults mResults
= LaunchResults();
200 TimeStamp mStartTimeStamp
= TimeStamp::Now();
203 // Set during launch.
204 IPC::Channel
* mChannel
= nullptr;
205 std::wstring mChannelId
;
206 ScopedPRFileDesc mCrashAnnotationReadPipe
;
207 ScopedPRFileDesc mCrashAnnotationWritePipe
;
208 nsCOMPtr
<nsIFile
> mAppDir
;
212 class WindowsProcessLauncher
: public BaseProcessLauncher
{
214 WindowsProcessLauncher(GeckoChildProcessHost
* aHost
,
215 std::vector
<std::string
>&& aExtraOpts
)
216 : BaseProcessLauncher(aHost
, std::move(aExtraOpts
)) {}
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
;
230 class PosixProcessLauncher
: public BaseProcessLauncher
{
232 PosixProcessLauncher(GeckoChildProcessHost
* aHost
,
233 std::vector
<std::string
>&& aExtraOpts
)
234 : BaseProcessLauncher(aHost
, std::move(aExtraOpts
)),
235 mProfileDir(aHost
->mProfileDir
) {}
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
{
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.
257 StringPrintf("org.mozilla.machname.%d",
258 base::RandInt(0, std::numeric_limits
<int>::max()))),
259 mParentRecvPort(mMachConnectionName
.c_str()) {}
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
{
275 AndroidProcessLauncher(GeckoChildProcessHost
* aHost
,
276 std::vector
<std::string
>&& aExtraOpts
)
277 : PosixProcessLauncher(aHost
, std::move(aExtraOpts
)) {}
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
{
293 LinuxProcessLauncher(GeckoChildProcessHost
* aHost
,
294 std::vector
<std::string
>&& aExtraOpts
)
295 : PosixProcessLauncher(aHost
, std::move(aExtraOpts
)) {}
298 virtual bool DoSetup() override
;
300 typedef LinuxProcessLauncher ProcessLauncher
;
302 # error "Unknown platform"
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
,
317 : mProcessType(aProcessType
),
318 mIsFileContent(aIsFileContent
),
319 mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
320 mLaunchOptions(MakeUnique
<base::LaunchOptions
>()),
321 mProcessState(CREATING_CHANNEL
),
325 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
326 mEnableSandboxLogging(false),
329 mChildProcessHandle(0),
330 #if defined(MOZ_WIDGET_COCOA)
331 mChildTask(MACH_PORT_NULL
),
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
);
353 GeckoChildProcessHost::~GeckoChildProcessHost()
357 MOZ_RELEASE_ASSERT(mDestroying
);
359 MOZ_COUNT_DTOR(GeckoChildProcessHost
);
361 if (mChildProcessHandle
!= 0) {
362 #if defined(MOZ_WIDGET_COCOA)
363 SharedMemoryBasic::CleanupForPid(mChildProcessHandle
);
365 ProcessWatcher::EnsureProcessTerminated(
367 #ifdef NS_FREE_PERMANENT_DATA
368 // If we're doing leak logging, shutdown can be slow.
370 false // don't "force"
375 #if defined(MOZ_WIDGET_COCOA)
376 if (mChildTask
!= MACH_PORT_NULL
)
377 mach_port_deallocate(mach_task_self(), mChildTask
);
380 if (mChildProcessHandle
!= 0) {
382 CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
383 base::GetProcId(mChildProcessHandle
));
385 CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
386 mChildProcessHandle
);
389 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
390 if (mSandboxBroker
) {
391 mSandboxBroker
->Shutdown();
392 mSandboxBroker
= nullptr;
397 void GeckoChildProcessHost::RemoveFromProcessList() {
398 StaticMutexAutoLock
lock(sMutex
);
399 if (!sGeckoChildProcessHosts
) {
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
;
413 // AsyncLaunch not called yet, so dispatch immediately.
414 whenReady
= ProcessHandlePromise::CreateAndReject(LaunchError
{}, __func__
);
417 using Value
= ProcessHandlePromise::ResolveOrRejectValue
;
419 whenReady
->Then(XRE_GetIOMessageLoop()->SerialEventTarget(), __func__
,
420 [this](const Value
&) { delete this; });
424 mozilla::BinPathType
BaseProcessLauncher::GetPathToBinary(
425 FilePath
& exePath
, GeckoProcessType processType
) {
426 BinPathType pathType
= XRE_GetChildProcBinPathType(processType
);
428 if (pathType
== BinPathType::Self
) {
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
);
444 exePath
= FilePath::FromWStringHack(exePathBuf
);
446 #elif defined(OS_POSIX)
447 exePath
= FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
449 # error Sorry; target OS not supported yet.
454 if (ShouldHaveDirectoryService()) {
455 MOZ_ASSERT(gGREBinPath
);
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"));
469 childProcPath
->GetNativePath(tempCPath
);
470 exePath
= FilePath(tempCPath
.get());
473 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath
), path
);
474 exePath
= FilePath(path
.get());
478 if (exePath
.empty()) {
481 FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
483 exePath
= FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
485 exePath
= exePath
.DirName();
488 exePath
= exePath
.AppendASCII(MOZ_CHILD_PROCESS_NAME
);
493 #ifdef MOZ_WIDGET_COCOA
494 class AutoCFTypeObject
{
496 explicit AutoCFTypeObject(CFTypeRef object
) { mObject
= object
; }
497 ~AutoCFTypeObject() { ::CFRelease(mObject
); }
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;
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());
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.");
551 resolvedPath
.append(L
"\\*");
553 mAllowedFilesRead
.push_back(resolvedPath
);
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");
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
));
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
);
584 bool isSupported
= false;
585 taskbarInfo
->GetAvailable(&isSupported
);
587 if (isSupported
&& NS_SUCCEEDED(taskbarInfo
->GetDefaultGroupId(appId
))) {
588 MOZ_ASSERT(mGroupId
.EqualsLiteral("-"));
589 mGroupId
.Assign(appId
);
595 bool GeckoChildProcessHost::SyncLaunch(std::vector
<std::string
> aExtraOpts
,
597 if (!AsyncLaunch(std::move(aExtraOpts
))) {
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
) {
613 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
614 if (IsMacSandboxLaunchEnabled() && !AppendMacSandboxParams(aExtraOpts
)) {
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__
);
630 mozilla::InvokeAsync
<GeckoChildProcessHost
*>(
631 IOThread(), launcher
.get(), __func__
, &BaseProcessLauncher::Launch
, this)
633 IOThread(), __func__
,
634 [this, p
](const LaunchResults aResults
) {
636 if (!OpenPrivilegedHandle(base::GetProcId(aResults
.mHandle
))
638 // If we failed in opening the process handle, try harder by
640 && !::DuplicateHandle(::GetCurrentProcess(), aResults
.mHandle
,
641 ::GetCurrentProcess(),
642 &mChildProcessHandle
,
643 PROCESS_DUP_HANDLE
| PROCESS_TERMINATE
|
644 PROCESS_QUERY_INFORMATION
|
645 PROCESS_VM_READ
| SYNCHRONIZE
,
649 MOZ_CRASH("cannot open handle to child process");
653 this->mChildTask
= aResults
.mChildTask
;
655 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
656 this->mSandboxBroker
= aResults
.mSandboxBroker
;
659 MonitorAutoLock
lock(mMonitor
);
660 // The OnChannel{Connected,Error} may have already advanced the
662 if (mProcessState
< PROCESS_CREATED
) {
663 mProcessState
= PROCESS_CREATED
;
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.
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
;
683 p
->Reject(aError
, __func__
);
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
693 TimeDuration timeout
= (aTimeoutMs
> 0)
694 ? TimeDuration::FromMilliseconds(aTimeoutMs
)
695 : TimeDuration::Forever();
697 MonitorAutoLock
lock(mMonitor
);
698 TimeStamp waitStart
= TimeStamp::Now();
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
) {
709 CVStatus status
= lock
.Wait(timeout
);
710 if (status
== CVStatus::Timeout
) {
714 if (timeout
!= TimeDuration::Forever()) {
715 current
= TimeStamp::Now();
716 timeout
-= current
- waitStart
;
721 return mProcessState
== PROCESS_CONNECTED
;
724 bool GeckoChildProcessHost::LaunchAndWaitForProcessHandle(
725 StringVector aExtraOpts
) {
726 if (!AsyncLaunch(std::move(aExtraOpts
))) {
730 MonitorAutoLock
lock(mMonitor
);
731 while (mProcessState
< PROCESS_CREATED
) {
734 MOZ_ASSERT(mProcessState
== PROCESS_ERROR
|| mChildProcessHandle
);
736 return mProcessState
< PROCESS_ERROR
;
739 void GeckoChildProcessHost::InitializeChannel() {
742 MonitorAutoLock
lock(mMonitor
);
743 mProcessState
= CHANNEL_INITIALIZED
;
747 void GeckoChildProcessHost::Join() {
750 if (!mChildProcessHandle
) {
754 // If this fails, there's nothing we can do.
755 base::KillProcess(mChildProcessHandle
, 0, /*wait*/ true);
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
) {
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
))) {
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
)) {
781 MakeSpan(reinterpret_cast<const char16_t
*>(resolvedPath
.data()),
782 resolvedPath
.size()),
787 buffer
.Append(absPath
);
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
811 // Android also needs a single dedicated thread to simplify thread
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
{
823 virtual ~IPCLaunchThreadObserver() = default;
826 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver
, nsIObserver
, nsISupports
)
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
);
835 if (gIPCLaunchThread
) {
836 rv
= gIPCLaunchThread
->Shutdown();
837 gIPCLaunchThread
= nullptr;
839 mozilla::Unused
<< NS_WARN_IF(NS_FAILED(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);
857 gIPCLaunchThread
= thread
.forget();
861 nsCOMPtr
<nsIEventTarget
> thread
= gIPCLaunchThread
.get();
862 MOZ_DIAGNOSTIC_ASSERT(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
);
881 AddAppDirToCommandLine(CommandLine
& aCmdLine
, nsIFile
* aAppDir
)
883 AddAppDirToCommandLine(std::vector
<std::string
>& aCmdLine
, nsIFile
* aAppDir
,
884 nsIFile
* aProfileDir
)
887 // Content processes need access to application resources, so pass
888 // the full application directory path to the child process.
892 MOZ_ALWAYS_SUCCEEDS(aAppDir
->GetPath(path
));
893 aCmdLine
.AppendLooseValue(UTF8ToWide("-appdir"));
894 std::wstring
wpath(path
.get());
895 aCmdLine
.AppendLooseValue(wpath
);
898 MOZ_ALWAYS_SUCCEEDS(aAppDir
->GetNativePath(path
));
899 aCmdLine
.push_back("-appdir");
900 aCmdLine
.push_back(path
.get());
903 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
904 // Full path to the profile dir
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();
913 MOZ_ALWAYS_SUCCEEDS(aProfileDir
->GetNativePath(path
));
914 aCmdLine
.push_back("-profile");
915 aCmdLine
.push_back(path
.get());
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() {
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
);
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()) {
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
1000 mLaunchOptions
->env_map
["NO_AT_BRIDGE"] = "1";
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
1017 #endif // MOZ_WIDGET_GTK
1020 bool PosixProcessLauncher::DoSetup() {
1021 if (!BaseProcessLauncher::DoSetup()) {
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
);
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)
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
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)
1112 AddAppDirToCommandLine(mChildArgv
, mAppDir
, mProfileDir
);
1114 AddAppDirToCommandLine(mChildArgv
, mAppDir
, nullptr);
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
)) {
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");
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());
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
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()) {
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();
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
;
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
;
1203 task_t child_task
= child_message
.GetTranslatedPort(0);
1204 if (child_task
== MACH_PORT_NULL
) {
1205 CHROMIUM_LOG(ERROR
) << "parent GetTranslatedPort(0) failed.";
1209 if (child_message
.GetTranslatedPort(1) == MACH_PORT_NULL
) {
1210 CHROMIUM_LOG(ERROR
) << "parent GetTranslatedPort(1) failed.";
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
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.";
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()
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
;
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
;
1273 bool WindowsProcessLauncher::DoSetup() {
1274 if (!BaseProcessLauncher::DoSetup()) {
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
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();
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
1345 mResults
.mSandboxBroker
->SetSecurityLevelForContentProcess(
1346 mSandboxLevel
, mIsFileContent
);
1350 case GeckoProcessType_Plugin
:
1351 if (mSandboxLevel
> 0 && !PR_GetEnv("MOZ_DISABLE_NPAPI_SANDBOX")) {
1352 if (!mResults
.mSandboxBroker
->SetSecurityLevelForPluginProcess(
1359 case GeckoProcessType_IPDLUnitTest
:
1360 // XXX: We don't sandbox this process type yet
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.
1369 isWidevine
? SandboxBroker::Restricted
: SandboxBroker::LockDown
;
1370 if (!mResults
.mSandboxBroker
->SetSecurityLevelForGMPlugin(level
)) {
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
);
1385 case GeckoProcessType_VR
:
1386 if (mSandboxLevel
> 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
1387 // TODO: Implement sandbox for VR process, Bug 1430043.
1390 case GeckoProcessType_RDD
:
1391 if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
1392 if (!mResults
.mSandboxBroker
->SetSecurityLevelForRDDProcess()) {
1398 case GeckoProcessType_Socket
:
1399 // TODO - setup sandboxing for the socket process.
1401 case GeckoProcessType_RemoteSandboxBroker
:
1402 // We don't sandbox the sandbox launcher...
1404 case GeckoProcessType_Default
:
1406 MOZ_CRASH("Bad process type in GeckoChildProcessHost");
1411 for (auto it
= mAllowedFilesRead
.begin(); it
!= mAllowedFilesRead
.end();
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.
1426 mCmdLine
->AppendLooseValue(mGroupId
.get());
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
));
1442 mCmdLine
->AppendLooseValue(UTF8ToWide(ChildProcessType()));
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
1456 RefPtr
<ProcessHandlePromise
> WindowsProcessLauncher::DoLaunch() {
1457 ProcessHandle handle
= 0;
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()) {
1486 // We need to be able to duplicate handles to some types of non-sandboxed
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.
1496 if (!SandboxBroker::AddTargetPeer(mResults
.mHandle
)) {
1497 NS_WARNING("Failed to add child process as target peer.");
1501 # endif // MOZ_SANDBOX
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
,
1520 return ProcessLaunchPromise::CreateAndResolve(mResults
, __func__
);
1523 bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid
) {
1524 if (mChildProcessHandle
) {
1525 MOZ_ASSERT(aPid
== base::GetProcId(mChildProcessHandle
));
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
;
1541 void GeckoChildProcessHost::OnMessageReceived(IPC::Message
&& aMsg
) {
1542 // We never process messages ourself, just save them up for the next
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
;
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();
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.
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
);
1612 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1613 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector
& aArgs
) {
1614 MacSandboxInfo info
;
1615 if (!FillMacSandboxInfo(info
)) {
1618 info
.AppendAsParams(aArgs
);
1622 // Fill |aInfo| with the flags needed to launch the utility sandbox
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());
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.
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
;
1660 case GeckoProcessType_RDD
:
1661 sandboxType
= RDDProcessHost::GetMacSandboxType();
1663 case GeckoProcessType_GMPlugin
:
1664 sandboxType
= gmp::GMPProcessParent::GetMacSandboxType();
1669 return mozilla::StartMacSandboxIfEnabled(sandboxType
, aArgc
, aArgv
,
1673 #endif /* XP_MACOSX && MOZ_SANDBOX */
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
)
1685 RefPtr
<ProcessLaunchPromise
> BaseProcessLauncher::Launch(
1686 GeckoChildProcessHost
* aHost
) {
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
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
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
1702 aHost
->InitializeChannel();
1703 mChannel
= aHost
->GetChannel();
1705 return ProcessLaunchPromise::CreateAndReject(LaunchError
{}, __func__
);
1707 mChannelId
= aHost
->GetChannelId();
1709 return InvokeAsync(mLaunchThread
, this, __func__
,
1710 &BaseProcessLauncher::PerformAsyncLaunch
);
1714 } // namespace mozilla