Bug 1885602 - Part 4: Implement navigating to the settings from the menu header for...
[gecko.git] / ipc / glue / GeckoChildProcessHost.cpp
blob3090a9ee92dd606598b0969d524b944829489fd3
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"
16 #ifdef XP_DARWIN
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"
22 #endif
23 #ifdef MOZ_WIDGET_COCOA
24 # include <bsm/libbsm.h>
25 # include <servers/bootstrap.h>
26 # include "nsILocalFileMac.h"
27 #endif
29 #include "GeckoProfiler.h"
30 #include "MainThreadUtils.h"
31 #include "mozilla/Preferences.h"
32 #include "mozilla/Sprintf.h"
33 #include "nsXPCOMPrivate.h"
34 #include "prenv.h"
35 #include "prerror.h"
37 #if defined(MOZ_SANDBOX)
38 # include "mozilla/SandboxSettings.h"
39 # include "nsAppDirectoryServiceDefs.h"
40 #endif
42 #include <sys/stat.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"
64 #include "nsIFile.h"
65 #include "nsIObserverService.h"
66 #include "nsPrintfCString.h"
68 #ifdef XP_WIN
69 # include <stdlib.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"
79 # if defined(_ARM64_)
80 # include "mozilla/remoteSandboxBroker.h"
81 # endif
82 # endif
84 # include "mozilla/NativeNt.h"
85 # include "mozilla/CacheNtDllThunk.h"
86 #endif
88 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
89 # include "mozilla/SandboxLaunch.h"
90 #endif
92 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
93 # include "GMPProcessParent.h"
94 # include "nsMacUtilsImpl.h"
95 #endif
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"
118 #endif
120 #ifdef MOZ_ENABLE_FORKSERVER
121 # include "mozilla/ipc/ForkServiceChild.h"
122 #endif
124 static bool ShouldHaveDirectoryService() {
125 return GeckoProcessType_Default == XRE_GetProcessType();
128 namespace mozilla {
129 namespace ipc {
131 struct LaunchResults {
132 base::ProcessHandle mHandle = 0;
133 #ifdef XP_DARWIN
134 task_t mChildTask = MACH_PORT_NULL;
135 #endif
136 #ifdef XP_IOS
137 Maybe<ExtensionKitProcess> mExtensionKitProcess;
138 DarwinObjectPtr<xpc_connection_t> mXPCConnection;
139 UniqueBEProcessCapabilityGrant mForegroundCapabilityGrant;
140 #endif
141 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
142 RefPtr<AbstractSandboxBroker> mSandboxBroker;
143 #endif
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 {
155 public:
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)),
161 #ifdef XP_WIN
162 mGroupId(aHost->mGroupId),
163 #endif
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),
170 #endif
171 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
172 mDisableOSActivityMode(aHost->mDisableOSActivityMode),
173 #endif
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();
181 mLaunchThread =
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.
187 mozilla::Unused
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;
199 #endif
201 RefPtr<ProcessLaunchPromise> Launch(GeckoChildProcessHost*);
203 protected:
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;
230 #endif
231 std::vector<std::string> mExtraOpts;
232 #ifdef XP_WIN
233 nsString mGroupId;
234 #endif
235 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
236 std::vector<std::wstring> mAllowedFilesRead;
237 int32_t mSandboxLevel;
238 SandboxingKind mSandbox;
239 bool mIsFileContent;
240 bool mEnableSandboxLogging;
241 #endif
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;
246 #endif
247 nsCString mTmpDirName;
248 LaunchResults mResults = LaunchResults();
249 int32_t mChildId;
250 TimeStamp mStartTimeStamp = TimeStamp::Now();
251 char mPidString[32];
252 char mInitialChannelIdString[NSID_LENGTH];
254 // Set during launch.
255 IPC::Channel::ChannelHandle mClientChannelHandle;
256 nsCOMPtr<nsIFile> mAppDir;
259 #ifdef XP_WIN
260 class WindowsProcessLauncher final : public BaseProcessLauncher {
261 public:
262 WindowsProcessLauncher(GeckoChildProcessHost* aHost,
263 std::vector<std::string>&& aExtraOpts)
264 : BaseProcessLauncher(aHost, std::move(aExtraOpts)),
265 mCachedNtdllThunk(GetCachedNtDllThunk()) {}
267 protected:
268 virtual Result<Ok, LaunchError> DoSetup() override;
269 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
270 virtual Result<Ok, LaunchError> DoFinishLaunch() override;
272 private:
273 void AddApplicationPrefetchArgument();
275 mozilla::Maybe<CommandLine> mCmdLine;
276 # ifdef MOZ_SANDBOX
277 bool mUseSandbox = false;
278 # endif
280 const Buffer<IMAGE_THUNK_DATA>* mCachedNtdllThunk;
282 typedef WindowsProcessLauncher ProcessLauncher;
283 #endif // XP_WIN
285 #ifdef XP_UNIX
286 class PosixProcessLauncher : public BaseProcessLauncher {
287 public:
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()) {}
294 protected:
295 virtual Result<Ok, LaunchError> DoSetup() override;
296 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
298 nsCOMPtr<nsIFile> mProfileDir;
300 std::vector<std::string> mChildArgv;
301 int mChannelDstFd;
304 # if defined(XP_MACOSX)
305 class MacProcessLauncher : public PosixProcessLauncher {
306 public:
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.
313 mMachConnectionName(
314 StringPrintf("org.mozilla.machname.%d",
315 base::RandInt(0, std::numeric_limits<int>::max()))) {
316 MOZ_ASSERT(mMachConnectionName.size() < BOOTSTRAP_MAX_NAME_LEN);
319 protected:
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 {
332 public:
333 AndroidProcessLauncher(GeckoChildProcessHost* aHost,
334 std::vector<std::string>&& aExtraOpts)
335 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
337 protected:
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 {
350 public:
351 LinuxProcessLauncher(GeckoChildProcessHost* aHost,
352 std::vector<std::string>&& aExtraOpts)
353 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
355 protected:
356 virtual Result<Ok, LaunchError> DoSetup() override;
358 typedef LinuxProcessLauncher ProcessLauncher;
359 # elif defined(MOZ_WIDGET_UIKIT)
360 class IosProcessLauncher : public PosixProcessLauncher {
361 public:
362 IosProcessLauncher(GeckoChildProcessHost* aHost,
363 std::vector<std::string>&& aExtraOpts)
364 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
366 protected:
367 virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
369 DarwinObjectPtr<xpc_object_t> mBootstrapMessage;
371 typedef IosProcessLauncher ProcessLauncher;
372 # else
373 # error "Unknown platform"
374 # endif
375 #endif // XP_UNIX
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,
387 bool aIsFileContent)
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),
394 #ifdef XP_WIN
395 mGroupId(u"-"),
396 #endif
397 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
398 mEnableSandboxLogging(false),
399 mSandboxLevel(0),
400 #endif
401 mHandleLock("mozilla.ipc.GeckoChildProcessHost.mHandleLock"),
402 mChildProcessHandle(0),
403 #if defined(XP_DARWIN)
404 mChildTask(MACH_PORT_NULL),
405 #endif
406 #if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
407 mDisableOSActivityMode(false),
408 #endif
409 mDestroying(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);
426 # endif
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";
438 #endif
439 #if defined(MOZ_ENABLE_FORKSERVER)
440 if (aProcessType != GeckoProcessType_ForkServer && ForkServiceChild::Get()) {
441 mLaunchOptions->use_forkserver = true;
443 #endif
446 GeckoChildProcessHost::~GeckoChildProcessHost()
449 AssertIOThread();
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);
460 #endif
461 #if defined(XP_IOS)
462 if (mForegroundCapabilityGrant) {
463 mForegroundCapabilityGrant.reset();
465 if (mExtensionKitProcess) {
466 mExtensionKitProcess->Invalidate();
468 if (mXPCConnection) {
469 xpc_connection_cancel(mXPCConnection.get());
471 #endif
473 if (mChildProcessHandle != 0) {
474 ProcessWatcher::EnsureProcessTerminated(
475 mChildProcessHandle
476 #ifdef NS_FREE_PERMANENT_DATA
477 // If we're doing leak logging, shutdown can be slow.
479 false // don't "force"
480 #endif
482 mChildProcessHandle = 0;
486 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
487 if (mSandboxBroker) {
488 mSandboxBroker->Shutdown();
489 mSandboxBroker = nullptr;
491 #endif
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) {
502 return 0;
504 return base::GetProcId(mChildProcessHandle);
507 #ifdef XP_DARWIN
508 task_t GeckoChildProcessHost::GetChildTask() {
509 mozilla::AutoReadLock handleLock(mHandleLock);
510 return mChildTask;
512 #endif
514 void GeckoChildProcessHost::RemoveFromProcessList() {
515 StaticMutexAutoLock lock(sMutex);
516 if (!sGeckoChildProcessHosts) {
517 return;
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;
529 if (!whenReady) {
530 // AsyncLaunch not called yet, so dispatch immediately.
531 whenReady = ProcessHandlePromise::CreateAndReject(
532 LaunchError("DestroyEarly"), __func__);
535 using Value = ProcessHandlePromise::ResolveOrRejectValue;
536 mDestroying = true;
537 whenReady->Then(XRE_GetIOMessageLoop()->SerialEventTarget(), __func__,
538 [this](const Value&) { delete this; });
541 // static
542 mozilla::BinPathType BaseProcessLauncher::GetPathToBinary(
543 FilePath& exePath, GeckoProcessType processType) {
544 BinPathType pathType = XRE_GetChildProcBinPathType(processType);
546 if (pathType == BinPathType::Self) {
547 #if defined(XP_WIN)
548 wchar_t exePathBuf[MAXPATHLEN];
549 if (!::GetModuleFileNameW(nullptr, exePathBuf, MAXPATHLEN)) {
550 MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
552 exePath = FilePath::FromWStringHack(exePathBuf);
553 #else
554 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
555 #endif
556 return pathType;
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;
569 } else {
570 bundleName = MOZ_CHILD_PROCESS_BUNDLENAME;
571 executableLeafName = MOZ_CHILD_PROCESS_NAME;
573 #endif
575 if (ShouldHaveDirectoryService()) {
576 MOZ_ASSERT(gGREBinPath);
577 #ifdef XP_WIN
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);
589 nsCString tempCPath;
590 childProcPath->GetNativePath(tempCPath);
591 exePath = FilePath(tempCPath.get());
592 #else
593 nsCString path;
594 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
595 exePath = FilePath(path.get());
596 #endif
599 if (exePath.empty()) {
600 #ifdef XP_WIN
601 exePath =
602 FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
603 #else
604 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
605 #endif
606 exePath = exePath.DirName();
609 #ifdef MOZ_WIDGET_COCOA
610 exePath = exePath.Append(executableLeafName);
611 #else
612 exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
613 #endif
615 return pathType;
618 #ifdef MOZ_WIDGET_COCOA
619 class AutoCFTypeObject {
620 public:
621 explicit AutoCFTypeObject(CFTypeRef object) { mObject = object; }
622 ~AutoCFTypeObject() { ::CFRelease(mObject); }
624 private:
625 CFTypeRef mObject;
627 #endif
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;
633 /* static */
634 uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID++; }
636 /* static */
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());
650 #endif
652 #ifdef XP_WIN
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
659 // thread
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);
684 # endif
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");
693 # endif
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));
701 # endif
702 #endif
705 #ifdef XP_WIN
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);
711 if (taskbarInfo) {
712 bool isSupported = false;
713 taskbarInfo->GetAvailable(&isSupported);
714 nsAutoString appId;
715 if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
716 MOZ_ASSERT(mGroupId.EqualsLiteral("-"));
717 mGroupId.Assign(appId);
721 #endif
723 bool GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts,
724 int aTimeoutMs) {
725 if (!AsyncLaunch(std::move(aExtraOpts))) {
726 return false;
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) {
739 PrepareLaunch();
741 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
742 if (IsMacSandboxLaunchEnabled() && !AppendMacSandboxParams(aExtraOpts)) {
743 return false;
745 #endif
747 RefPtr<BaseProcessLauncher> launcher =
748 new ProcessLauncher(this, std::move(aExtraOpts));
749 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH
750 launcher->SetLaunchArchitecture(mLaunchArch);
751 #endif
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);
757 mHandlePromise =
758 mozilla::InvokeAsync<GeckoChildProcessHost*>(
759 IOThread(), launcher.get(), __func__, &BaseProcessLauncher::Launch,
760 this)
761 ->Then(
762 IOThread(), __func__,
763 [this](LaunchResults&& aResults) {
766 mozilla::AutoWriteLock handleLock(mHandleLock);
767 if (!OpenPrivilegedHandle(base::GetProcId(aResults.mHandle))
768 #ifdef XP_WIN
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 |
776 SYNCHRONIZE,
777 FALSE, 0)
778 #endif // XP_WIN
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;
789 #ifdef XP_DARWIN
790 this->mChildTask = aResults.mChildTask;
791 #endif
792 #ifdef XP_IOS
793 this->mExtensionKitProcess = aResults.mExtensionKitProcess;
794 this->mXPCConnection = aResults.mXPCConnection;
795 this->mForegroundCapabilityGrant =
796 std::move(aResults.mForegroundCapabilityGrant);
797 #endif
799 if (mNodeChannel) {
800 mNodeChannel->SetOtherPid(
801 base::GetProcId(this->mChildProcessHandle));
802 #ifdef XP_DARWIN
803 mNodeChannel->SetMachTaskPort(this->mChildTask);
804 #endif
807 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
808 this->mSandboxBroker = std::move(aResults.mSandboxBroker);
809 #endif
811 MonitorAutoLock lock(mMonitor);
812 // The OnChannel{Connected,Error} may have already advanced
813 // the state.
814 if (mProcessState < PROCESS_CREATED) {
815 mProcessState = PROCESS_CREATED;
817 lock.Notify();
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.
825 CHROMIUM_LOG(ERROR)
826 << "Failed to launch "
827 << XRE_GeckoProcessTypeToString(mProcessType)
828 << " subprocess @" << aError.FunctionName()
829 << " (Error:" << aError.ErrorCode() << ")";
830 Telemetry::Accumulate(
831 Telemetry::SUBPROCESS_LAUNCH_FAILURE,
832 nsDependentCString(
833 XRE_GeckoProcessTypeToString(mProcessType)));
834 nsCString telemetryKey = nsPrintfCString(
835 #if defined(XP_WIN)
836 "%s,0x%lx,%s",
837 #else
838 "%s,%d,%s",
839 #endif
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",
846 telemetryKey.get())
847 .get());
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;
857 lock.Notify();
859 return ProcessHandlePromise::CreateAndReject(aError, __func__);
861 return true;
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
868 // class.
869 TimeDuration timeout = (aTimeoutMs > 0)
870 ? TimeDuration::FromMilliseconds(aTimeoutMs)
871 : TimeDuration::Forever();
873 MonitorAutoLock lock(mMonitor);
874 TimeStamp waitStart = TimeStamp::Now();
875 TimeStamp current;
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) {
882 break;
885 CVStatus status = lock.Wait(timeout);
886 if (status == CVStatus::Timeout) {
887 break;
890 if (timeout != TimeDuration::Forever()) {
891 current = TimeStamp::Now();
892 timeout -= current - waitStart;
893 waitStart = current;
897 return mProcessState == PROCESS_CONNECTED;
900 bool GeckoChildProcessHost::WaitForProcessHandle() {
901 MonitorAutoLock lock(mMonitor);
902 while (mProcessState < PROCESS_CREATED) {
903 lock.Wait();
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))) {
913 return false;
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
921 // process.
922 mozilla::UniquePtr<IPC::Channel> channel = MakeUnique<IPC::Channel>(
923 std::move(aServerHandle), IPC::Channel::MODE_SERVER,
924 base::kInvalidProcessId);
925 #if defined(XP_WIN)
926 channel->StartAcceptingHandles(IPC::Channel::MODE_SERVER);
927 #elif defined(XP_DARWIN)
928 channel->StartAcceptingMachPorts(IPC::Channel::MODE_SERVER);
929 #endif
931 mNodeController = NodeController::GetSingleton();
932 std::tie(mInitialPort, mNodeChannel) =
933 mNodeController->InviteChildProcess(std::move(channel), this);
935 MonitorAutoLock lock(mMonitor);
936 mProcessState = CHANNEL_INITIALIZED;
937 lock.Notify();
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) {
952 #ifdef XP_WIN
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);
959 } else
960 #endif
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
979 // code.
981 // Android also needs a single dedicated thread to simplify thread
982 // safety in java.
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 {
994 public:
995 NS_DECL_ISUPPORTS
996 NS_DECL_NSIOBSERVER
997 protected:
998 virtual ~IPCLaunchThreadObserver() = default;
1001 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver, nsIObserver, nsISupports)
1003 NS_IMETHODIMP
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));
1015 return 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);
1030 }));
1031 gIPCLaunchThread = thread.forget();
1035 nsCOMPtr<nsIEventTarget> thread = gIPCLaunchThread.get();
1036 MOZ_DIAGNOSTIC_ASSERT(thread);
1037 return 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);
1049 return pool;
1052 #endif // XP_WIN || MOZ_WIDGET_ANDROID || MOZ_ENABLE_FORKSERVER
1054 void
1055 #if defined(XP_WIN)
1056 AddAppDirToCommandLine(CommandLine& aCmdLine, nsIFile* aAppDir)
1057 #else
1058 AddAppDirToCommandLine(std::vector<std::string>& aCmdLine, nsIFile* aAppDir,
1059 nsIFile* aProfileDir)
1060 #endif
1062 // Content processes need access to application resources, so pass
1063 // the full application directory path to the child process.
1064 if (aAppDir) {
1065 #if defined(XP_WIN)
1066 nsString path;
1067 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetPath(path));
1068 aCmdLine.AppendLooseValue(UTF8ToWide(geckoargs::sAppDir.Name()));
1069 std::wstring wpath(path.get());
1070 aCmdLine.AppendLooseValue(wpath);
1071 #else
1072 nsAutoCString path;
1073 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetNativePath(path));
1074 geckoargs::sAppDir.Put(path.get(), aCmdLine);
1075 #endif
1077 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1078 // Full path to the profile dir
1079 if (aProfileDir) {
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();
1086 nsAutoCString path;
1087 MOZ_ALWAYS_SUCCEEDS(aProfileDir->GetNativePath(path));
1088 geckoargs::sProfile.Put(path.get(), aCmdLine);
1090 #endif
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);
1127 #ifdef MOZ_MEMORY
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());
1135 #endif
1137 MapChildLogging();
1139 return Ok();
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
1171 // to crash).
1172 mClientChannelHandle = nullptr;
1174 return Ok();
1177 #if defined(MOZ_WIDGET_GTK)
1178 Result<Ok, LaunchError> LinuxProcessLauncher::DoSetup() {
1179 Result<Ok, LaunchError> aError = PosixProcessLauncher::DoSetup();
1180 if (aError.isErr()) {
1181 return aError;
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
1190 // anyway.
1191 mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
1194 # ifdef MOZ_SANDBOX
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
1206 return Ok();
1208 #endif // MOZ_WIDGET_GTK
1210 #ifdef XP_UNIX
1211 Result<Ok, LaunchError> PosixProcessLauncher::DoSetup() {
1212 Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup();
1213 if (aError.isErr()) {
1214 return aError;
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);
1223 nsCString path;
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();
1236 # elif XP_MACOSX
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)
1264 # endif
1267 FilePath exePath;
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);
1278 # endif
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.
1299 nsAutoCString path;
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)
1312 # ifdef XP_MACOSX
1313 AddAppDirToCommandLine(mChildArgv, mAppDir, mProfileDir);
1314 # else
1315 AddAppDirToCommandLine(mChildArgv, mAppDir, nullptr);
1316 # endif
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");
1338 } else {
1339 // "false" == crash reporting disabled
1340 mChildArgv.push_back("false");
1342 # endif
1345 # ifdef MOZ_WIDGET_COCOA
1347 auto* thisMac = static_cast<MacProcessLauncher*>(this);
1348 kern_return_t kr =
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());
1361 return Ok();
1363 #endif // XP_UNIX
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
1372 #ifdef XP_UNIX
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__);
1382 #endif // XP_UNIX
1384 #ifdef XP_IOS
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",
1399 "bootstrap");
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(),
1405 envValue.c_str());
1407 xpc_dictionary_set_value(bootstrapMessage.get(), "environ",
1408 environDict.get());
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.
1414 // See bug 1440207.
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,
1436 bootstrapMessage =
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__);
1443 return;
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
1454 // no-op.
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
1468 // process.
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) {
1473 CHROMIUM_LOG(ERROR)
1474 << "Got error sending XPC bootstrap message to child";
1475 promise->Reject(
1476 LaunchError("xpc_connection_send_message_with_reply error"),
1477 __func__);
1478 return;
1481 if (xpc_get_type(reply) != XPC_TYPE_DICTIONARY) {
1482 CHROMIUM_LOG(ERROR)
1483 << "Unexpected reply type for bootstrap message from child";
1484 promise->Reject(
1485 LaunchError(
1486 "xpc_connection_send_message_with_reply non-dictionary"),
1487 __func__);
1488 return;
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
1497 // unnecessary.
1498 self->mResults.mChildTask =
1499 xpc_dictionary_copy_mach_send(reply, "task");
1500 pid_t pid =
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;
1505 pid_t taskPid;
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__);
1510 return;
1513 promise->Resolve(pid, __func__);
1517 return promise;
1519 #endif
1521 #ifdef XP_MACOSX
1522 Result<Ok, LaunchError> MacProcessLauncher::DoFinishLaunch() {
1523 Result<Ok, LaunchError> aError = PosixProcessLauncher::DoFinishLaunch();
1524 if (aError.isErr()) {
1525 return aError;
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: "
1540 << errString;
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();
1564 return Ok();
1566 #endif // XP_MACOSX
1568 #ifdef XP_WIN
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
1595 // to launch.
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.
1608 default:
1609 MOZ_ASSERT_UNREACHABLE("Invalid process type");
1610 return 0;
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:
1616 return 2;
1617 case GeckoProcessType_Socket:
1618 return 3; // usurps IPDLUnitTest
1619 case GeckoProcessType_GMPlugin:
1620 return 4;
1621 case GeckoProcessType_GPU:
1622 return 5;
1623 case GeckoProcessType_RemoteSandboxBroker:
1624 return 6; // usurps VR
1625 case GeckoProcessType_RDD:
1626 return 7;
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;
1636 # else
1637 size_t const val = static_cast<size_t>(mSandbox);
1638 # endif
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:
1647 return kMaxSlotNo;
1649 }();
1650 MOZ_ASSERT(prefetchSlot <= kMaxSlotNo);
1652 if (prefetchSlot == 0) {
1653 // default; no explicit argument needed
1654 return;
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()) {
1663 return aError;
1666 FilePath exePath;
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(
1694 gSafeMode,
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,
1707 processChannelID);
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);
1718 else
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
1731 // here.
1732 mResults.mSandboxBroker->SetSecurityLevelForContentProcess(
1733 mSandboxLevel, mIsFileContent);
1734 mUseSandbox = true;
1736 break;
1737 case GeckoProcessType_IPDLUnitTest:
1738 // XXX: We don't sandbox this process type yet
1739 break;
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.
1746 auto level =
1747 isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
1748 if (NS_WARN_IF(
1749 !mResults.mSandboxBroker->SetSecurityLevelForGMPlugin(level))) {
1750 return Err(LaunchError("SetSecurityLevelForGMPlugin"));
1752 mUseSandbox = true;
1754 break;
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);
1761 mUseSandbox = true;
1763 break;
1764 case GeckoProcessType_VR:
1765 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
1766 // TODO: Implement sandbox for VR process, Bug 1430043.
1768 break;
1769 case GeckoProcessType_RDD:
1770 if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
1771 if (NS_WARN_IF(
1772 !mResults.mSandboxBroker->SetSecurityLevelForRDDProcess())) {
1773 return Err(LaunchError("SetSecurityLevelForRDDProcess"));
1775 mUseSandbox = true;
1777 break;
1778 case GeckoProcessType_Socket:
1779 if (!PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS_SANDBOX")) {
1780 if (NS_WARN_IF(
1781 !mResults.mSandboxBroker->SetSecurityLevelForSocketProcess())) {
1782 return Err(LaunchError("SetSecurityLevelForSocketProcess"));
1784 mUseSandbox = true;
1786 break;
1787 case GeckoProcessType_Utility:
1788 if (IsUtilitySandboxEnabled(mSandbox)) {
1789 if (!mResults.mSandboxBroker->SetSecurityLevelForUtilityProcess(
1790 mSandbox)) {
1791 return Err(LaunchError("SetSecurityLevelForUtilityProcess"));
1793 mUseSandbox = true;
1795 break;
1796 case GeckoProcessType_RemoteSandboxBroker:
1797 // We don't sandbox the sandbox launcher...
1798 break;
1799 case GeckoProcessType_Default:
1800 default:
1801 MOZ_CRASH("Bad process type in GeckoChildProcessHost");
1802 break;
1805 if (mUseSandbox) {
1806 for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end();
1807 ++it) {
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.
1825 // Win app model id
1826 mCmdLine->AppendLooseValue(mGroupId.get());
1828 // Initial MessageChannel id
1829 mCmdLine->AppendLooseValue(UTF8ToWide(mInitialChannelIdString));
1831 // Process id
1832 mCmdLine->AppendLooseValue(UTF8ToWide(mPidString));
1834 mCmdLine->AppendLooseValue(
1835 UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
1837 // Process type
1838 mCmdLine->AppendLooseValue(UTF8ToWide(ChildProcessType()));
1840 // Prefetch cache hint
1841 AddApplicationPrefetchArgument();
1843 # ifdef MOZ_SANDBOX
1844 if (mUseSandbox) {
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
1852 return Ok();
1855 RefPtr<ProcessHandlePromise> WindowsProcessLauncher::DoLaunch() {
1856 ProcessHandle handle = 0;
1857 # ifdef MOZ_SANDBOX
1858 if (mUseSandbox) {
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);
1865 if (err.isOk()) {
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(),
1880 __func__);
1882 return ProcessHandlePromise::CreateAndResolve(handle, __func__);
1885 Result<Ok, LaunchError> WindowsProcessLauncher::DoFinishLaunch() {
1886 Result<Ok, LaunchError> err = BaseProcessLauncher::DoFinishLaunch();
1887 if (err.isErr()) {
1888 return err;
1891 return Ok();
1893 #endif // XP_WIN
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,
1904 mStartTimeStamp);
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));
1912 return true;
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;
1927 lock.Notify();
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();
1941 MOZ_ASSERT(env);
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.
1954 // See bug 1440207.
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);
1969 #endif
1971 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
1972 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector& aArgs) {
1973 MacSandboxInfo info;
1974 if (NS_WARN_IF(!FillMacSandboxInfo(info))) {
1975 return false;
1977 info.AppendAsParams(aArgs);
1978 return true;
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());
1992 return true;
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.
2005 /* static */
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;
2017 break;
2018 case GeckoProcessType_RDD:
2019 sandboxType = RDDProcessHost::GetMacSandboxType();
2020 break;
2021 case GeckoProcessType_Socket:
2022 sandboxType = net::SocketProcessHost::GetMacSandboxType();
2023 break;
2024 case GeckoProcessType_GMPlugin:
2025 sandboxType = gmp::GMPProcessParent::GetMacSandboxType();
2026 break;
2027 case GeckoProcessType_Utility:
2028 sandboxType = ipc::UtilityProcessHost::GetMacSandboxType();
2029 break;
2030 default:
2031 return true;
2034 return mozilla::StartMacSandboxIfEnabled(sandboxType, aArgc, aArgv,
2035 aErrorMessage);
2038 #endif /* XP_MACOSX && MOZ_SANDBOX */
2040 /* static */
2041 void GeckoChildProcessHost::GetAll(const GeckoProcessCallback& aCallback) {
2042 StaticMutexAutoLock lock(sMutex);
2043 if (!sGeckoChildProcessHosts) {
2044 return;
2046 for (GeckoChildProcessHost* gp = sGeckoChildProcessHosts->getFirst(); gp;
2047 gp = static_cast<mozilla::LinkedListElement<GeckoChildProcessHost>*>(gp)
2048 ->getNext()) {
2049 aCallback(gp);
2053 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::Launch(
2054 GeckoChildProcessHost* aHost) {
2055 AssertIOThread();
2057 // The ForkServer doesn't use IPC::Channel for communication, so we can skip
2058 // initializing it.
2059 if (mProcessType != GeckoProcessType_ForkServer) {
2060 IPC::Channel::ChannelHandle serverHandle;
2061 if (!IPC::Channel::CreateRawPipe(&serverHandle, &mClientChannelHandle)) {
2062 return ProcessLaunchPromise::CreateAndReject(LaunchError("CreateRawPipe"),
2063 __func__);
2065 aHost->InitializeChannel(std::move(serverHandle));
2068 return InvokeAsync(mLaunchThread, this, __func__,
2069 &BaseProcessLauncher::PerformAsyncLaunch);
2072 } // namespace ipc
2073 } // namespace mozilla