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/process.h"
11 #include "base/process_util.h"
12 #include "base/string_util.h"
13 #include "base/task.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/process_watcher.h"
17 # include <mach/mach_traps.h>
18 # include "SharedMemoryBasic.h"
19 # include "base/rand_util.h"
20 # include "chrome/common/mach_ipc_mac.h"
21 # include "mozilla/StaticPrefs_media.h"
23 #ifdef MOZ_WIDGET_COCOA
24 # include <bsm/libbsm.h>
25 # include <servers/bootstrap.h>
26 # include "nsILocalFileMac.h"
29 #include "GeckoProfiler.h"
30 #include "MainThreadUtils.h"
31 #include "mozilla/Preferences.h"
32 #include "mozilla/Sprintf.h"
33 #include "nsXPCOMPrivate.h"
37 #if defined(MOZ_SANDBOX)
38 # include "mozilla/SandboxSettings.h"
39 # include "nsAppDirectoryServiceDefs.h"
44 #include "ProtocolUtils.h"
45 #include "mozilla/LinkedList.h"
46 #include "mozilla/Logging.h"
47 #include "mozilla/Maybe.h"
48 #include "mozilla/GeckoArgs.h"
49 #include "mozilla/Omnijar.h"
50 #include "mozilla/RDDProcessHost.h"
51 #include "mozilla/Services.h"
52 #include "mozilla/SharedThreadPool.h"
53 #include "mozilla/StaticMutex.h"
54 #include "mozilla/TaskQueue.h"
55 #include "mozilla/Telemetry.h"
56 #include "mozilla/UniquePtrExtensions.h"
57 #include "mozilla/ipc/BrowserProcessSubThread.h"
58 #include "mozilla/ipc/EnvironmentMap.h"
59 #include "mozilla/ipc/NodeController.h"
60 #include "mozilla/net/SocketProcessHost.h"
61 #include "nsDirectoryService.h"
62 #include "nsDirectoryServiceDefs.h"
63 #include "nsExceptionHandler.h"
65 #include "nsIObserverService.h"
66 #include "nsPrintfCString.h"
71 # include "mozilla/WindowsVersion.h"
72 # include "nsIWinTaskbar.h"
73 # define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
75 # if defined(MOZ_SANDBOX)
76 # include "WinUtils.h"
77 # include "mozilla/Preferences.h"
78 # include "mozilla/sandboxing/sandboxLogging.h"
80 # include "mozilla/remoteSandboxBroker.h"
84 # include "mozilla/NativeNt.h"
85 # include "mozilla/CacheNtDllThunk.h"
88 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
89 # include "mozilla/SandboxLaunch.h"
92 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
93 # include "GMPProcessParent.h"
94 # include "nsMacUtilsImpl.h"
97 #include "mozilla/ipc/UtilityProcessHost.h"
98 #include "mozilla/ipc/UtilityProcessSandboxing.h"
100 #include "nsClassHashtable.h"
101 #include "nsHashKeys.h"
102 #include "nsNativeCharsetUtils.h"
103 #include "nsTArray.h"
104 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
105 #include "nsIThread.h"
107 using mozilla::MonitorAutoLock
;
108 using mozilla::Preferences
;
109 using mozilla::StaticMutexAutoLock
;
111 #ifdef MOZ_WIDGET_ANDROID
112 # include "AndroidBridge.h"
113 # include "mozilla/java/GeckoProcessManagerWrappers.h"
114 # include "mozilla/java/GeckoProcessTypeWrappers.h"
115 # include "mozilla/java/GeckoResultWrappers.h"
116 # include "mozilla/jni/Refs.h"
117 # include "mozilla/jni/Utils.h"
120 #ifdef MOZ_ENABLE_FORKSERVER
121 # include "mozilla/ipc/ForkServiceChild.h"
124 static bool ShouldHaveDirectoryService() {
125 return GeckoProcessType_Default
== XRE_GetProcessType();
131 struct LaunchResults
{
132 base::ProcessHandle mHandle
= 0;
134 task_t mChildTask
= MACH_PORT_NULL
;
137 Maybe
<ExtensionKitProcess
> mExtensionKitProcess
;
138 DarwinObjectPtr
<xpc_connection_t
> mXPCConnection
;
139 UniqueBEProcessCapabilityGrant mForegroundCapabilityGrant
;
141 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
142 RefPtr
<AbstractSandboxBroker
> mSandboxBroker
;
145 typedef mozilla::MozPromise
<LaunchResults
, LaunchError
, true>
146 ProcessLaunchPromise
;
148 static Atomic
<int32_t> gChildCounter
;
150 static inline nsISerialEventTarget
* IOThread() {
151 return XRE_GetIOMessageLoop()->SerialEventTarget();
154 class BaseProcessLauncher
{
156 BaseProcessLauncher(GeckoChildProcessHost
* aHost
,
157 std::vector
<std::string
>&& aExtraOpts
)
158 : mProcessType(aHost
->mProcessType
),
159 mLaunchOptions(std::move(aHost
->mLaunchOptions
)),
160 mExtraOpts(std::move(aExtraOpts
)),
162 mGroupId(aHost
->mGroupId
),
164 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
165 mAllowedFilesRead(aHost
->mAllowedFilesRead
),
166 mSandboxLevel(aHost
->mSandboxLevel
),
167 mSandbox(aHost
->mSandbox
),
168 mIsFileContent(aHost
->mIsFileContent
),
169 mEnableSandboxLogging(aHost
->mEnableSandboxLogging
),
171 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
172 mDisableOSActivityMode(aHost
->mDisableOSActivityMode
),
174 mTmpDirName(aHost
->mTmpDirName
),
175 mChildId(++gChildCounter
) {
176 SprintfLiteral(mPidString
, "%" PRIPID
, base::GetCurrentProcId());
177 aHost
->mInitialChannelId
.ToProvidedString(mInitialChannelIdString
);
179 // Compute the serial event target we'll use for launching.
180 nsCOMPtr
<nsIEventTarget
> threadOrPool
= GetIPCLauncher();
182 TaskQueue::Create(threadOrPool
.forget(), "BaseProcessLauncher");
184 if (ShouldHaveDirectoryService()) {
185 // "Current process directory" means the app dir, not the current
186 // working dir or similar.
188 << nsDirectoryService::gService
->GetCurrentProcessDirectory(
189 getter_AddRefs(mAppDir
));
193 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseProcessLauncher
);
195 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
196 void SetLaunchArchitecture(uint32_t aLaunchArch
) {
197 mLaunchArch
= aLaunchArch
;
201 RefPtr
<ProcessLaunchPromise
> Launch(GeckoChildProcessHost
*);
204 virtual ~BaseProcessLauncher() = default;
206 RefPtr
<ProcessLaunchPromise
> PerformAsyncLaunch();
207 RefPtr
<ProcessLaunchPromise
> FinishLaunch();
209 // Overrideable hooks. If superclass behavior is invoked, it's always at the
210 // top of the override.
211 virtual Result
<Ok
, LaunchError
> DoSetup();
212 virtual RefPtr
<ProcessHandlePromise
> DoLaunch() = 0;
213 virtual Result
<Ok
, LaunchError
> DoFinishLaunch();
215 void MapChildLogging();
217 static BinPathType
GetPathToBinary(FilePath
&, GeckoProcessType
);
219 void GetChildLogName(const char* origLogName
, nsACString
& buffer
);
221 const char* ChildProcessType() {
222 return XRE_GeckoProcessTypeToString(mProcessType
);
225 nsCOMPtr
<nsISerialEventTarget
> mLaunchThread
;
226 GeckoProcessType mProcessType
;
227 UniquePtr
<base::LaunchOptions
> mLaunchOptions
;
228 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
229 uint32_t mLaunchArch
= base::PROCESS_ARCH_INVALID
;
231 std::vector
<std::string
> mExtraOpts
;
235 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
236 std::vector
<std::wstring
> mAllowedFilesRead
;
237 int32_t mSandboxLevel
;
238 SandboxingKind mSandbox
;
240 bool mEnableSandboxLogging
;
242 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
243 // Controls whether or not the process will be launched with
244 // environment variable OS_ACTIVITY_MODE set to "disabled".
245 bool mDisableOSActivityMode
;
247 nsCString mTmpDirName
;
248 LaunchResults mResults
= LaunchResults();
250 TimeStamp mStartTimeStamp
= TimeStamp::Now();
252 char mInitialChannelIdString
[NSID_LENGTH
];
254 // Set during launch.
255 IPC::Channel::ChannelHandle mClientChannelHandle
;
256 nsCOMPtr
<nsIFile
> mAppDir
;
260 class WindowsProcessLauncher final
: public BaseProcessLauncher
{
262 WindowsProcessLauncher(GeckoChildProcessHost
* aHost
,
263 std::vector
<std::string
>&& aExtraOpts
)
264 : BaseProcessLauncher(aHost
, std::move(aExtraOpts
)),
265 mCachedNtdllThunk(GetCachedNtDllThunk()) {}
268 virtual Result
<Ok
, LaunchError
> DoSetup() override
;
269 virtual RefPtr
<ProcessHandlePromise
> DoLaunch() override
;
270 virtual Result
<Ok
, LaunchError
> DoFinishLaunch() override
;
273 void AddApplicationPrefetchArgument();
275 mozilla::Maybe
<CommandLine
> mCmdLine
;
277 bool mUseSandbox
= false;
280 const Buffer
<IMAGE_THUNK_DATA
>* mCachedNtdllThunk
;
282 typedef WindowsProcessLauncher ProcessLauncher
;
286 class PosixProcessLauncher
: public BaseProcessLauncher
{
288 PosixProcessLauncher(GeckoChildProcessHost
* aHost
,
289 std::vector
<std::string
>&& aExtraOpts
)
290 : BaseProcessLauncher(aHost
, std::move(aExtraOpts
)),
291 mProfileDir(aHost
->mProfileDir
),
292 mChannelDstFd(IPC::Channel::GetClientChannelHandle()) {}
295 virtual Result
<Ok
, LaunchError
> DoSetup() override
;
296 virtual RefPtr
<ProcessHandlePromise
> DoLaunch() override
;
298 nsCOMPtr
<nsIFile
> mProfileDir
;
300 std::vector
<std::string
> mChildArgv
;
304 # if defined(XP_MACOSX)
305 class MacProcessLauncher
: public PosixProcessLauncher
{
307 MacProcessLauncher(GeckoChildProcessHost
* aHost
,
308 std::vector
<std::string
>&& aExtraOpts
)
309 : PosixProcessLauncher(aHost
, std::move(aExtraOpts
)),
310 // Put a random number into the channel name, so that
311 // a compromised renderer can't pretend being the child
312 // that's forked off.
314 StringPrintf("org.mozilla.machname.%d",
315 base::RandInt(0, std::numeric_limits
<int>::max()))) {
316 MOZ_ASSERT(mMachConnectionName
.size() < BOOTSTRAP_MAX_NAME_LEN
);
320 virtual Result
<Ok
, LaunchError
> DoFinishLaunch() override
;
322 std::string mMachConnectionName
;
323 // We add a mach port to the command line so the child can communicate its
324 // 'task_t' back to the parent.
325 mozilla::UniqueMachReceiveRight mParentRecvPort
;
327 friend class PosixProcessLauncher
;
329 typedef MacProcessLauncher ProcessLauncher
;
330 # elif defined(MOZ_WIDGET_ANDROID)
331 class AndroidProcessLauncher
: public PosixProcessLauncher
{
333 AndroidProcessLauncher(GeckoChildProcessHost
* aHost
,
334 std::vector
<std::string
>&& aExtraOpts
)
335 : PosixProcessLauncher(aHost
, std::move(aExtraOpts
)) {}
338 virtual RefPtr
<ProcessHandlePromise
> DoLaunch() override
;
339 RefPtr
<ProcessHandlePromise
> LaunchAndroidService(
340 const GeckoProcessType aType
, const std::vector
<std::string
>& argv
,
341 const base::file_handle_mapping_vector
& fds_to_remap
);
343 typedef AndroidProcessLauncher ProcessLauncher
;
344 // NB: Technically Android is linux (i.e. XP_LINUX is defined), but we want
345 // orthogonal IPC machinery there. Conversely, there are tier-3 non-Linux
346 // platforms (BSD and Solaris) where we want the "linux" IPC machinery. So
347 // we use MOZ_WIDGET_* to choose the platform backend.
348 # elif defined(MOZ_WIDGET_GTK)
349 class LinuxProcessLauncher
: public PosixProcessLauncher
{
351 LinuxProcessLauncher(GeckoChildProcessHost
* aHost
,
352 std::vector
<std::string
>&& aExtraOpts
)
353 : PosixProcessLauncher(aHost
, std::move(aExtraOpts
)) {}
356 virtual Result
<Ok
, LaunchError
> DoSetup() override
;
358 typedef LinuxProcessLauncher ProcessLauncher
;
359 # elif defined(MOZ_WIDGET_UIKIT)
360 class IosProcessLauncher
: public PosixProcessLauncher
{
362 IosProcessLauncher(GeckoChildProcessHost
* aHost
,
363 std::vector
<std::string
>&& aExtraOpts
)
364 : PosixProcessLauncher(aHost
, std::move(aExtraOpts
)) {}
367 virtual RefPtr
<ProcessHandlePromise
> DoLaunch() override
;
369 DarwinObjectPtr
<xpc_object_t
> mBootstrapMessage
;
371 typedef IosProcessLauncher ProcessLauncher
;
373 # error "Unknown platform"
377 using base::ProcessHandle
;
378 using mozilla::ipc::BaseProcessLauncher
;
379 using mozilla::ipc::ProcessLauncher
;
381 mozilla::StaticAutoPtr
<mozilla::LinkedList
<GeckoChildProcessHost
>>
382 GeckoChildProcessHost::sGeckoChildProcessHosts
;
384 mozilla::StaticMutex
GeckoChildProcessHost::sMutex
;
386 GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType
,
388 : mProcessType(aProcessType
),
389 mIsFileContent(aIsFileContent
),
390 mMonitor("mozilla.ipc.GeckoChildProcessHost.mMonitor"),
391 mLaunchOptions(MakeUnique
<base::LaunchOptions
>()),
392 mInitialChannelId(nsID::GenerateUUID()),
393 mProcessState(CREATING_CHANNEL
),
397 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
398 mEnableSandboxLogging(false),
401 mHandleLock("mozilla.ipc.GeckoChildProcessHost.mHandleLock"),
402 mChildProcessHandle(0),
403 #if defined(XP_DARWIN)
404 mChildTask(MACH_PORT_NULL
),
406 #if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
407 mDisableOSActivityMode(false),
410 MOZ_COUNT_CTOR(GeckoChildProcessHost
);
411 StaticMutexAutoLock
lock(sMutex
);
412 if (!sGeckoChildProcessHosts
) {
413 sGeckoChildProcessHosts
= new mozilla::LinkedList
<GeckoChildProcessHost
>();
415 sGeckoChildProcessHosts
->insertBack(this);
416 #if defined(MOZ_SANDBOX) && defined(XP_LINUX)
417 if (aProcessType
== GeckoProcessType_Content
) {
418 # if defined(MOZ_CONTENT_TEMP_DIR)
419 // The content process needs the content temp dir:
420 nsCOMPtr
<nsIFile
> contentTempDir
;
421 nsresult rv
= NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR
,
422 getter_AddRefs(contentTempDir
));
423 if (NS_SUCCEEDED(rv
)) {
424 contentTempDir
->GetNativePath(mTmpDirName
);
427 } else if (aProcessType
== GeckoProcessType_RDD
) {
428 // The RDD process makes limited use of EGL. If Mesa's shader
429 // cache is enabled and the directory isn't explicitly set, then
430 // it will try to getpwuid() the user which can cause problems
431 // with sandboxing. Because we shouldn't need shader caching in
432 // this process, we just disable the cache to prevent that.
433 mLaunchOptions
->env_map
["MESA_GLSL_CACHE_DISABLE"] = "true";
434 mLaunchOptions
->env_map
["MESA_SHADER_CACHE_DISABLE"] = "true";
435 // In case the nvidia driver is also loaded:
436 mLaunchOptions
->env_map
["__GL_SHADER_DISK_CACHE"] = "0";
439 #if defined(MOZ_ENABLE_FORKSERVER)
440 if (aProcessType
!= GeckoProcessType_ForkServer
&& ForkServiceChild::Get()) {
441 mLaunchOptions
->use_forkserver
= true;
446 GeckoChildProcessHost::~GeckoChildProcessHost()
450 MOZ_RELEASE_ASSERT(mDestroying
);
452 MOZ_COUNT_DTOR(GeckoChildProcessHost
);
455 mozilla::AutoWriteLock
hLock(mHandleLock
);
456 #if defined(XP_DARWIN)
457 if (mChildTask
!= MACH_PORT_NULL
) {
458 mach_port_deallocate(mach_task_self(), mChildTask
);
462 if (mForegroundCapabilityGrant
) {
463 mForegroundCapabilityGrant
.reset();
465 if (mExtensionKitProcess
) {
466 mExtensionKitProcess
->Invalidate();
468 if (mXPCConnection
) {
469 xpc_connection_cancel(mXPCConnection
.get());
473 if (mChildProcessHandle
!= 0) {
474 ProcessWatcher::EnsureProcessTerminated(
476 #ifdef NS_FREE_PERMANENT_DATA
477 // If we're doing leak logging, shutdown can be slow.
479 false // don't "force"
482 mChildProcessHandle
= 0;
486 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
487 if (mSandboxBroker
) {
488 mSandboxBroker
->Shutdown();
489 mSandboxBroker
= nullptr;
494 base::ProcessHandle
GeckoChildProcessHost::GetChildProcessHandle() {
495 mozilla::AutoReadLock
handleLock(mHandleLock
);
496 return mChildProcessHandle
;
499 base::ProcessId
GeckoChildProcessHost::GetChildProcessId() {
500 mozilla::AutoReadLock
handleLock(mHandleLock
);
501 if (!mChildProcessHandle
) {
504 return base::GetProcId(mChildProcessHandle
);
508 task_t
GeckoChildProcessHost::GetChildTask() {
509 mozilla::AutoReadLock
handleLock(mHandleLock
);
514 void GeckoChildProcessHost::RemoveFromProcessList() {
515 StaticMutexAutoLock
lock(sMutex
);
516 if (!sGeckoChildProcessHosts
) {
519 LinkedListElement
<GeckoChildProcessHost
>::removeFrom(
520 *sGeckoChildProcessHosts
);
523 void GeckoChildProcessHost::Destroy() {
524 MOZ_RELEASE_ASSERT(!mDestroying
);
525 // We can remove from the list before it's really destroyed
526 RemoveFromProcessList();
527 RefPtr
<ProcessHandlePromise
> whenReady
= mHandlePromise
;
530 // AsyncLaunch not called yet, so dispatch immediately.
531 whenReady
= ProcessHandlePromise::CreateAndReject(
532 LaunchError("DestroyEarly"), __func__
);
535 using Value
= ProcessHandlePromise::ResolveOrRejectValue
;
537 whenReady
->Then(XRE_GetIOMessageLoop()->SerialEventTarget(), __func__
,
538 [this](const Value
&) { delete this; });
542 mozilla::BinPathType
BaseProcessLauncher::GetPathToBinary(
543 FilePath
& exePath
, GeckoProcessType processType
) {
544 BinPathType pathType
= XRE_GetChildProcBinPathType(processType
);
546 if (pathType
== BinPathType::Self
) {
548 wchar_t exePathBuf
[MAXPATHLEN
];
549 if (!::GetModuleFileNameW(nullptr, exePathBuf
, MAXPATHLEN
)) {
550 MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
552 exePath
= FilePath::FromWStringHack(exePathBuf
);
554 exePath
= FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
559 #ifdef MOZ_WIDGET_COCOA
560 // The GMP child process runs via the Media Plugin Helper executable
561 // which is a clone of plugin-container allowing for GMP-specific
562 // codesigning entitlements.
563 nsCString bundleName
;
564 std::string executableLeafName
;
565 if (processType
== GeckoProcessType_GMPlugin
&&
566 mozilla::StaticPrefs::media_plugin_helper_process_enabled()) {
567 bundleName
= MOZ_EME_PROCESS_BUNDLENAME
;
568 executableLeafName
= MOZ_EME_PROCESS_NAME_BRANDED
;
570 bundleName
= MOZ_CHILD_PROCESS_BUNDLENAME
;
571 executableLeafName
= MOZ_CHILD_PROCESS_NAME
;
575 if (ShouldHaveDirectoryService()) {
576 MOZ_ASSERT(gGREBinPath
);
578 exePath
= FilePath(char16ptr_t(gGREBinPath
));
579 #elif MOZ_WIDGET_COCOA
580 nsCOMPtr
<nsIFile
> childProcPath
;
581 NS_NewLocalFile(nsDependentString(gGREBinPath
), false,
582 getter_AddRefs(childProcPath
));
584 // We need to use an App Bundle on OS X so that we can hide
585 // the dock icon. See Bug 557225.
586 childProcPath
->AppendNative(bundleName
);
587 childProcPath
->AppendNative("Contents"_ns
);
588 childProcPath
->AppendNative("MacOS"_ns
);
590 childProcPath
->GetNativePath(tempCPath
);
591 exePath
= FilePath(tempCPath
.get());
594 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath
), path
);
595 exePath
= FilePath(path
.get());
599 if (exePath
.empty()) {
602 FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
604 exePath
= FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
606 exePath
= exePath
.DirName();
609 #ifdef MOZ_WIDGET_COCOA
610 exePath
= exePath
.Append(executableLeafName
);
612 exePath
= exePath
.AppendASCII(MOZ_CHILD_PROCESS_NAME
);
618 #ifdef MOZ_WIDGET_COCOA
619 class AutoCFTypeObject
{
621 explicit AutoCFTypeObject(CFTypeRef object
) { mObject
= object
; }
622 ~AutoCFTypeObject() { ::CFRelease(mObject
); }
629 // We start the unique IDs at 1 so that 0 can be used to mean that
630 // a component has no unique ID assigned to it.
631 uint32_t GeckoChildProcessHost::sNextUniqueID
= 1;
634 uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID
++; }
637 void GeckoChildProcessHost::SetEnv(const char* aKey
, const char* aValue
) {
638 MOZ_ASSERT(mLaunchOptions
);
639 mLaunchOptions
->env_map
[ENVIRONMENT_STRING(aKey
)] =
640 ENVIRONMENT_STRING(aValue
);
643 void GeckoChildProcessHost::PrepareLaunch() {
644 if (CrashReporter::GetEnabled()) {
645 CrashReporter::OOPInit();
648 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
649 SandboxLaunch::Configure(mProcessType
, mSandbox
, mLaunchOptions
.get());
654 # if defined(MOZ_SANDBOX)
655 // We need to get the pref here as the process is launched off main thread.
656 if (mProcessType
== GeckoProcessType_Content
) {
657 // Win32k Lockdown state must be initialized on the main thread.
658 // This is our last chance to do it before it is read on the IPC Launch
660 GetWin32kLockdownState();
661 mSandboxLevel
= GetEffectiveContentSandboxLevel();
662 mEnableSandboxLogging
=
663 Preferences::GetBool("security.sandbox.logging.enabled");
665 // We currently have to whitelist certain paths for tests to work in some
666 // development configurations.
667 nsAutoString readPaths
;
668 nsresult rv
= Preferences::GetString(
669 "security.sandbox.content.read_path_whitelist", readPaths
);
670 if (NS_SUCCEEDED(rv
)) {
671 for (const nsAString
& readPath
: readPaths
.Split(',')) {
672 nsString
trimmedPath(readPath
);
673 trimmedPath
.Trim(" ", true, true);
674 std::wstring
resolvedPath(trimmedPath
.Data());
675 // Check if path ends with '\' as this indicates we want to give read
676 // access to a directory and so it needs a wildcard.
677 if (resolvedPath
.back() == L
'\\') {
678 resolvedPath
.append(L
"*");
680 mAllowedFilesRead
.push_back(resolvedPath
);
686 # if defined(MOZ_SANDBOX)
687 // For other process types we can't rely on them being launched on main
688 // thread and they may not have access to prefs in the child process, so allow
689 // them to turn on logging via an environment variable.
690 mEnableSandboxLogging
=
691 mEnableSandboxLogging
|| !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
694 #elif defined(XP_MACOSX)
695 # if defined(MOZ_SANDBOX)
696 if (ShouldHaveDirectoryService() &&
697 mProcessType
!= GeckoProcessType_GMPlugin
) {
698 mozilla::Unused
<< NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
,
699 getter_AddRefs(mProfileDir
));
706 void GeckoChildProcessHost::InitWindowsGroupID() {
707 // On Win7+, pass the application user model to the child, so it can
708 // register with it. This insures windows created by the container
709 // properly group with the parent app on the Win7 taskbar.
710 nsCOMPtr
<nsIWinTaskbar
> taskbarInfo
= do_GetService(NS_TASKBAR_CONTRACTID
);
712 bool isSupported
= false;
713 taskbarInfo
->GetAvailable(&isSupported
);
715 if (isSupported
&& NS_SUCCEEDED(taskbarInfo
->GetDefaultGroupId(appId
))) {
716 MOZ_ASSERT(mGroupId
.EqualsLiteral("-"));
717 mGroupId
.Assign(appId
);
723 bool GeckoChildProcessHost::SyncLaunch(std::vector
<std::string
> aExtraOpts
,
725 if (!AsyncLaunch(std::move(aExtraOpts
))) {
728 return WaitUntilConnected(aTimeoutMs
);
731 // Note: for most process types, we currently call AsyncLaunch, and therefore
732 // the *ProcessLauncher constructor, on the main thread, while the
733 // ProcessLauncher methods to actually execute the launch are called on the IO
734 // or IPC launcher thread. GMP processes are an exception - the GMP code
735 // invokes GeckoChildProcessHost from non-main-threads, and therefore we cannot
736 // rely on having access to mainthread-only services (like the directory
737 // service) from this code if we're launching that type of process.
738 bool GeckoChildProcessHost::AsyncLaunch(std::vector
<std::string
> aExtraOpts
) {
741 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
742 if (IsMacSandboxLaunchEnabled() && !AppendMacSandboxParams(aExtraOpts
)) {
747 RefPtr
<BaseProcessLauncher
> launcher
=
748 new ProcessLauncher(this, std::move(aExtraOpts
));
749 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
750 launcher
->SetLaunchArchitecture(mLaunchArch
);
753 // Note: Destroy() waits on mHandlePromise to delete |this|. As such, we want
754 // to be sure that all of our post-launch processing on |this| happens before
755 // mHandlePromise notifies.
756 MOZ_ASSERT(mHandlePromise
== nullptr);
758 mozilla::InvokeAsync
<GeckoChildProcessHost
*>(
759 IOThread(), launcher
.get(), __func__
, &BaseProcessLauncher::Launch
,
762 IOThread(), __func__
,
763 [this](LaunchResults
&& aResults
) {
766 mozilla::AutoWriteLock
handleLock(mHandleLock
);
767 if (!OpenPrivilegedHandle(base::GetProcId(aResults
.mHandle
))
769 // If we failed in opening the process handle, try
770 // harder by duplicating one.
771 && !::DuplicateHandle(
772 ::GetCurrentProcess(), aResults
.mHandle
,
773 ::GetCurrentProcess(), &mChildProcessHandle
,
774 PROCESS_DUP_HANDLE
| PROCESS_TERMINATE
|
775 PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
|
780 MOZ_CRASH("cannot open handle to child process");
782 // The original handle is no longer needed; it must
783 // be closed to prevent a resource leak.
784 base::CloseProcessHandle(aResults
.mHandle
);
785 // FIXME (bug 1720523): define a cross-platform
786 // "safe" invalid value to use in places like this.
787 aResults
.mHandle
= 0;
790 this->mChildTask
= aResults
.mChildTask
;
793 this->mExtensionKitProcess
= aResults
.mExtensionKitProcess
;
794 this->mXPCConnection
= aResults
.mXPCConnection
;
795 this->mForegroundCapabilityGrant
=
796 std::move(aResults
.mForegroundCapabilityGrant
);
800 mNodeChannel
->SetOtherPid(
801 base::GetProcId(this->mChildProcessHandle
));
803 mNodeChannel
->SetMachTaskPort(this->mChildTask
);
807 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
808 this->mSandboxBroker
= std::move(aResults
.mSandboxBroker
);
811 MonitorAutoLock
lock(mMonitor
);
812 // The OnChannel{Connected,Error} may have already advanced
814 if (mProcessState
< PROCESS_CREATED
) {
815 mProcessState
= PROCESS_CREATED
;
819 return ProcessHandlePromise::CreateAndResolve(
820 GetChildProcessHandle(), __func__
);
822 [this](const LaunchError aError
) {
823 // WaitUntilConnected might be waiting for us to signal.
824 // If something failed let's set the error state and notify.
826 << "Failed to launch "
827 << XRE_GeckoProcessTypeToString(mProcessType
)
828 << " subprocess @" << aError
.FunctionName()
829 << " (Error:" << aError
.ErrorCode() << ")";
830 Telemetry::Accumulate(
831 Telemetry::SUBPROCESS_LAUNCH_FAILURE
,
833 XRE_GeckoProcessTypeToString(mProcessType
)));
834 nsCString telemetryKey
= nsPrintfCString(
840 aError
.FunctionName(), aError
.ErrorCode(),
841 XRE_GeckoProcessTypeToString(mProcessType
));
842 // Max telemetry key is 72 chars
843 // https://searchfox.org/mozilla-central/rev/c244b16815d1fc827d141472b9faac5610f250e7/toolkit/components/telemetry/core/TelemetryScalar.cpp#105
844 if (telemetryKey
.Length() > 72) {
845 NS_WARNING(nsPrintfCString("Truncating telemetry key: %s",
848 telemetryKey
.Truncate(72);
850 Telemetry::ScalarAdd(
851 Telemetry::ScalarID::
852 DOM_PARENTPROCESS_PROCESS_LAUNCH_ERRORS
,
853 NS_ConvertUTF8toUTF16(telemetryKey
), 1);
855 MonitorAutoLock
lock(mMonitor
);
856 mProcessState
= PROCESS_ERROR
;
859 return ProcessHandlePromise::CreateAndReject(aError
, __func__
);
864 bool GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs
) {
865 AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER
);
867 // NB: this uses a different mechanism than the chromium parent
869 TimeDuration timeout
= (aTimeoutMs
> 0)
870 ? TimeDuration::FromMilliseconds(aTimeoutMs
)
871 : TimeDuration::Forever();
873 MonitorAutoLock
lock(mMonitor
);
874 TimeStamp waitStart
= TimeStamp::Now();
877 // We'll receive several notifications, we need to exit when we
878 // have either successfully launched or have timed out.
879 while (mProcessState
!= PROCESS_CONNECTED
) {
880 // If there was an error then return it, don't wait out the timeout.
881 if (mProcessState
== PROCESS_ERROR
) {
885 CVStatus status
= lock
.Wait(timeout
);
886 if (status
== CVStatus::Timeout
) {
890 if (timeout
!= TimeDuration::Forever()) {
891 current
= TimeStamp::Now();
892 timeout
-= current
- waitStart
;
897 return mProcessState
== PROCESS_CONNECTED
;
900 bool GeckoChildProcessHost::WaitForProcessHandle() {
901 MonitorAutoLock
lock(mMonitor
);
902 while (mProcessState
< PROCESS_CREATED
) {
905 MOZ_ASSERT(mProcessState
== PROCESS_ERROR
|| GetChildProcessHandle());
907 return mProcessState
< PROCESS_ERROR
;
910 bool GeckoChildProcessHost::LaunchAndWaitForProcessHandle(
911 StringVector aExtraOpts
) {
912 if (!AsyncLaunch(std::move(aExtraOpts
))) {
915 return WaitForProcessHandle();
918 void GeckoChildProcessHost::InitializeChannel(
919 IPC::Channel::ChannelHandle
&& aServerHandle
) {
920 // Create the IPC channel which will be used for communication with this
922 mozilla::UniquePtr
<IPC::Channel
> channel
= MakeUnique
<IPC::Channel
>(
923 std::move(aServerHandle
), IPC::Channel::MODE_SERVER
,
924 base::kInvalidProcessId
);
926 channel
->StartAcceptingHandles(IPC::Channel::MODE_SERVER
);
927 #elif defined(XP_DARWIN)
928 channel
->StartAcceptingMachPorts(IPC::Channel::MODE_SERVER
);
931 mNodeController
= NodeController::GetSingleton();
932 std::tie(mInitialPort
, mNodeChannel
) =
933 mNodeController
->InviteChildProcess(std::move(channel
), this);
935 MonitorAutoLock
lock(mMonitor
);
936 mProcessState
= CHANNEL_INITIALIZED
;
940 void GeckoChildProcessHost::SetAlreadyDead() {
941 mozilla::AutoWriteLock
handleLock(mHandleLock
);
942 if (mChildProcessHandle
&&
943 mChildProcessHandle
!= base::kInvalidProcessHandle
) {
944 base::CloseProcessHandle(mChildProcessHandle
);
947 mChildProcessHandle
= 0;
950 void BaseProcessLauncher::GetChildLogName(const char* origLogName
,
951 nsACString
& buffer
) {
953 // On Windows we must expand relative paths because sandboxing rules
954 // bound only to full paths. fopen fowards to NtCreateFile which checks
955 // the path against the sanboxing rules as passed to fopen (left relative).
956 char absPath
[MAX_PATH
+ 2];
957 if (_fullpath(absPath
, origLogName
, sizeof(absPath
))) {
958 buffer
.Append(absPath
);
962 buffer
.Append(origLogName
);
965 // Remove .moz_log extension to avoid its duplication, it will be added
966 // automatically by the logging backend
967 static constexpr auto kMozLogExt
= nsLiteralCString
{MOZ_LOG_FILE_EXTENSION
};
968 if (StringEndsWith(buffer
, kMozLogExt
)) {
969 buffer
.Truncate(buffer
.Length() - kMozLogExt
.Length());
972 // Append child-specific postfix to name
973 buffer
.AppendLiteral(".child-");
974 buffer
.AppendInt(mChildId
);
977 // Windows needs a single dedicated thread for process launching,
978 // because of thread-safety restrictions/assertions in the sandbox
981 // Android also needs a single dedicated thread to simplify thread
984 // Fork server needs a dedicated thread for accessing
985 // |ForkServiceChild|.
986 #if defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID) || \
987 defined(MOZ_ENABLE_FORKSERVER)
989 static mozilla::StaticMutex gIPCLaunchThreadMutex
;
990 static mozilla::StaticRefPtr
<nsIThread
> gIPCLaunchThread
991 MOZ_GUARDED_BY(gIPCLaunchThreadMutex
);
993 class IPCLaunchThreadObserver final
: public nsIObserver
{
998 virtual ~IPCLaunchThreadObserver() = default;
1001 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver
, nsIObserver
, nsISupports
)
1004 IPCLaunchThreadObserver::Observe(nsISupports
* aSubject
, const char* aTopic
,
1005 const char16_t
* aData
) {
1006 MOZ_RELEASE_ASSERT(strcmp(aTopic
, "xpcom-shutdown-threads") == 0);
1007 StaticMutexAutoLock
lock(gIPCLaunchThreadMutex
);
1009 nsresult rv
= NS_OK
;
1010 if (gIPCLaunchThread
) {
1011 rv
= gIPCLaunchThread
->Shutdown();
1012 gIPCLaunchThread
= nullptr;
1014 mozilla::Unused
<< NS_WARN_IF(NS_FAILED(rv
));
1018 nsCOMPtr
<nsIEventTarget
> GetIPCLauncher() {
1019 StaticMutexAutoLock
lock(gIPCLaunchThreadMutex
);
1020 if (!gIPCLaunchThread
) {
1021 nsCOMPtr
<nsIThread
> thread
;
1022 nsresult rv
= NS_NewNamedThread("IPC Launch"_ns
, getter_AddRefs(thread
));
1023 if (!NS_WARN_IF(NS_FAILED(rv
))) {
1024 NS_DispatchToMainThread(
1025 NS_NewRunnableFunction("GeckoChildProcessHost::GetIPCLauncher", [] {
1026 nsCOMPtr
<nsIObserverService
> obsService
=
1027 mozilla::services::GetObserverService();
1028 nsCOMPtr
<nsIObserver
> obs
= new IPCLaunchThreadObserver();
1029 obsService
->AddObserver(obs
, "xpcom-shutdown-threads", false);
1031 gIPCLaunchThread
= thread
.forget();
1035 nsCOMPtr
<nsIEventTarget
> thread
= gIPCLaunchThread
.get();
1036 MOZ_DIAGNOSTIC_ASSERT(thread
);
1040 #else // defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID) ||
1041 // defined(MOZ_ENABLE_FORKSERVER)
1043 // Other platforms use an on-demand thread pool.
1045 nsCOMPtr
<nsIEventTarget
> GetIPCLauncher() {
1046 nsCOMPtr
<nsIEventTarget
> pool
=
1047 mozilla::SharedThreadPool::Get("IPC Launch"_ns
);
1048 MOZ_DIAGNOSTIC_ASSERT(pool
);
1052 #endif // XP_WIN || MOZ_WIDGET_ANDROID || MOZ_ENABLE_FORKSERVER
1056 AddAppDirToCommandLine(CommandLine
& aCmdLine
, nsIFile
* aAppDir
)
1058 AddAppDirToCommandLine(std::vector
<std::string
>& aCmdLine
, nsIFile
* aAppDir
,
1059 nsIFile
* aProfileDir
)
1062 // Content processes need access to application resources, so pass
1063 // the full application directory path to the child process.
1067 MOZ_ALWAYS_SUCCEEDS(aAppDir
->GetPath(path
));
1068 aCmdLine
.AppendLooseValue(UTF8ToWide(geckoargs::sAppDir
.Name()));
1069 std::wstring
wpath(path
.get());
1070 aCmdLine
.AppendLooseValue(wpath
);
1073 MOZ_ALWAYS_SUCCEEDS(aAppDir
->GetNativePath(path
));
1074 geckoargs::sAppDir
.Put(path
.get(), aCmdLine
);
1077 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1078 // Full path to the profile dir
1080 // If the profile doesn't exist, normalization will
1081 // fail. But we don't return an error here because some
1082 // tests require startup with a missing profile dir.
1083 // For users, almost universally, the profile will be in
1084 // the home directory and normalization isn't required.
1085 mozilla::Unused
<< aProfileDir
->Normalize();
1087 MOZ_ALWAYS_SUCCEEDS(aProfileDir
->GetNativePath(path
));
1088 geckoargs::sProfile
.Put(path
.get(), aCmdLine
);
1094 #if defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
1095 static bool Contains(const std::vector
<std::string
>& aExtraOpts
,
1096 const char* aValue
) {
1097 return std::any_of(aExtraOpts
.begin(), aExtraOpts
.end(),
1098 [&](const std::string arg
) {
1099 return arg
.find(aValue
) != std::string::npos
;
1102 #endif // defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
1104 RefPtr
<ProcessLaunchPromise
> BaseProcessLauncher::PerformAsyncLaunch() {
1105 Result
<Ok
, LaunchError
> aError
= DoSetup();
1106 if (aError
.isErr()) {
1107 return ProcessLaunchPromise::CreateAndReject(aError
.unwrapErr(), __func__
);
1109 RefPtr
<BaseProcessLauncher
> self
= this;
1110 return DoLaunch()->Then(
1111 mLaunchThread
, __func__
,
1112 [self
](base::ProcessHandle aHandle
) {
1113 self
->mResults
.mHandle
= aHandle
;
1114 return self
->FinishLaunch();
1116 [](LaunchError aError
) {
1117 return ProcessLaunchPromise::CreateAndReject(aError
, __func__
);
1121 Result
<Ok
, LaunchError
> BaseProcessLauncher::DoSetup() {
1122 RefPtr
<BaseProcessLauncher
> self
= this;
1123 GetProfilerEnvVarsForChildProcess([self
](const char* key
, const char* value
) {
1124 self
->mLaunchOptions
->env_map
[ENVIRONMENT_STRING(key
)] =
1125 ENVIRONMENT_STRING(value
);
1128 if (mProcessType
== GeckoProcessType_Content
) {
1129 nsAutoCString
mallocOpts(PR_GetEnv("MALLOC_OPTIONS"));
1130 // Disable randomization of small arenas in content.
1131 mallocOpts
.Append("r");
1132 self
->mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("MALLOC_OPTIONS")] =
1133 ENVIRONMENT_STRING(mallocOpts
.get());
1142 void BaseProcessLauncher::MapChildLogging() {
1143 const char* origNSPRLogName
= PR_GetEnv("NSPR_LOG_FILE");
1144 const char* origMozLogName
= PR_GetEnv("MOZ_LOG_FILE");
1146 if (origNSPRLogName
) {
1147 nsAutoCString nsprLogName
;
1148 GetChildLogName(origNSPRLogName
, nsprLogName
);
1149 mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("NSPR_LOG_FILE")] =
1150 ENVIRONMENT_STRING(nsprLogName
.get());
1152 if (origMozLogName
) {
1153 nsAutoCString mozLogName
;
1154 GetChildLogName(origMozLogName
, mozLogName
);
1155 mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("MOZ_LOG_FILE")] =
1156 ENVIRONMENT_STRING(mozLogName
.get());
1159 // `RUST_LOG_CHILD` is meant for logging child processes only.
1160 nsAutoCString
childRustLog(PR_GetEnv("RUST_LOG_CHILD"));
1161 if (!childRustLog
.IsEmpty()) {
1162 mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("RUST_LOG")] =
1163 ENVIRONMENT_STRING(childRustLog
.get());
1167 Result
<Ok
, LaunchError
> BaseProcessLauncher::DoFinishLaunch() {
1168 // We're in the parent and the child was launched. Close the child channel
1169 // handle in the parent as soon as possible, which will allow the parent to
1170 // detect when the child closes its handle (either due to normal exit or due
1172 mClientChannelHandle
= nullptr;
1177 #if defined(MOZ_WIDGET_GTK)
1178 Result
<Ok
, LaunchError
> LinuxProcessLauncher::DoSetup() {
1179 Result
<Ok
, LaunchError
> aError
= PosixProcessLauncher::DoSetup();
1180 if (aError
.isErr()) {
1184 if (mProcessType
== GeckoProcessType_Content
) {
1185 // disable IM module to avoid sandbox violation
1186 mLaunchOptions
->env_map
["GTK_IM_MODULE"] = "gtk-im-context-simple";
1188 // Disable ATK accessibility code in content processes because it conflicts
1189 // with the sandbox, and we proxy that information through the main process
1191 mLaunchOptions
->env_map
["NO_AT_BRIDGE"] = "1";
1195 if (!mTmpDirName
.IsEmpty()) {
1196 // Point a bunch of things that might want to write from content to our
1197 // shiny new content-process specific tmpdir
1198 mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("TMPDIR")] =
1199 ENVIRONMENT_STRING(mTmpDirName
.get());
1200 // Partial fix for bug 1380051 (not persistent - should be)
1201 mLaunchOptions
->env_map
[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
1202 ENVIRONMENT_STRING(mTmpDirName
.get());
1204 # endif // MOZ_SANDBOX
1208 #endif // MOZ_WIDGET_GTK
1211 Result
<Ok
, LaunchError
> PosixProcessLauncher::DoSetup() {
1212 Result
<Ok
, LaunchError
> aError
= BaseProcessLauncher::DoSetup();
1213 if (aError
.isErr()) {
1217 // XPCOM may not be initialized in some subprocesses. We don't want
1218 // to initialize XPCOM just for the directory service, especially
1219 // since LD_LIBRARY_PATH is already set correctly in subprocesses
1220 // (meaning that we don't need to set that up in the environment).
1221 if (ShouldHaveDirectoryService()) {
1222 MOZ_ASSERT(gGREBinPath
);
1224 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath
), path
);
1225 # if defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \
1226 defined(XP_NETBSD) || defined(XP_OPENBSD)
1227 const char* ld_library_path
= PR_GetEnv("LD_LIBRARY_PATH");
1228 nsCString
new_ld_lib_path(path
.get());
1230 if (ld_library_path
&& *ld_library_path
) {
1231 new_ld_lib_path
.Append(':');
1232 new_ld_lib_path
.Append(ld_library_path
);
1234 mLaunchOptions
->env_map
["LD_LIBRARY_PATH"] = new_ld_lib_path
.get();
1237 // With signed production Mac builds, the dynamic linker (dyld) will
1238 // ignore dyld environment variables preventing the use of variables
1239 // such as DYLD_LIBRARY_PATH and DYLD_INSERT_LIBRARIES.
1241 // If we're running with gtests, add the gtest XUL ahead of normal XUL on
1242 // the DYLD_LIBRARY_PATH so that plugin-container.app loads it instead.
1243 nsCString
new_dyld_lib_path(path
.get());
1244 if (PR_GetEnv("MOZ_RUN_GTEST")) {
1245 new_dyld_lib_path
= path
+ "/gtest:"_ns
+ new_dyld_lib_path
;
1246 mLaunchOptions
->env_map
["DYLD_LIBRARY_PATH"] = new_dyld_lib_path
.get();
1249 // DYLD_INSERT_LIBRARIES is currently unused by default but we allow
1250 // it to be set by the external environment.
1251 const char* interpose
= PR_GetEnv("DYLD_INSERT_LIBRARIES");
1252 if (interpose
&& strlen(interpose
) > 0) {
1253 mLaunchOptions
->env_map
["DYLD_INSERT_LIBRARIES"] = interpose
;
1256 // Prevent connection attempts to diagnosticd(8) to save cycles. Log
1257 // messages can trigger these connection attempts, but access to
1258 // diagnosticd is blocked in sandboxed child processes.
1259 # if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
1260 if (mDisableOSActivityMode
) {
1261 mLaunchOptions
->env_map
["OS_ACTIVITY_MODE"] = "disable";
1263 # endif // defined(MOZ_SANDBOX)
1268 BinPathType pathType
= GetPathToBinary(exePath
, mProcessType
);
1270 // remap the IPC socket fd to a well-known int, as the OS does for
1271 // STDOUT_FILENO, for example
1272 // The fork server doesn't use IPC::Channel, so can skip this step.
1273 if (mProcessType
!= GeckoProcessType_ForkServer
) {
1274 # if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT)
1275 // On Android/iOS, mChannelDstFd is initialised to -1 and the launching
1276 // code uses only the first of each pair.
1277 MOZ_ASSERT(mChannelDstFd
>= 0);
1279 mLaunchOptions
->fds_to_remap
.push_back(
1280 std::pair
<int, int>(mClientChannelHandle
.get(), mChannelDstFd
));
1283 // no need for kProcessChannelID, the child process inherits the
1284 // other end of the socketpair() from us
1286 mChildArgv
.push_back(exePath
.value());
1288 if (pathType
== BinPathType::Self
) {
1289 mChildArgv
.push_back("-contentproc");
1292 mChildArgv
.insert(mChildArgv
.end(), mExtraOpts
.begin(), mExtraOpts
.end());
1294 if ((mProcessType
== GeckoProcessType_Content
||
1295 mProcessType
== GeckoProcessType_ForkServer
) &&
1296 Omnijar::IsInitialized()) {
1297 // Make sure that child processes can find the omnijar, if they
1298 // use full XPCOM. See Omnijar::ChildProcessInit and its callers.
1300 nsCOMPtr
<nsIFile
> greFile
= Omnijar::GetPath(Omnijar::GRE
);
1301 if (greFile
&& NS_SUCCEEDED(greFile
->GetNativePath(path
))) {
1302 geckoargs::sGREOmni
.Put(path
.get(), mChildArgv
);
1304 nsCOMPtr
<nsIFile
> appFile
= Omnijar::GetPath(Omnijar::APP
);
1305 if (appFile
&& NS_SUCCEEDED(appFile
->GetNativePath(path
))) {
1306 geckoargs::sAppOmni
.Put(path
.get(), mChildArgv
);
1310 if (mProcessType
!= GeckoProcessType_GMPlugin
) {
1311 // Add the application directory path (-appdir path)
1313 AddAppDirToCommandLine(mChildArgv
, mAppDir
, mProfileDir
);
1315 AddAppDirToCommandLine(mChildArgv
, mAppDir
, nullptr);
1319 mChildArgv
.push_back(mInitialChannelIdString
);
1321 mChildArgv
.push_back(mPidString
);
1323 if (!CrashReporter::IsDummy()) {
1324 # if defined(MOZ_WIDGET_COCOA)
1325 mChildArgv
.push_back(CrashReporter::GetChildNotificationPipe());
1326 # elif defined(XP_UNIX)
1327 int childCrashFd
, childCrashRemapFd
;
1328 if (NS_WARN_IF(!CrashReporter::CreateNotificationPipeForChild(
1329 &childCrashFd
, &childCrashRemapFd
))) {
1330 return Err(LaunchError("CR::CreateNotificationPipeForChild"));
1333 if (0 <= childCrashFd
) {
1334 mLaunchOptions
->fds_to_remap
.push_back(
1335 std::pair
<int, int>(childCrashFd
, childCrashRemapFd
));
1336 // "true" == crash reporting enabled
1337 mChildArgv
.push_back("true");
1339 // "false" == crash reporting disabled
1340 mChildArgv
.push_back("false");
1345 # ifdef MOZ_WIDGET_COCOA
1347 auto* thisMac
= static_cast<MacProcessLauncher
*>(this);
1349 bootstrap_check_in(bootstrap_port
, thisMac
->mMachConnectionName
.c_str(),
1350 getter_Transfers(thisMac
->mParentRecvPort
));
1351 if (kr
!= KERN_SUCCESS
) {
1352 CHROMIUM_LOG(ERROR
) << "parent bootstrap_check_in failed: "
1353 << mach_error_string(kr
);
1354 return Err(LaunchError("bootstrap_check_in", kr
));
1356 mChildArgv
.push_back(thisMac
->mMachConnectionName
.c_str());
1358 # endif // MOZ_WIDGET_COCOA
1360 mChildArgv
.push_back(ChildProcessType());
1365 #if defined(MOZ_WIDGET_ANDROID)
1366 RefPtr
<ProcessHandlePromise
> AndroidProcessLauncher::DoLaunch() {
1367 return LaunchAndroidService(mProcessType
, mChildArgv
,
1368 mLaunchOptions
->fds_to_remap
);
1370 #endif // MOZ_WIDGET_ANDROID
1373 RefPtr
<ProcessHandlePromise
> PosixProcessLauncher::DoLaunch() {
1374 ProcessHandle handle
= 0;
1375 Result
<Ok
, LaunchError
> aError
=
1376 base::LaunchApp(mChildArgv
, std::move(*mLaunchOptions
), &handle
);
1377 if (aError
.isErr()) {
1378 return ProcessHandlePromise::CreateAndReject(aError
.unwrapErr(), __func__
);
1380 return ProcessHandlePromise::CreateAndResolve(handle
, __func__
);
1385 RefPtr
<ProcessHandlePromise
> IosProcessLauncher::DoLaunch() {
1386 MOZ_RELEASE_ASSERT(mLaunchOptions
->fds_to_remap
.size() == 3,
1387 "Unexpected fds_to_remap on iOS");
1389 ExtensionKitProcess::Kind kind
= ExtensionKitProcess::Kind::WebContent
;
1390 if (mProcessType
== GeckoProcessType_GPU
) {
1391 kind
= ExtensionKitProcess::Kind::Rendering
;
1392 } else if (mProcessType
== GeckoProcessType_Socket
) {
1393 kind
= ExtensionKitProcess::Kind::Networking
;
1396 DarwinObjectPtr
<xpc_object_t
> bootstrapMessage
=
1397 AdoptDarwinObject(xpc_dictionary_create_empty());
1398 xpc_dictionary_set_string(bootstrapMessage
.get(), "message-name",
1401 DarwinObjectPtr
<xpc_object_t
> environDict
=
1402 AdoptDarwinObject(xpc_dictionary_create_empty());
1403 for (auto& [envKey
, envValue
] : mLaunchOptions
->env_map
) {
1404 xpc_dictionary_set_string(environDict
.get(), envKey
.c_str(),
1407 xpc_dictionary_set_value(bootstrapMessage
.get(), "environ",
1410 // XXX: this processing depends entirely on the internals of
1411 // ContentParent::LaunchSubprocess()
1412 // GeckoChildProcessHost::PerformAsyncLaunch(), and the order in
1413 // which they append to fds_to_remap. There must be a better way to do it.
1415 int prefsFd
= mLaunchOptions
->fds_to_remap
[0].first
;
1416 int prefMapFd
= mLaunchOptions
->fds_to_remap
[1].first
;
1417 int ipcFd
= mLaunchOptions
->fds_to_remap
[2].first
;
1418 xpc_dictionary_set_fd(bootstrapMessage
.get(), "prefs", prefsFd
);
1419 xpc_dictionary_set_fd(bootstrapMessage
.get(), "prefmap", prefMapFd
);
1420 xpc_dictionary_set_fd(bootstrapMessage
.get(), "channel", ipcFd
);
1422 // Setup stdout and stderr to inherit.
1423 xpc_dictionary_set_fd(bootstrapMessage
.get(), "stdout", STDOUT_FILENO
);
1424 xpc_dictionary_set_fd(bootstrapMessage
.get(), "stderr", STDERR_FILENO
);
1426 DarwinObjectPtr
<xpc_object_t
> argsArray
=
1427 AdoptDarwinObject(xpc_array_create_empty());
1428 for (auto& argv
: mChildArgv
) {
1429 xpc_array_set_string(argsArray
.get(), XPC_ARRAY_APPEND
, argv
.c_str());
1431 MOZ_ASSERT(xpc_array_get_count(argsArray
.get()) == mChildArgv
.size());
1432 xpc_dictionary_set_value(bootstrapMessage
.get(), "argv", argsArray
.get());
1434 auto promise
= MakeRefPtr
<ProcessHandlePromise::Private
>(__func__
);
1435 ExtensionKitProcess::StartProcess(kind
, [self
= RefPtr
{this}, promise
,
1437 std::move(bootstrapMessage
)](
1438 Result
<ExtensionKitProcess
,
1439 LaunchError
>&& result
) {
1440 if (result
.isErr()) {
1441 CHROMIUM_LOG(ERROR
) << "ExtensionKitProcess::StartProcess failed";
1442 promise
->Reject(result
.unwrapErr(), __func__
);
1446 auto process
= result
.unwrap();
1447 self
->mResults
.mForegroundCapabilityGrant
=
1448 process
.GrantForegroundCapability();
1449 self
->mResults
.mXPCConnection
= process
.MakeLibXPCConnection();
1450 self
->mResults
.mExtensionKitProcess
= Some(std::move(process
));
1452 // We don't actually use the event handler for anything other than
1453 // watching for errors. Once the promise is resolved, this becomes a
1455 xpc_connection_set_event_handler(self
->mResults
.mXPCConnection
.get(), ^(
1456 xpc_object_t event
) {
1457 if (!event
|| xpc_get_type(event
) == XPC_TYPE_ERROR
) {
1458 CHROMIUM_LOG(WARNING
) << "XPC connection received encountered an error";
1459 promise
->Reject(LaunchError("xpc_connection_event_handler"), __func__
);
1462 xpc_connection_resume(self
->mResults
.mXPCConnection
.get());
1464 // Send our bootstrap message to the content and wait for it to reply with
1465 // the task port before resolving.
1466 // FIXME: Should we have a time-out for if the child process doesn't respond
1467 // in time? The main thread may be blocked while we're starting this
1469 xpc_connection_send_message_with_reply(
1470 self
->mResults
.mXPCConnection
.get(), bootstrapMessage
.get(), nullptr,
1471 ^(xpc_object_t reply
) {
1472 if (xpc_get_type(reply
) == XPC_TYPE_ERROR
) {
1474 << "Got error sending XPC bootstrap message to child";
1476 LaunchError("xpc_connection_send_message_with_reply error"),
1481 if (xpc_get_type(reply
) != XPC_TYPE_DICTIONARY
) {
1483 << "Unexpected reply type for bootstrap message from child";
1486 "xpc_connection_send_message_with_reply non-dictionary"),
1491 // FIXME: We have to trust the child to tell us its pid & mach task.
1492 // WebKit uses `xpc_connection_get_pid` to get the pid, however this
1493 // is marked as unavailable on iOS.
1495 // Given how the process is started, however, validating this
1496 // information it sends us this early during startup may be
1498 self
->mResults
.mChildTask
=
1499 xpc_dictionary_copy_mach_send(reply
, "task");
1501 static_cast<pid_t
>(xpc_dictionary_get_int64(reply
, "pid"));
1502 CHROMIUM_LOG(INFO
) << "ExtensionKit process started, task: "
1503 << self
->mResults
.mChildTask
<< ", pid: " << pid
;
1506 kern_return_t kr
= pid_for_task(self
->mResults
.mChildTask
, &taskPid
);
1507 if (kr
!= KERN_SUCCESS
|| pid
!= taskPid
) {
1508 CHROMIUM_LOG(ERROR
) << "Could not validate child task matches pid";
1509 promise
->Reject(LaunchError("pid_for_task mismatch"), __func__
);
1513 promise
->Resolve(pid
, __func__
);
1522 Result
<Ok
, LaunchError
> MacProcessLauncher::DoFinishLaunch() {
1523 Result
<Ok
, LaunchError
> aError
= PosixProcessLauncher::DoFinishLaunch();
1524 if (aError
.isErr()) {
1528 MOZ_ASSERT(mParentRecvPort
, "should have been configured during DoSetup()");
1530 // Wait for the child process to send us its 'task_t' data.
1531 const int kTimeoutMs
= 10000;
1533 mozilla::UniqueMachSendRight child_task
;
1534 audit_token_t audit_token
{};
1535 kern_return_t kr
= MachReceivePortSendRight(
1536 mParentRecvPort
, mozilla::Some(kTimeoutMs
), &child_task
, &audit_token
);
1537 if (kr
!= KERN_SUCCESS
) {
1538 std::string errString
= StringPrintf("0x%x %s", kr
, mach_error_string(kr
));
1539 CHROMIUM_LOG(ERROR
) << "parent MachReceivePortSendRight failed: "
1541 return Err(LaunchError("MachReceivePortSendRight", kr
));
1544 // Ensure the message was sent by the newly spawned child process.
1545 if (audit_token_to_pid(audit_token
) != base::GetProcId(mResults
.mHandle
)) {
1546 CHROMIUM_LOG(ERROR
) << "task_t was not sent by child process";
1547 return Err(LaunchError("audit_token_to_pid"));
1550 // Ensure the task_t corresponds to the newly spawned child process.
1551 pid_t task_pid
= -1;
1552 kr
= pid_for_task(child_task
.get(), &task_pid
);
1553 if (kr
!= KERN_SUCCESS
) {
1554 CHROMIUM_LOG(ERROR
) << "pid_for_task failed: " << mach_error_string(kr
);
1555 return Err(LaunchError("pid_for_task", kr
));
1557 if (task_pid
!= base::GetProcId(mResults
.mHandle
)) {
1558 CHROMIUM_LOG(ERROR
) << "task_t is not for child process";
1559 return Err(LaunchError("task_pid"));
1562 mResults
.mChildTask
= child_task
.release();
1569 void WindowsProcessLauncher::AddApplicationPrefetchArgument() {
1570 // The Application Launch Prefetcher (ALPF) is an ill-documented Windows
1571 // subsystem that's intended to speed up process launching, apparently mostly
1572 // by assuming that a binary is going to want to load the same DLLs as it did
1573 // the last time it launched, and getting those prepped for loading as well.
1575 // For most applications, that's a good bet. For Firefox, it's less so, since
1576 // we use the same binary with different arguments to do completely different
1577 // things. Windows does allow applications to take up multiple slots in this
1578 // cache, but the "which bucket does this invocation go in?" mechanism is
1579 // highly unusual: the OS scans the command line and looks for a command-line
1580 // switch of a particular form.
1582 // (There is allegedly a way to do this without involving the command line,
1583 // OVERRIDE_PREFETCH_PARAMETER, but it's even more poorly documented.)
1585 // Applications' different prefetch-cache buckets are named with numbers from
1586 // "1" to some OS-version-determined limit, with an additional implicit "0"
1587 // cache bucket which is used when no valid prefetch cache slot is named.
1589 // (The "0" bucket's existence and behavior is not documented, but has been
1590 // confirmed by observing the creation and enumeration of cache files in the
1591 // C:\Windows\Prefetch folder.)
1592 static size_t const kMaxSlotNo
= IsWin1122H2OrLater() ? 16 : 8;
1594 // Determine the prefetch-slot number to be used for the process we're about
1597 // This may be changed freely between Firefox versions, as a Firefox update
1598 // will completely invalidate the prefetch cache anyway.
1599 size_t const prefetchSlot
= [&]() -> size_t {
1600 switch (mProcessType
) {
1601 // This code path is not used when starting the main process...
1602 case GeckoProcessType_Default
:
1603 // ...ForkServer is not used on Windows...
1604 case GeckoProcessType_ForkServer
:
1605 // ..."End" isn't a process-type, just a limit...
1606 case GeckoProcessType_End
:
1607 // ...and any new process-types should be considered explicitly here.
1609 MOZ_ASSERT_UNREACHABLE("Invalid process type");
1612 // We reserve 1 for the main process as started by the launcher process.
1613 // (See LauncherProcessWin.cpp.) Otherwise, we mostly match the process-
1614 // type enumeration.
1615 case GeckoProcessType_Content
:
1617 case GeckoProcessType_Socket
:
1618 return 3; // usurps IPDLUnitTest
1619 case GeckoProcessType_GMPlugin
:
1621 case GeckoProcessType_GPU
:
1623 case GeckoProcessType_RemoteSandboxBroker
:
1624 return 6; // usurps VR
1625 case GeckoProcessType_RDD
:
1628 case GeckoProcessType_Utility
: {
1629 // Continue the enumeration, using the SandboxingKind as a
1630 // probably-passably-precise proxy for the process's purpose.
1632 // (On Win10 and earlier, or when sandboxing is not used, this will lump
1633 // all utility processes into slot 8.)
1634 # ifndef MOZ_SANDBOX
1635 size_t const val
= 0;
1637 size_t const val
= static_cast<size_t>(mSandbox
);
1639 return std::min(kMaxSlotNo
, 8 + val
);
1642 // These process types are started so rarely that we're not concerned
1643 // about their interaction with the prefetch cache. Lump them together at
1644 // the end (possibly alongside other process types).
1645 case GeckoProcessType_IPDLUnitTest
:
1646 case GeckoProcessType_VR
:
1650 MOZ_ASSERT(prefetchSlot
<= kMaxSlotNo
);
1652 if (prefetchSlot
== 0) {
1653 // default; no explicit argument needed
1657 mCmdLine
->AppendLooseValue(StringPrintf(L
"/prefetch:%zu", prefetchSlot
));
1660 Result
<Ok
, LaunchError
> WindowsProcessLauncher::DoSetup() {
1661 Result
<Ok
, LaunchError
> aError
= BaseProcessLauncher::DoSetup();
1662 if (aError
.isErr()) {
1667 BinPathType pathType
= GetPathToBinary(exePath
, mProcessType
);
1669 # if defined(MOZ_SANDBOX) || defined(_ARM64_)
1670 const bool isGMP
= mProcessType
== GeckoProcessType_GMPlugin
;
1671 const bool isWidevine
= isGMP
&& Contains(mExtraOpts
, "gmp-widevinecdm");
1672 # if defined(_ARM64_)
1673 bool useRemoteSandboxBroker
= false;
1674 if (mLaunchArch
& (base::PROCESS_ARCH_I386
| base::PROCESS_ARCH_X86_64
)) {
1675 // On Windows on ARM64 for ClearKey and Widevine, and for the sandbox
1676 // launcher process, we want to run the x86 plugin-container.exe in
1677 // the "i686" subdirectory, instead of the aarch64 plugin-container.exe.
1678 // So insert "i686" into the exePath.
1679 exePath
= exePath
.DirName().AppendASCII("i686").Append(exePath
.BaseName());
1680 useRemoteSandboxBroker
=
1681 mProcessType
!= GeckoProcessType_RemoteSandboxBroker
;
1683 # endif // if defined(_ARM64_)
1684 # endif // defined(MOZ_SANDBOX) || defined(_ARM64_)
1686 mCmdLine
.emplace(exePath
.ToWStringHack());
1688 if (pathType
== BinPathType::Self
) {
1689 mCmdLine
->AppendLooseValue(UTF8ToWide("-contentproc"));
1692 # ifdef HAS_DLL_BLOCKLIST
1693 if (IsDynamicBlocklistDisabled(
1695 CommandLine::ForCurrentProcess()->HasSwitch(UTF8ToWide(
1696 mozilla::geckoargs::sDisableDynamicDllBlocklist
.sMatch
)))) {
1697 mCmdLine
->AppendLooseValue(
1698 UTF8ToWide(mozilla::geckoargs::sDisableDynamicDllBlocklist
.sMatch
));
1700 # endif // HAS_DLL_BLOCKLIST
1702 // Inherit the initial client channel handle into the child process.
1703 std::wstring processChannelID
=
1704 std::to_wstring(uint32_t(uintptr_t(mClientChannelHandle
.get())));
1705 mLaunchOptions
->handles_to_inherit
.push_back(mClientChannelHandle
.get());
1706 mCmdLine
->AppendSwitchWithValue(switches::kProcessChannelID
,
1709 for (std::vector
<std::string
>::iterator it
= mExtraOpts
.begin();
1710 it
!= mExtraOpts
.end(); ++it
) {
1711 mCmdLine
->AppendLooseValue(UTF8ToWide(*it
));
1714 # if defined(MOZ_SANDBOX)
1715 # if defined(_ARM64_)
1716 if (useRemoteSandboxBroker
)
1717 mResults
.mSandboxBroker
= new RemoteSandboxBroker(mLaunchArch
);
1719 # endif // if defined(_ARM64_)
1720 mResults
.mSandboxBroker
= new SandboxBroker();
1722 // XXX: Bug 1124167: We should get rid of the process specific logic for
1723 // sandboxing in this class at some point. Unfortunately it will take a bit
1724 // of reorganizing so I don't think this patch is the right time.
1725 switch (mProcessType
) {
1726 case GeckoProcessType_Content
:
1727 if (mSandboxLevel
> 0) {
1728 // For now we treat every failure as fatal in
1729 // SetSecurityLevelForContentProcess and just crash there right away.
1730 // Should this change in the future then we should also handle the error
1732 mResults
.mSandboxBroker
->SetSecurityLevelForContentProcess(
1733 mSandboxLevel
, mIsFileContent
);
1737 case GeckoProcessType_IPDLUnitTest
:
1738 // XXX: We don't sandbox this process type yet
1740 case GeckoProcessType_GMPlugin
:
1741 if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
1742 // The Widevine CDM on Windows can only load at USER_RESTRICTED,
1743 // not at USER_LOCKDOWN. So look in the command line arguments
1744 // to see if we're loading the path to the Widevine CDM, and if
1745 // so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
1747 isWidevine
? SandboxBroker::Restricted
: SandboxBroker::LockDown
;
1749 !mResults
.mSandboxBroker
->SetSecurityLevelForGMPlugin(level
))) {
1750 return Err(LaunchError("SetSecurityLevelForGMPlugin"));
1755 case GeckoProcessType_GPU
:
1756 if (mSandboxLevel
> 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) {
1757 // For now we treat every failure as fatal in
1758 // SetSecurityLevelForGPUProcess and just crash there right away. Should
1759 // this change in the future then we should also handle the error here.
1760 mResults
.mSandboxBroker
->SetSecurityLevelForGPUProcess(mSandboxLevel
);
1764 case GeckoProcessType_VR
:
1765 if (mSandboxLevel
> 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
1766 // TODO: Implement sandbox for VR process, Bug 1430043.
1769 case GeckoProcessType_RDD
:
1770 if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
1772 !mResults
.mSandboxBroker
->SetSecurityLevelForRDDProcess())) {
1773 return Err(LaunchError("SetSecurityLevelForRDDProcess"));
1778 case GeckoProcessType_Socket
:
1779 if (!PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS_SANDBOX")) {
1781 !mResults
.mSandboxBroker
->SetSecurityLevelForSocketProcess())) {
1782 return Err(LaunchError("SetSecurityLevelForSocketProcess"));
1787 case GeckoProcessType_Utility
:
1788 if (IsUtilitySandboxEnabled(mSandbox
)) {
1789 if (!mResults
.mSandboxBroker
->SetSecurityLevelForUtilityProcess(
1791 return Err(LaunchError("SetSecurityLevelForUtilityProcess"));
1796 case GeckoProcessType_RemoteSandboxBroker
:
1797 // We don't sandbox the sandbox launcher...
1799 case GeckoProcessType_Default
:
1801 MOZ_CRASH("Bad process type in GeckoChildProcessHost");
1806 for (auto it
= mAllowedFilesRead
.begin(); it
!= mAllowedFilesRead
.end();
1808 mResults
.mSandboxBroker
->AllowReadFile(it
->c_str());
1811 if (mResults
.mSandboxBroker
->IsWin32kLockedDown()) {
1812 mCmdLine
->AppendLooseValue(
1813 UTF8ToWide(geckoargs::sWin32kLockedDown
.Name()));
1816 # endif // defined(MOZ_SANDBOX)
1818 // Add the application directory path (-appdir path)
1819 AddAppDirToCommandLine(mCmdLine
.ref(), mAppDir
);
1821 // XXX Command line params past this point are expected to be at
1822 // the end of the command line string, and in a specific order.
1823 // See XRE_InitChildProcess in nsEmbedFunction.
1826 mCmdLine
->AppendLooseValue(mGroupId
.get());
1828 // Initial MessageChannel id
1829 mCmdLine
->AppendLooseValue(UTF8ToWide(mInitialChannelIdString
));
1832 mCmdLine
->AppendLooseValue(UTF8ToWide(mPidString
));
1834 mCmdLine
->AppendLooseValue(
1835 UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
1838 mCmdLine
->AppendLooseValue(UTF8ToWide(ChildProcessType()));
1840 // Prefetch cache hint
1841 AddApplicationPrefetchArgument();
1845 // Mark the handles to inherit as inheritable.
1846 for (HANDLE h
: mLaunchOptions
->handles_to_inherit
) {
1847 mResults
.mSandboxBroker
->AddHandleToShare(h
);
1850 # endif // MOZ_SANDBOX
1855 RefPtr
<ProcessHandlePromise
> WindowsProcessLauncher::DoLaunch() {
1856 ProcessHandle handle
= 0;
1859 const IMAGE_THUNK_DATA
* cachedNtdllThunk
=
1860 mCachedNtdllThunk
? mCachedNtdllThunk
->begin() : nullptr;
1861 Result
<Ok
, LaunchError
> err
= mResults
.mSandboxBroker
->LaunchApp(
1862 mCmdLine
->program().c_str(), mCmdLine
->command_line_string().c_str(),
1863 mLaunchOptions
->env_map
, mProcessType
, mEnableSandboxLogging
,
1864 cachedNtdllThunk
, &handle
);
1866 EnvironmentLog("MOZ_PROCESS_LOG")
1867 .print("==> process %d launched child process %d (%S)\n",
1868 base::GetCurrentProcId(), base::GetProcId(handle
),
1869 mCmdLine
->command_line_string().c_str());
1870 return ProcessHandlePromise::CreateAndResolve(handle
, __func__
);
1872 return ProcessHandlePromise::CreateAndReject(err
.unwrapErr(), __func__
);
1874 # endif // defined(MOZ_SANDBOX)
1876 Result
<Ok
, LaunchError
> launchErr
=
1877 base::LaunchApp(mCmdLine
.ref(), *mLaunchOptions
, &handle
);
1878 if (launchErr
.isErr()) {
1879 return ProcessHandlePromise::CreateAndReject(launchErr
.unwrapErr(),
1882 return ProcessHandlePromise::CreateAndResolve(handle
, __func__
);
1885 Result
<Ok
, LaunchError
> WindowsProcessLauncher::DoFinishLaunch() {
1886 Result
<Ok
, LaunchError
> err
= BaseProcessLauncher::DoFinishLaunch();
1895 RefPtr
<ProcessLaunchPromise
> BaseProcessLauncher::FinishLaunch() {
1896 Result
<Ok
, LaunchError
> aError
= DoFinishLaunch();
1897 if (aError
.isErr()) {
1898 return ProcessLaunchPromise::CreateAndReject(aError
.unwrapErr(), __func__
);
1901 MOZ_DIAGNOSTIC_ASSERT(mResults
.mHandle
);
1903 Telemetry::AccumulateTimeDelta(Telemetry::CHILD_PROCESS_LAUNCH_MS
,
1906 return ProcessLaunchPromise::CreateAndResolve(std::move(mResults
), __func__
);
1909 bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid
) {
1910 if (mChildProcessHandle
) {
1911 MOZ_ASSERT(aPid
== base::GetProcId(mChildProcessHandle
));
1915 return base::OpenPrivilegedProcessHandle(aPid
, &mChildProcessHandle
);
1918 void GeckoChildProcessHost::OnChannelConnected(base::ProcessId peer_pid
) {
1920 mozilla::AutoWriteLock
hLock(mHandleLock
);
1921 if (!OpenPrivilegedHandle(peer_pid
)) {
1922 MOZ_CRASH("can't open handle to child process");
1925 MonitorAutoLock
lock(mMonitor
);
1926 mProcessState
= PROCESS_CONNECTED
;
1930 RefPtr
<ProcessHandlePromise
> GeckoChildProcessHost::WhenProcessHandleReady() {
1931 MOZ_ASSERT(mHandlePromise
!= nullptr);
1932 return mHandlePromise
;
1935 #ifdef MOZ_WIDGET_ANDROID
1936 RefPtr
<ProcessHandlePromise
> AndroidProcessLauncher::LaunchAndroidService(
1937 const GeckoProcessType aType
, const std::vector
<std::string
>& argv
,
1938 const base::file_handle_mapping_vector
& fds_to_remap
) {
1939 MOZ_RELEASE_ASSERT((2 <= fds_to_remap
.size()) && (fds_to_remap
.size() <= 5));
1940 JNIEnv
* const env
= mozilla::jni::GetEnvForThread();
1943 const int argvSize
= argv
.size();
1944 jni::ObjectArray::LocalRef jargs
=
1945 jni::ObjectArray::New
<jni::String
>(argvSize
);
1946 for (int ix
= 0; ix
< argvSize
; ix
++) {
1947 jargs
->SetElement(ix
, jni::StringParam(argv
[ix
].c_str(), env
));
1950 // XXX: this processing depends entirely on the internals of
1951 // ContentParent::LaunchSubprocess()
1952 // GeckoChildProcessHost::PerformAsyncLaunch(), and the order in
1953 // which they append to fds_to_remap. There must be a better way to do it.
1955 int32_t prefsFd
= fds_to_remap
[0].first
;
1956 int32_t prefMapFd
= fds_to_remap
[1].first
;
1957 int32_t ipcFd
= fds_to_remap
[2].first
;
1958 int32_t crashFd
= -1;
1959 if (fds_to_remap
.size() == 4) {
1960 crashFd
= fds_to_remap
[3].first
;
1963 auto type
= java::GeckoProcessType::FromInt(aType
);
1964 auto genericResult
= java::GeckoProcessManager::Start(
1965 type
, jargs
, prefsFd
, prefMapFd
, ipcFd
, crashFd
);
1966 auto typedResult
= java::GeckoResult::LocalRef(std::move(genericResult
));
1967 return ProcessHandlePromise::FromGeckoResult(typedResult
);
1971 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1972 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector
& aArgs
) {
1973 MacSandboxInfo info
;
1974 if (NS_WARN_IF(!FillMacSandboxInfo(info
))) {
1977 info
.AppendAsParams(aArgs
);
1981 // Fill |aInfo| with the flags needed to launch the utility sandbox
1982 bool GeckoChildProcessHost::FillMacSandboxInfo(MacSandboxInfo
& aInfo
) {
1983 aInfo
.type
= GetDefaultMacSandboxType();
1984 aInfo
.shouldLog
= Preferences::GetBool("security.sandbox.logging.enabled") ||
1985 PR_GetEnv("MOZ_SANDBOX_LOGGING");
1987 nsAutoCString appPath
;
1988 if (!nsMacUtilsImpl::GetAppPath(appPath
)) {
1989 MOZ_CRASH("Failed to get app path");
1991 aInfo
.appPath
.assign(appPath
.get());
1995 void GeckoChildProcessHost::DisableOSActivityMode() {
1996 mDisableOSActivityMode
= true;
2000 // If early sandbox startup is enabled for this process type, map the
2001 // process type to the sandbox type and enable the sandbox. Returns true
2002 // if no errors were encountered or if early sandbox startup is not
2003 // enabled for this process. Returns false if an error was encountered.
2006 bool GeckoChildProcessHost::StartMacSandbox(int aArgc
, char** aArgv
,
2007 std::string
& aErrorMessage
) {
2008 MacSandboxType sandboxType
= MacSandboxType_Invalid
;
2009 switch (XRE_GetProcessType()) {
2010 // For now, only support early sandbox startup for content,
2011 // RDD, and GMP processes. Add case statements for the additional
2012 // process types once early sandbox startup is implemented for them.
2013 case GeckoProcessType_Content
:
2014 // Content processes don't use GeckoChildProcessHost
2015 // to configure sandboxing so hard code the sandbox type.
2016 sandboxType
= MacSandboxType_Content
;
2018 case GeckoProcessType_RDD
:
2019 sandboxType
= RDDProcessHost::GetMacSandboxType();
2021 case GeckoProcessType_Socket
:
2022 sandboxType
= net::SocketProcessHost::GetMacSandboxType();
2024 case GeckoProcessType_GMPlugin
:
2025 sandboxType
= gmp::GMPProcessParent::GetMacSandboxType();
2027 case GeckoProcessType_Utility
:
2028 sandboxType
= ipc::UtilityProcessHost::GetMacSandboxType();
2034 return mozilla::StartMacSandboxIfEnabled(sandboxType
, aArgc
, aArgv
,
2038 #endif /* XP_MACOSX && MOZ_SANDBOX */
2041 void GeckoChildProcessHost::GetAll(const GeckoProcessCallback
& aCallback
) {
2042 StaticMutexAutoLock
lock(sMutex
);
2043 if (!sGeckoChildProcessHosts
) {
2046 for (GeckoChildProcessHost
* gp
= sGeckoChildProcessHosts
->getFirst(); gp
;
2047 gp
= static_cast<mozilla::LinkedListElement
<GeckoChildProcessHost
>*>(gp
)
2053 RefPtr
<ProcessLaunchPromise
> BaseProcessLauncher::Launch(
2054 GeckoChildProcessHost
* aHost
) {
2057 // The ForkServer doesn't use IPC::Channel for communication, so we can skip
2059 if (mProcessType
!= GeckoProcessType_ForkServer
) {
2060 IPC::Channel::ChannelHandle serverHandle
;
2061 if (!IPC::Channel::CreateRawPipe(&serverHandle
, &mClientChannelHandle
)) {
2062 return ProcessLaunchPromise::CreateAndReject(LaunchError("CreateRawPipe"),
2065 aHost
->InitializeChannel(std::move(serverHandle
));
2068 return InvokeAsync(mLaunchThread
, this, __func__
,
2069 &BaseProcessLauncher::PerformAsyncLaunch
);
2073 } // namespace mozilla