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