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