GeckoChildProcessHost.cpp (68864B)
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/process.h" 11 #include "base/process_util.h" 12 #include "base/string_util.h" 13 #include "base/task.h" 14 #include "chrome/common/chrome_switches.h" 15 #include "chrome/common/process_watcher.h" 16 #ifdef XP_DARWIN 17 # include <mach/mach_traps.h> 18 # include "base/rand_util.h" 19 # include "chrome/common/mach_ipc_mac.h" 20 # include "mozilla/StaticPrefs_layers.h" 21 # include "mozilla/StaticPrefs_media.h" 22 #endif 23 #ifdef MOZ_WIDGET_COCOA 24 # include <bsm/libbsm.h> 25 # include <servers/bootstrap.h> 26 # include "nsILocalFileMac.h" 27 #endif 28 29 #include "GeckoProfiler.h" 30 #include "MainThreadUtils.h" 31 #include "mozilla/Preferences.h" 32 #include "mozilla/Sprintf.h" 33 #include "nsXPCOMPrivate.h" 34 #include "prenv.h" 35 #include "prerror.h" 36 37 #if defined(MOZ_SANDBOX) 38 # include "mozilla/SandboxSettings.h" 39 # include "nsAppDirectoryServiceDefs.h" 40 #endif 41 42 #include "ProtocolUtils.h" 43 #include "mozilla/LinkedList.h" 44 #include "mozilla/Logging.h" 45 #include "mozilla/Maybe.h" 46 #include "mozilla/GeckoArgs.h" 47 #include "mozilla/Omnijar.h" 48 #include "mozilla/RDDProcessHost.h" 49 #include "mozilla/Services.h" 50 #include "mozilla/SharedThreadPool.h" 51 #include "mozilla/StaticMutex.h" 52 #include "mozilla/TaskQueue.h" 53 #include "mozilla/glean/DomMetrics.h" 54 #include "mozilla/glean/IpcMetrics.h" 55 #include "mozilla/UniquePtrExtensions.h" 56 #include "mozilla/ipc/IOThread.h" 57 #include "mozilla/ipc/EnvironmentMap.h" 58 #include "mozilla/ipc/NodeController.h" 59 #include "mozilla/net/SocketProcessHost.h" 60 #include "nsDirectoryService.h" 61 #include "nsDirectoryServiceDefs.h" 62 #include "nsExceptionHandler.h" 63 #include "nsIFile.h" 64 #include "nsIObserverService.h" 65 #include "nsPrintfCString.h" 66 67 #ifdef XP_WIN 68 # include <stdlib.h> 69 70 # include "nsIWinTaskbar.h" 71 # define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1" 72 73 # if defined(MOZ_SANDBOX) 74 # include "WinUtils.h" 75 # include "mozilla/Preferences.h" 76 # include "mozilla/sandboxing/sandboxLogging.h" 77 # endif 78 79 # include "mozilla/NativeNt.h" 80 # include "mozilla/CacheNtDllThunk.h" 81 #endif 82 83 #if defined(XP_LINUX) && defined(MOZ_SANDBOX) 84 # include "mozilla/SandboxLaunch.h" 85 #endif 86 87 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) 88 # include "GMPProcessParent.h" 89 # include "nsMacUtilsImpl.h" 90 # include "mozilla/gfx/GPUProcessHost.h" 91 #endif 92 93 #include "mozilla/ipc/UtilityProcessHost.h" 94 #include "mozilla/ipc/UtilityProcessSandboxing.h" 95 96 #include "nsClassHashtable.h" 97 #include "nsHashKeys.h" 98 #include "nsNativeCharsetUtils.h" 99 #include "nsTArray.h" 100 #include "nscore.h" // for NS_FREE_PERMANENT_DATA 101 #include "nsIThread.h" 102 103 using mozilla::MonitorAutoLock; 104 using mozilla::Preferences; 105 using mozilla::StaticMutexAutoLock; 106 107 #ifdef MOZ_WIDGET_ANDROID 108 # include "AndroidBridge.h" 109 # include "mozilla/java/GeckoProcessManagerWrappers.h" 110 # include "mozilla/java/GeckoProcessTypeWrappers.h" 111 # include "mozilla/java/GeckoResultWrappers.h" 112 # include "mozilla/jni/Refs.h" 113 # include "mozilla/jni/Utils.h" 114 #endif 115 116 #ifdef MOZ_ENABLE_FORKSERVER 117 # include "mozilla/ipc/ForkServiceChild.h" 118 #endif 119 120 static bool ShouldHaveDirectoryService() { 121 return GeckoProcessType_Default == XRE_GetProcessType(); 122 } 123 124 #ifdef XP_IOS 125 // Hack to ensure environment variables are copied into child processes on iOS. 126 extern char** environ; 127 #endif 128 129 namespace mozilla { 130 namespace ipc { 131 132 struct LaunchResults { 133 base::ProcessHandle mHandle = 0; 134 #ifdef XP_MACOSX 135 task_t mChildTask = MACH_PORT_NULL; 136 #endif 137 #ifdef XP_IOS 138 Maybe<ExtensionKitProcess> mExtensionKitProcess; 139 DarwinObjectPtr<xpc_connection_t> mXPCConnection; 140 UniqueBEProcessCapabilityGrant mForegroundCapabilityGrant; 141 #endif 142 #if defined(XP_WIN) && defined(MOZ_SANDBOX) 143 UniquePtr<SandboxBroker> mSandboxBroker; 144 #endif 145 }; 146 typedef mozilla::MozPromise<LaunchResults, LaunchError, true> 147 ProcessLaunchPromise; 148 149 // Monotonic counter used to generate a unique ChildID for each process as it is 150 // created. The parent process is given the ChildID of `0`, and each child 151 // process is given a non-zero ID. 152 static Atomic<int32_t> gChildCounter; 153 154 class BaseProcessLauncher { 155 public: 156 BaseProcessLauncher(GeckoChildProcessHost* aHost, 157 geckoargs::ChildProcessArgs&& aExtraOpts) 158 : mProcessType(aHost->mProcessType), 159 mLaunchOptions(std::move(aHost->mLaunchOptions)), 160 mChildArgs(std::move(aExtraOpts)) 161 #ifdef XP_WIN 162 , 163 mGroupId(aHost->mGroupId) 164 #endif 165 #if defined(XP_WIN) && defined(MOZ_SANDBOX) 166 , 167 mAllowedFilesRead(aHost->mAllowedFilesRead), 168 mSandboxLevel(aHost->mSandboxLevel), 169 mSandbox(aHost->mSandbox), 170 mIsFileContent(aHost->mIsFileContent), 171 mEnableSandboxLogging(aHost->mEnableSandboxLogging) 172 #endif 173 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) 174 , 175 mDisableOSActivityMode(aHost->mDisableOSActivityMode) 176 #endif 177 { 178 aHost->mInitialChannelId.ToProvidedString(mInitialChannelIdString); 179 SprintfLiteral(mChildIDString, "%d", aHost->mChildID); 180 181 // Compute the serial event target we'll use for launching. 182 nsCOMPtr<nsIEventTarget> threadOrPool = GetIPCLauncher(); 183 mLaunchThread = 184 TaskQueue::Create(threadOrPool.forget(), "BaseProcessLauncher"); 185 186 if (ShouldHaveDirectoryService()) { 187 // "Current process directory" means the app dir, not the current 188 // working dir or similar. 189 (void)nsDirectoryService::gService->GetCurrentProcessDirectory( 190 getter_AddRefs(mAppDir)); 191 } 192 } 193 194 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseProcessLauncher); 195 196 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH 197 void SetLaunchArchitecture(uint32_t aLaunchArch) { 198 mLaunchArch = aLaunchArch; 199 } 200 #endif 201 202 RefPtr<ProcessLaunchPromise> Launch(GeckoChildProcessHost*); 203 204 protected: 205 virtual ~BaseProcessLauncher() = default; 206 207 RefPtr<ProcessLaunchPromise> PerformAsyncLaunch(); 208 209 // Overrideable hooks. If superclass behavior is invoked, it's always at the 210 // top of the override. 211 virtual Result<Ok, LaunchError> DoSetup(); 212 virtual RefPtr<ProcessLaunchPromise> DoLaunch() = 0; 213 214 void MapChildLogging(); 215 216 static BinPathType GetPathToBinary(FilePath&, GeckoProcessType); 217 218 void GetChildLogName(const char* origLogName, nsACString& buffer); 219 220 const char* ChildProcessType() { 221 return XRE_GeckoProcessTypeToString(mProcessType); 222 } 223 224 nsCOMPtr<nsISerialEventTarget> mLaunchThread; 225 GeckoProcessType mProcessType; 226 UniquePtr<base::LaunchOptions> mLaunchOptions; 227 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH 228 uint32_t mLaunchArch = base::PROCESS_ARCH_INVALID; 229 #endif 230 geckoargs::ChildProcessArgs mChildArgs; 231 #ifdef XP_WIN 232 nsString mGroupId; 233 #endif 234 #if defined(XP_WIN) && defined(MOZ_SANDBOX) 235 std::vector<std::wstring> mAllowedFilesRead; 236 int32_t mSandboxLevel; 237 SandboxingKind mSandbox; 238 bool mIsFileContent; 239 bool mEnableSandboxLogging; 240 #endif 241 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) 242 // Controls whether or not the process will be launched with 243 // environment variable OS_ACTIVITY_MODE set to "disabled". 244 bool mDisableOSActivityMode; 245 #endif 246 LaunchResults mResults = LaunchResults(); 247 char mInitialChannelIdString[NSID_LENGTH]; 248 char mChildIDString[32]; 249 250 // Set during launch. 251 nsCOMPtr<nsIFile> mAppDir; 252 }; 253 254 #ifdef XP_WIN 255 class WindowsProcessLauncher : public BaseProcessLauncher { 256 public: 257 WindowsProcessLauncher(GeckoChildProcessHost* aHost, 258 geckoargs::ChildProcessArgs&& aExtraOpts) 259 : BaseProcessLauncher(aHost, std::move(aExtraOpts)), 260 mCachedNtdllThunk(GetCachedNtDllThunk()) {} 261 262 protected: 263 virtual Result<Ok, LaunchError> DoSetup() override; 264 virtual RefPtr<ProcessLaunchPromise> DoLaunch() override; 265 266 mozilla::Maybe<CommandLine> mCmdLine; 267 # ifdef MOZ_SANDBOX 268 bool mUseSandbox = false; 269 # endif 270 271 const Buffer<IMAGE_THUNK_DATA>* mCachedNtdllThunk; 272 }; 273 typedef WindowsProcessLauncher ProcessLauncher; 274 #endif // XP_WIN 275 276 #ifdef XP_UNIX 277 class PosixProcessLauncher : public BaseProcessLauncher { 278 public: 279 PosixProcessLauncher(GeckoChildProcessHost* aHost, 280 geckoargs::ChildProcessArgs&& aExtraOpts) 281 : BaseProcessLauncher(aHost, std::move(aExtraOpts)), 282 mProfileDir(aHost->mProfileDir) {} 283 284 protected: 285 virtual Result<Ok, LaunchError> DoSetup() override; 286 virtual RefPtr<ProcessLaunchPromise> DoLaunch() override; 287 288 nsCOMPtr<nsIFile> mProfileDir; 289 }; 290 291 # if defined(XP_MACOSX) 292 class MacProcessLauncher : public PosixProcessLauncher { 293 public: 294 MacProcessLauncher(GeckoChildProcessHost* aHost, 295 geckoargs::ChildProcessArgs&& aExtraOpts) 296 : PosixProcessLauncher(aHost, std::move(aExtraOpts)), 297 // Put a random number into the channel name, so that 298 // a compromised renderer can't pretend being the child 299 // that's forked off. 300 mMachConnectionName( 301 StringPrintf("org.mozilla.machname.%d", 302 base::RandInt(0, std::numeric_limits<int>::max()))) { 303 MOZ_ASSERT(mMachConnectionName.size() < BOOTSTRAP_MAX_NAME_LEN); 304 } 305 306 protected: 307 virtual RefPtr<ProcessLaunchPromise> DoLaunch() override; 308 309 std::string mMachConnectionName; 310 // We add a mach port to the command line so the child can communicate its 311 // 'task_t' back to the parent. 312 mozilla::UniqueMachReceiveRight mParentRecvPort; 313 314 friend class PosixProcessLauncher; 315 }; 316 typedef MacProcessLauncher ProcessLauncher; 317 # elif defined(MOZ_WIDGET_ANDROID) 318 class AndroidProcessLauncher : public PosixProcessLauncher { 319 public: 320 AndroidProcessLauncher(GeckoChildProcessHost* aHost, 321 geckoargs::ChildProcessArgs&& aExtraOpts) 322 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {} 323 324 protected: 325 virtual RefPtr<ProcessLaunchPromise> DoLaunch() override; 326 RefPtr<ProcessHandlePromise> LaunchAndroidService( 327 const GeckoProcessType aType, const geckoargs::ChildProcessArgs& args); 328 }; 329 typedef AndroidProcessLauncher ProcessLauncher; 330 // NB: Technically Android is linux (i.e. XP_LINUX is defined), but we want 331 // orthogonal IPC machinery there. Conversely, there are tier-3 non-Linux 332 // platforms (BSD and Solaris) where we want the "linux" IPC machinery. So 333 // we use MOZ_WIDGET_* to choose the platform backend. 334 # elif defined(MOZ_WIDGET_GTK) 335 class LinuxProcessLauncher : public PosixProcessLauncher { 336 public: 337 LinuxProcessLauncher(GeckoChildProcessHost* aHost, 338 geckoargs::ChildProcessArgs&& aExtraOpts) 339 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {} 340 341 protected: 342 virtual Result<Ok, LaunchError> DoSetup() override; 343 }; 344 typedef LinuxProcessLauncher ProcessLauncher; 345 # elif defined(MOZ_WIDGET_UIKIT) 346 class IosProcessLauncher : public PosixProcessLauncher { 347 public: 348 IosProcessLauncher(GeckoChildProcessHost* aHost, 349 geckoargs::ChildProcessArgs&& aExtraOpts) 350 : PosixProcessLauncher(aHost, std::move(aExtraOpts)) {} 351 352 protected: 353 virtual Result<Ok, LaunchError> DoSetup() override; 354 virtual RefPtr<ProcessLaunchPromise> DoLaunch() override; 355 356 DarwinObjectPtr<xpc_object_t> mBootstrapMessage; 357 }; 358 typedef IosProcessLauncher ProcessLauncher; 359 # else 360 # error "Unknown platform" 361 # endif 362 #endif // XP_UNIX 363 364 using base::ProcessHandle; 365 using mozilla::ipc::BaseProcessLauncher; 366 using mozilla::ipc::ProcessLauncher; 367 368 mozilla::StaticAutoPtr<mozilla::LinkedList<GeckoChildProcessHost>> 369 GeckoChildProcessHost::sGeckoChildProcessHosts; 370 371 mozilla::StaticMutex GeckoChildProcessHost::sMutex; 372 373 GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType, 374 bool aIsFileContent) 375 : mProcessType(aProcessType), 376 mChildID(++gChildCounter), 377 mIsFileContent(aIsFileContent), 378 mMonitor("mozilla.ipc.GeckoChildProcessHost.mMonitor"), 379 mLaunchOptions(MakeUnique<base::LaunchOptions>()), 380 mInitialChannelId(nsID::GenerateUUID()), 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 mHandleLock("mozilla.ipc.GeckoChildProcessHost.mHandleLock"), 390 mChildProcessHandle(0), 391 #if defined(XP_MACOSX) 392 mChildTask(MACH_PORT_NULL), 393 #endif 394 #if defined(MOZ_SANDBOX) && defined(XP_MACOSX) 395 mDisableOSActivityMode(false), 396 #endif 397 mDestroying(false) { 398 MOZ_COUNT_CTOR(GeckoChildProcessHost); 399 MOZ_RELEASE_ASSERT(mChildID > 0, "gChildCounter overflowed"); 400 StaticMutexAutoLock lock(sMutex); 401 if (!sGeckoChildProcessHosts) { 402 sGeckoChildProcessHosts = new mozilla::LinkedList<GeckoChildProcessHost>(); 403 } 404 sGeckoChildProcessHosts->insertBack(this); 405 #if defined(MOZ_SANDBOX) && defined(XP_LINUX) 406 if (aProcessType == GeckoProcessType_RDD) { 407 // The RDD process makes limited use of EGL. If Mesa's shader 408 // cache is enabled and the directory isn't explicitly set, then 409 // it will try to getpwuid() the user which can cause problems 410 // with sandboxing. Because we shouldn't need shader caching in 411 // this process, we just disable the cache to prevent that. 412 mLaunchOptions->env_map["MESA_GLSL_CACHE_DISABLE"] = "true"; 413 mLaunchOptions->env_map["MESA_SHADER_CACHE_DISABLE"] = "true"; 414 // In case the nvidia driver is also loaded: 415 mLaunchOptions->env_map["__GL_SHADER_DISK_CACHE"] = "0"; 416 } 417 #endif 418 } 419 420 GeckoChildProcessHost::~GeckoChildProcessHost() { 421 AssertIOThread(); 422 MOZ_RELEASE_ASSERT(mDestroying); 423 424 MOZ_COUNT_DTOR(GeckoChildProcessHost); 425 426 { 427 mozilla::AutoWriteLock hLock(mHandleLock); 428 #if defined(XP_MACOSX) 429 if (mChildTask != MACH_PORT_NULL) { 430 mach_port_deallocate(mach_task_self(), mChildTask); 431 } 432 #endif 433 #if defined(XP_IOS) 434 if (mForegroundCapabilityGrant) { 435 mForegroundCapabilityGrant.reset(); 436 } 437 if (mExtensionKitProcess) { 438 mExtensionKitProcess->Invalidate(); 439 } 440 if (mXPCConnection) { 441 xpc_connection_cancel(mXPCConnection.get()); 442 } 443 #endif 444 445 if (mChildProcessHandle != 0) { 446 ProcessWatcher::EnsureProcessTerminated(mChildProcessHandle); 447 mChildProcessHandle = 0; 448 } 449 } 450 } 451 452 base::ProcessHandle GeckoChildProcessHost::GetChildProcessHandle() { 453 mozilla::AutoReadLock handleLock(mHandleLock); 454 return mChildProcessHandle; 455 } 456 457 base::ProcessId GeckoChildProcessHost::GetChildProcessId() { 458 mozilla::AutoReadLock handleLock(mHandleLock); 459 if (!mChildProcessHandle) { 460 return 0; 461 } 462 return base::GetProcId(mChildProcessHandle); 463 } 464 465 #ifdef XP_MACOSX 466 task_t GeckoChildProcessHost::GetChildTask() { 467 mozilla::AutoReadLock handleLock(mHandleLock); 468 return mChildTask; 469 } 470 #endif 471 472 void GeckoChildProcessHost::RemoveFromProcessList() { 473 StaticMutexAutoLock lock(sMutex); 474 if (!sGeckoChildProcessHosts) { 475 return; 476 } 477 LinkedListElement<GeckoChildProcessHost>::removeFrom( 478 *sGeckoChildProcessHosts); 479 } 480 481 void GeckoChildProcessHost::Destroy() { 482 MOZ_RELEASE_ASSERT(!mDestroying); 483 // We can remove from the list before it's really destroyed 484 RemoveFromProcessList(); 485 RefPtr<ProcessHandlePromise> whenReady = mHandlePromise; 486 487 if (!whenReady) { 488 // AsyncLaunch not called yet, so dispatch immediately. 489 whenReady = ProcessHandlePromise::CreateAndReject( 490 LaunchError("DestroyEarly"), __func__); 491 } 492 493 using Value = ProcessHandlePromise::ResolveOrRejectValue; 494 mDestroying = true; 495 496 // Synchronously invoke `delete this` if we're already shutting the IO thread 497 // down to ensure we're cleaned up before the thread dies. This is safe as we 498 // can never resolve `mHandlePromise` after the IO thread goes away. 499 MessageLoop* loop = MessageLoop::current(); 500 if (loop && MessageLoop::TYPE_IO == loop->type() && 501 !loop->IsAcceptingTasks()) { 502 delete this; 503 return; 504 } 505 506 // If we're not in shutdown, do this async, as we may still be waiting for the 507 // child process PID from the launcher thread. 508 whenReady->Then(XRE_GetAsyncIOEventTarget(), __func__, 509 [this](const Value&) { delete this; }); 510 } 511 512 // static 513 mozilla::BinPathType BaseProcessLauncher::GetPathToBinary( 514 FilePath& exePath, GeckoProcessType processType) { 515 exePath = {}; 516 BinPathType pathType = XRE_GetChildProcBinPathType(processType); 517 518 if (pathType == BinPathType::Self) { 519 #if defined(XP_WIN) 520 wchar_t exePathBuf[MAXPATHLEN]; 521 if (!::GetModuleFileNameW(nullptr, exePathBuf, MAXPATHLEN)) { 522 MOZ_CRASH("GetModuleFileNameW failed (FIXME)"); 523 } 524 exePath = FilePath::FromWStringHack(exePathBuf); 525 #else 526 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]); 527 #endif 528 return pathType; 529 } 530 531 #ifdef MOZ_WIDGET_COCOA 532 // To support different child process types having different codesigning 533 // entitlements, different executables are used to run some child process 534 // types. 535 nsCString bundleName; 536 std::string executableLeafName; 537 if (processType == GeckoProcessType_GMPlugin && 538 mozilla::StaticPrefs::media_plugin_helper_process_enabled()) { 539 // Use the media plugin helper executable 540 bundleName = MOZ_EME_PROCESS_BUNDLENAME; 541 executableLeafName = MOZ_EME_PROCESS_NAME_BRANDED; 542 } else if (processType == GeckoProcessType_GPU && 543 mozilla::StaticPrefs::layers_gpu_process_executable_enabled()) { 544 // Use the GPU helper executable 545 bundleName = MOZ_GPU_PROCESS_BUNDLENAME; 546 executableLeafName = MOZ_GPU_PROCESS_NAME_BRANDED; 547 } else { 548 // the default child process executable 549 bundleName = MOZ_CHILD_PROCESS_BUNDLENAME; 550 executableLeafName = MOZ_CHILD_PROCESS_NAME; 551 } 552 #endif 553 554 if (ShouldHaveDirectoryService()) { 555 MOZ_ASSERT(gGREBinPath); 556 #ifdef XP_WIN 557 exePath = FilePath(char16ptr_t(gGREBinPath)); 558 #elif MOZ_WIDGET_COCOA 559 nsCOMPtr<nsIFile> childProcPath; 560 if (NS_SUCCEEDED(NS_NewLocalFile(nsDependentString(gGREBinPath), 561 getter_AddRefs(childProcPath)))) { 562 // We need to use an App Bundle on OS X so that we can hide 563 // the dock icon. See Bug 557225. 564 if (NS_SUCCEEDED(childProcPath->AppendNative(bundleName)) && 565 NS_SUCCEEDED(childProcPath->AppendNative("Contents"_ns)) && 566 NS_SUCCEEDED(childProcPath->AppendNative("MacOS"_ns))) { 567 nsCString tempCPath; 568 if (NS_SUCCEEDED(childProcPath->GetNativePath(tempCPath))) { 569 exePath = FilePath(tempCPath.get()); 570 } 571 } 572 } 573 #else 574 nsCString path; 575 if (NS_SUCCEEDED( 576 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path))) { 577 exePath = FilePath(path.get()); 578 } 579 #endif 580 } 581 582 if (exePath.empty()) { 583 #ifdef XP_WIN 584 exePath = 585 FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program()); 586 #else 587 exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]); 588 #endif 589 exePath = exePath.DirName(); 590 } 591 592 #ifdef MOZ_WIDGET_COCOA 593 exePath = exePath.Append(executableLeafName); 594 #else 595 exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME); 596 #endif 597 598 return pathType; 599 } 600 601 #ifdef MOZ_WIDGET_COCOA 602 class AutoCFTypeObject { 603 public: 604 explicit AutoCFTypeObject(CFTypeRef object) { mObject = object; } 605 ~AutoCFTypeObject() { ::CFRelease(mObject); } 606 607 private: 608 CFTypeRef mObject; 609 }; 610 #endif 611 612 // We start the unique IDs at 1 so that 0 can be used to mean that 613 // a component has no unique ID assigned to it. 614 uint32_t GeckoChildProcessHost::sNextUniqueID = 1; 615 616 /* static */ 617 uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID++; } 618 619 /* static */ 620 void GeckoChildProcessHost::SetEnv(const char* aKey, const char* aValue) { 621 MOZ_ASSERT(mLaunchOptions); 622 mLaunchOptions->env_map[ENVIRONMENT_STRING(aKey)] = 623 ENVIRONMENT_STRING(aValue); 624 } 625 626 bool GeckoChildProcessHost::PrepareLaunch( 627 geckoargs::ChildProcessArgs& aExtraOpts) { 628 #if defined(XP_LINUX) && defined(MOZ_SANDBOX) 629 if (!SandboxLaunch::Configure(mProcessType, mSandbox, aExtraOpts, 630 mLaunchOptions.get())) { 631 return false; 632 } 633 #endif 634 635 #ifdef XP_WIN 636 637 # if defined(MOZ_SANDBOX) 638 // We need to get the pref here as the process is launched off main thread. 639 if (mProcessType == GeckoProcessType_Content) { 640 // Win32k Lockdown state must be initialized on the main thread. 641 // This is our last chance to do it before it is read on the IPC Launch 642 // thread 643 GetWin32kLockdownState(); 644 mSandboxLevel = GetEffectiveContentSandboxLevel(); 645 mEnableSandboxLogging = 646 Preferences::GetBool("security.sandbox.logging.enabled"); 647 648 // We currently have to whitelist certain paths for tests to work in some 649 // development configurations. 650 nsAutoString readPaths; 651 nsresult rv = Preferences::GetString( 652 "security.sandbox.content.read_path_whitelist", readPaths); 653 if (NS_SUCCEEDED(rv)) { 654 for (const nsAString& readPath : readPaths.Split(',')) { 655 nsString trimmedPath(readPath); 656 trimmedPath.Trim(" ", true, true); 657 std::wstring resolvedPath(trimmedPath.Data()); 658 // Check if path ends with '\' as this indicates we want to give read 659 // access to a directory and so it needs a wildcard. 660 if (resolvedPath.back() == L'\\') { 661 resolvedPath.append(L"*"); 662 } 663 mAllowedFilesRead.push_back(resolvedPath); 664 } 665 } 666 } 667 # endif 668 669 # if defined(MOZ_SANDBOX) 670 // For other process types we can't rely on them being launched on main 671 // thread and they may not have access to prefs in the child process, so allow 672 // them to turn on logging via an environment variable. 673 mEnableSandboxLogging = 674 mEnableSandboxLogging || !!PR_GetEnv("MOZ_SANDBOX_LOGGING"); 675 676 # endif 677 #elif defined(XP_MACOSX) 678 # if defined(MOZ_SANDBOX) 679 if (ShouldHaveDirectoryService() && 680 mProcessType != GeckoProcessType_GMPlugin) { 681 (void)NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, 682 getter_AddRefs(mProfileDir)); 683 } 684 # endif 685 #endif 686 687 return true; 688 } 689 690 #ifdef XP_WIN 691 void GeckoChildProcessHost::InitWindowsGroupID() { 692 // On Win7+, pass the application user model to the child, so it can 693 // register with it. This insures windows created by the container 694 // properly group with the parent app on the Win7 taskbar. 695 nsCOMPtr<nsIWinTaskbar> taskbarInfo = do_GetService(NS_TASKBAR_CONTRACTID); 696 if (taskbarInfo) { 697 bool isSupported = false; 698 taskbarInfo->GetAvailable(&isSupported); 699 nsAutoString appId; 700 if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) { 701 MOZ_ASSERT(mGroupId.EqualsLiteral("-")); 702 mGroupId.Assign(appId); 703 } 704 } 705 } 706 #endif 707 708 bool GeckoChildProcessHost::SyncLaunch(geckoargs::ChildProcessArgs aExtraOpts, 709 int aTimeoutMs) { 710 if (!AsyncLaunch(std::move(aExtraOpts))) { 711 return false; 712 } 713 return WaitUntilConnected(aTimeoutMs); 714 } 715 716 // Note: for most process types, we currently call AsyncLaunch, and therefore 717 // the *ProcessLauncher constructor, on the main thread, while the 718 // ProcessLauncher methods to actually execute the launch are called on the IO 719 // or IPC launcher thread. GMP processes are an exception - the GMP code 720 // invokes GeckoChildProcessHost from non-main-threads, and therefore we cannot 721 // rely on having access to mainthread-only services (like the directory 722 // service) from this code if we're launching that type of process. 723 bool GeckoChildProcessHost::AsyncLaunch( 724 geckoargs::ChildProcessArgs aExtraOpts) { 725 if (!PrepareLaunch(aExtraOpts)) { 726 return false; 727 } 728 729 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) 730 if (IsMacSandboxLaunchEnabled() && 731 !AppendMacSandboxParams(aExtraOpts.mArgs)) { 732 return false; 733 } 734 #endif 735 736 RefPtr<BaseProcessLauncher> launcher = 737 new ProcessLauncher(this, std::move(aExtraOpts)); 738 TimeStamp startTimeStamp = TimeStamp::Now(); 739 #ifdef ALLOW_GECKO_CHILD_PROCESS_ARCH 740 launcher->SetLaunchArchitecture(mLaunchArch); 741 #endif 742 743 // Note: Destroy() waits on mHandlePromise to delete |this|. As such, we want 744 // to be sure that all of our post-launch processing on |this| happens before 745 // mHandlePromise notifies. 746 MOZ_ASSERT(mHandlePromise == nullptr); 747 mHandlePromise = 748 mozilla::InvokeAsync<GeckoChildProcessHost*>( 749 XRE_GetAsyncIOEventTarget(), launcher.get(), __func__, 750 &BaseProcessLauncher::Launch, this) 751 ->Then( 752 XRE_GetAsyncIOEventTarget(), __func__, 753 [this, startTimeStamp](LaunchResults&& aResults) { 754 { 755 { 756 mozilla::AutoWriteLock handleLock(mHandleLock); 757 if (!OpenPrivilegedHandle(base::GetProcId(aResults.mHandle)) 758 #ifdef XP_WIN 759 // If we failed in opening the process handle, try 760 // harder by duplicating one. 761 && !::DuplicateHandle( 762 ::GetCurrentProcess(), aResults.mHandle, 763 ::GetCurrentProcess(), &mChildProcessHandle, 764 PROCESS_DUP_HANDLE | PROCESS_TERMINATE | 765 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | 766 SYNCHRONIZE, 767 FALSE, 0) 768 #endif // XP_WIN 769 ) { 770 MOZ_CRASH("cannot open handle to child process"); 771 } 772 // The original handle is no longer needed; it must 773 // be closed to prevent a resource leak. 774 base::CloseProcessHandle(aResults.mHandle); 775 // FIXME (bug 1720523): define a cross-platform 776 // "safe" invalid value to use in places like this. 777 aResults.mHandle = 0; 778 779 #ifdef XP_MACOSX 780 this->mChildTask = aResults.mChildTask; 781 #endif 782 #ifdef XP_IOS 783 this->mExtensionKitProcess = aResults.mExtensionKitProcess; 784 this->mXPCConnection = aResults.mXPCConnection; 785 this->mForegroundCapabilityGrant = 786 std::move(aResults.mForegroundCapabilityGrant); 787 #endif 788 789 if (mNodeChannel) { 790 mNodeChannel->SetOtherPid( 791 base::GetProcId(this->mChildProcessHandle)); 792 #ifdef XP_MACOSX 793 mNodeChannel->SetMachTaskPort(this->mChildTask); 794 #endif 795 } 796 } 797 #if defined(XP_WIN) && defined(MOZ_SANDBOX) 798 this->mSandboxBroker = std::move(aResults.mSandboxBroker); 799 #endif 800 801 glean::process::child_launch.AccumulateRawDuration( 802 TimeStamp::Now() - startTimeStamp); 803 804 MonitorAutoLock lock(mMonitor); 805 // The OnChannel{Connected,Error} may have already advanced 806 // the state. 807 if (mProcessState < PROCESS_CREATED) { 808 mProcessState = PROCESS_CREATED; 809 } 810 lock.Notify(); 811 } 812 return ProcessHandlePromise::CreateAndResolve( 813 GetChildProcessHandle(), __func__); 814 }, 815 [this](const LaunchError aError) { 816 // WaitUntilConnected might be waiting for us to signal. 817 // If something failed let's set the error state and notify. 818 CHROMIUM_LOG(ERROR) 819 << "Failed to launch " 820 << XRE_GeckoProcessTypeToString(mProcessType) 821 << " subprocess @" << aError.FunctionName() 822 << " (Error:" << aError.ErrorCode() << ")"; 823 glean::subprocess::launch_failure 824 .Get(nsDependentCString( 825 XRE_GeckoProcessTypeToString(mProcessType))) 826 .Add(1); 827 nsCString telemetryKey = nsPrintfCString( 828 #if defined(XP_WIN) 829 "%s,0x%lx,%s", 830 #else 831 "%s,%ld,%s", 832 #endif 833 aError.FunctionName().get(), aError.ErrorCode(), 834 XRE_GeckoProcessTypeToString(mProcessType)); 835 // Max telemetry key is 72 chars 836 // https://searchfox.org/mozilla-central/rev/c244b16815d1fc827d141472b9faac5610f250e7/toolkit/components/telemetry/core/TelemetryScalar.cpp#105 837 if (telemetryKey.Length() > 72) { 838 NS_WARNING(nsPrintfCString("Truncating telemetry key: %s", 839 telemetryKey.get()) 840 .get()); 841 telemetryKey.Truncate(72); 842 } 843 glean::dom_parentprocess::process_launch_errors 844 .Get(telemetryKey) 845 .Add(1); 846 { 847 MonitorAutoLock lock(mMonitor); 848 mProcessState = PROCESS_ERROR; 849 lock.Notify(); 850 } 851 return ProcessHandlePromise::CreateAndReject(aError, __func__); 852 }); 853 return true; 854 } 855 856 bool GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs) { 857 AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER); 858 859 // NB: this uses a different mechanism than the chromium parent 860 // class. 861 TimeDuration timeout = (aTimeoutMs > 0) 862 ? TimeDuration::FromMilliseconds(aTimeoutMs) 863 : TimeDuration::Forever(); 864 865 MonitorAutoLock lock(mMonitor); 866 TimeStamp waitStart = TimeStamp::Now(); 867 TimeStamp current; 868 869 // We'll receive several notifications, we need to exit when we 870 // have either successfully launched or have timed out. 871 while (mProcessState != PROCESS_CONNECTED) { 872 // If there was an error then return it, don't wait out the timeout. 873 if (mProcessState == PROCESS_ERROR) { 874 break; 875 } 876 877 CVStatus status = lock.Wait(timeout); 878 if (status == CVStatus::Timeout) { 879 break; 880 } 881 882 if (timeout != TimeDuration::Forever()) { 883 current = TimeStamp::Now(); 884 timeout -= current - waitStart; 885 waitStart = current; 886 } 887 } 888 889 return mProcessState == PROCESS_CONNECTED; 890 } 891 892 bool GeckoChildProcessHost::WaitForProcessHandle() { 893 MonitorAutoLock lock(mMonitor); 894 while (mProcessState < PROCESS_CREATED) { 895 lock.Wait(); 896 } 897 MOZ_ASSERT(mProcessState == PROCESS_ERROR || GetChildProcessHandle()); 898 899 return mProcessState < PROCESS_ERROR; 900 } 901 902 bool GeckoChildProcessHost::LaunchAndWaitForProcessHandle( 903 geckoargs::ChildProcessArgs aExtraOpts) { 904 if (!AsyncLaunch(std::move(aExtraOpts))) { 905 return false; 906 } 907 return WaitForProcessHandle(); 908 } 909 910 bool GeckoChildProcessHost::InitializeChannel( 911 IPC::Channel::ChannelHandle* aClientHandle) { 912 mNodeController = NodeController::GetSingleton(); 913 if (!mNodeController->InviteChildProcess(this, aClientHandle, &mInitialPort, 914 getter_AddRefs(mNodeChannel))) { 915 return false; 916 } 917 918 MOZ_ASSERT(mInitialPort.IsValid()); 919 MOZ_ASSERT(mNodeChannel); 920 921 MonitorAutoLock lock(mMonitor); 922 mProcessState = CHANNEL_INITIALIZED; 923 lock.Notify(); 924 return true; 925 } 926 927 void GeckoChildProcessHost::SetAlreadyDead() { 928 mozilla::AutoWriteLock handleLock(mHandleLock); 929 if (mChildProcessHandle && 930 mChildProcessHandle != base::kInvalidProcessHandle) { 931 base::CloseProcessHandle(mChildProcessHandle); 932 } 933 934 mChildProcessHandle = 0; 935 } 936 937 void BaseProcessLauncher::GetChildLogName(const char* origLogName, 938 nsACString& buffer) { 939 #ifdef XP_WIN 940 // On Windows we must expand relative paths because sandboxing rules 941 // bound only to full paths. fopen fowards to NtCreateFile which checks 942 // the path against the sanboxing rules as passed to fopen (left relative). 943 char absPath[MAX_PATH + 2]; 944 if (_fullpath(absPath, origLogName, sizeof(absPath))) { 945 buffer.Append(absPath); 946 } else 947 #endif 948 { 949 buffer.Append(origLogName); 950 } 951 952 // Remove .moz_log extension to avoid its duplication, it will be added 953 // automatically by the logging backend 954 static constexpr auto kMozLogExt = nsLiteralCString{MOZ_LOG_FILE_EXTENSION}; 955 if (StringEndsWith(buffer, kMozLogExt)) { 956 buffer.Truncate(buffer.Length() - kMozLogExt.Length()); 957 } 958 959 // Append child-specific postfix to name 960 buffer.AppendLiteral(".child-"); 961 buffer.AppendASCII(mChildIDString); 962 } 963 964 // We use a single dedicated thread for process launching. This is required on 965 // Windows (due to sandboxing code), Android (due to the java code) and Linux 966 // (due to ForkServerChild). Using a single thread is not required on macOS or 967 // iOS, but we use one to keep the implementation consistent. 968 // 969 // The only tier-1 platform where we do not need a dedicated thread is macOS, 970 // however we use a dedicated thread there as well for consistency and 971 // simplicity of implementation. 972 973 static mozilla::StaticMutex gIPCLaunchThreadMutex; 974 static mozilla::StaticRefPtr<nsIThread> gIPCLaunchThread 975 MOZ_GUARDED_BY(gIPCLaunchThreadMutex); 976 977 class IPCLaunchThreadObserver final : public nsIObserver { 978 public: 979 NS_DECL_ISUPPORTS 980 NS_DECL_NSIOBSERVER 981 protected: 982 virtual ~IPCLaunchThreadObserver() = default; 983 }; 984 985 NS_IMPL_ISUPPORTS(IPCLaunchThreadObserver, nsIObserver, nsISupports) 986 987 NS_IMETHODIMP 988 IPCLaunchThreadObserver::Observe(nsISupports* aSubject, const char* aTopic, 989 const char16_t* aData) { 990 MOZ_RELEASE_ASSERT(strcmp(aTopic, "xpcom-shutdown-threads") == 0); 991 992 nsCOMPtr<nsIThread> thread; 993 { 994 StaticMutexAutoLock lock(gIPCLaunchThreadMutex); 995 thread = gIPCLaunchThread.forget(); 996 } 997 998 nsresult rv = thread ? thread->Shutdown() : NS_OK; 999 (void)NS_WARN_IF(NS_FAILED(rv)); 1000 return rv; 1001 } 1002 1003 nsCOMPtr<nsISerialEventTarget> GetIPCLauncher() { 1004 StaticMutexAutoLock lock(gIPCLaunchThreadMutex); 1005 if (!gIPCLaunchThread) { 1006 nsCOMPtr<nsIThread> thread; 1007 nsresult rv = NS_NewNamedThread("IPC Launch"_ns, getter_AddRefs(thread)); 1008 if (!NS_WARN_IF(NS_FAILED(rv))) { 1009 NS_DispatchToMainThread( 1010 NS_NewRunnableFunction("GeckoChildProcessHost::GetIPCLauncher", [] { 1011 nsCOMPtr<nsIObserverService> obsService = 1012 mozilla::services::GetObserverService(); 1013 nsCOMPtr<nsIObserver> obs = new IPCLaunchThreadObserver(); 1014 obsService->AddObserver(obs, "xpcom-shutdown-threads", false); 1015 })); 1016 gIPCLaunchThread = thread.forget(); 1017 } 1018 } 1019 1020 nsCOMPtr<nsISerialEventTarget> thread = gIPCLaunchThread.get(); 1021 MOZ_DIAGNOSTIC_ASSERT(thread); 1022 return thread; 1023 } 1024 1025 void 1026 #if defined(XP_WIN) 1027 AddAppDirToCommandLine(CommandLine& aCmdLine, nsIFile* aAppDir) 1028 #else 1029 AddAppDirToCommandLine(geckoargs::ChildProcessArgs& aCmdLine, 1030 nsIFile* aAppDir, nsIFile* aProfileDir) 1031 #endif 1032 { 1033 // Content processes need access to application resources, so pass 1034 // the full application directory path to the child process. 1035 if (aAppDir) { 1036 #if defined(XP_WIN) 1037 nsString path; 1038 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetPath(path)); 1039 aCmdLine.AppendLooseValue(UTF8ToWide(geckoargs::sAppDir.Name())); 1040 std::wstring wpath(path.get()); 1041 aCmdLine.AppendLooseValue(wpath); 1042 #else 1043 nsAutoCString path; 1044 MOZ_ALWAYS_SUCCEEDS(aAppDir->GetNativePath(path)); 1045 geckoargs::sAppDir.Put(path.get(), aCmdLine); 1046 #endif 1047 1048 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) 1049 // Full path to the profile dir 1050 if (aProfileDir) { 1051 // If the profile doesn't exist, normalization will 1052 // fail. But we don't return an error here because some 1053 // tests require startup with a missing profile dir. 1054 // For users, almost universally, the profile will be in 1055 // the home directory and normalization isn't required. 1056 (void)aProfileDir->Normalize(); 1057 nsAutoCString path; 1058 MOZ_ALWAYS_SUCCEEDS(aProfileDir->GetNativePath(path)); 1059 geckoargs::sProfile.Put(path.get(), aCmdLine); 1060 } 1061 #endif 1062 } 1063 } 1064 1065 #if defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_)) 1066 static bool Contains(const geckoargs::ChildProcessArgs& aExtraOpts, 1067 const char* aValue) { 1068 return std::any_of(aExtraOpts.mArgs.begin(), aExtraOpts.mArgs.end(), 1069 [&](const std::string arg) { 1070 return arg.find(aValue) != std::string::npos; 1071 }); 1072 } 1073 #endif // defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_)) 1074 1075 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::PerformAsyncLaunch() { 1076 Result<Ok, LaunchError> aError = DoSetup(); 1077 if (aError.isErr()) { 1078 return ProcessLaunchPromise::CreateAndReject(aError.unwrapErr(), __func__); 1079 } 1080 return DoLaunch()->Then( 1081 mLaunchThread, __func__, 1082 [self = 1083 RefPtr{this}](ProcessLaunchPromise::ResolveOrRejectValue&& aResult) { 1084 // Explicitly destroy any outstanding references to HANDLEs which may be 1085 // held by mChildArgs before resolving. 1086 // 1087 // NOTE: This is technically redundant, as it will happen naturally as 1088 // the `BaseProcessLauncher` is destroyed, but this step makes it 1089 // explicit. If we leaked one of these HANDLEs, we could fail to detect 1090 // a child process shutting down or crashing. 1091 self->mChildArgs = {}; 1092 return ProcessLaunchPromise::CreateAndResolveOrReject( 1093 std::move(aResult), __func__); 1094 }); 1095 } 1096 1097 Result<Ok, LaunchError> BaseProcessLauncher::DoSetup() { 1098 RefPtr<BaseProcessLauncher> self = this; 1099 GetProfilerEnvVarsForChildProcess([self](const char* key, const char* value) { 1100 self->mLaunchOptions->env_map[ENVIRONMENT_STRING(key)] = 1101 ENVIRONMENT_STRING(value); 1102 }); 1103 #ifdef MOZ_MEMORY 1104 if (mProcessType == GeckoProcessType_Content) { 1105 nsAutoCString mallocOpts(PR_GetEnv("MALLOC_OPTIONS")); 1106 // Disable randomization of small arenas in content. 1107 mallocOpts.Append("r"); 1108 self->mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MALLOC_OPTIONS")] = 1109 ENVIRONMENT_STRING(mallocOpts.get()); 1110 } 1111 #endif 1112 1113 MapChildLogging(); 1114 1115 geckoargs::sInitialChannelID.Put(mInitialChannelIdString, mChildArgs); 1116 1117 geckoargs::sParentPid.Put(static_cast<uint64_t>(base::GetCurrentProcId()), 1118 mChildArgs); 1119 1120 if (!CrashReporter::IsDummy() && CrashReporter::GetEnabled() && 1121 mProcessType != GeckoProcessType_ForkServer) { 1122 #if defined(MOZ_WIDGET_COCOA) || defined(XP_WIN) 1123 geckoargs::sCrashReporter.Put(CrashReporter::GetChildNotificationPipe(), 1124 mChildArgs); 1125 #elif defined(XP_UNIX) && !defined(XP_IOS) 1126 UniqueFileHandle childCrashFd = CrashReporter::GetChildNotificationPipe(); 1127 if (!childCrashFd) { 1128 return Err(LaunchError("DuplicateFileHandle failed")); 1129 } 1130 geckoargs::sCrashReporter.Put(std::move(childCrashFd), mChildArgs); 1131 #endif // XP_UNIX && !XP_IOS 1132 1133 UniqueFileHandle crashHelperClientFd = 1134 CrashReporter::RegisterChildIPCChannel(); 1135 if (crashHelperClientFd) { 1136 geckoargs::sCrashHelper.Put(std::move(crashHelperClientFd), mChildArgs); 1137 } else { 1138 NS_WARNING("Could not create an IPC channel to the crash helper"); 1139 } 1140 } 1141 1142 return Ok(); 1143 } 1144 1145 void BaseProcessLauncher::MapChildLogging() { 1146 const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE"); 1147 const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE"); 1148 1149 if (origNSPRLogName) { 1150 nsAutoCString nsprLogName; 1151 GetChildLogName(origNSPRLogName, nsprLogName); 1152 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("NSPR_LOG_FILE")] = 1153 ENVIRONMENT_STRING(nsprLogName.get()); 1154 } 1155 if (origMozLogName) { 1156 nsAutoCString mozLogName; 1157 GetChildLogName(origMozLogName, mozLogName); 1158 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MOZ_LOG_FILE")] = 1159 ENVIRONMENT_STRING(mozLogName.get()); 1160 } 1161 1162 // `RUST_LOG_CHILD` is meant for logging child processes only. 1163 nsAutoCString childRustLog(PR_GetEnv("RUST_LOG_CHILD")); 1164 if (!childRustLog.IsEmpty()) { 1165 mLaunchOptions->env_map[ENVIRONMENT_LITERAL("RUST_LOG")] = 1166 ENVIRONMENT_STRING(childRustLog.get()); 1167 } 1168 } 1169 1170 #if defined(MOZ_WIDGET_GTK) 1171 Result<Ok, LaunchError> LinuxProcessLauncher::DoSetup() { 1172 Result<Ok, LaunchError> aError = PosixProcessLauncher::DoSetup(); 1173 if (aError.isErr()) { 1174 return aError; 1175 } 1176 1177 if (mProcessType == GeckoProcessType_Content) { 1178 // disable IM module to avoid sandbox violation 1179 mLaunchOptions->env_map["GTK_IM_MODULE"] = "gtk-im-context-simple"; 1180 1181 // Disable ATK accessibility code in content processes because it conflicts 1182 // with the sandbox, and we proxy that information through the main process 1183 // anyway. 1184 mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1"; 1185 } 1186 1187 return Ok(); 1188 } 1189 #endif // MOZ_WIDGET_GTK 1190 1191 #ifdef XP_UNIX 1192 Result<Ok, LaunchError> PosixProcessLauncher::DoSetup() { 1193 Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup(); 1194 if (aError.isErr()) { 1195 return aError; 1196 } 1197 1198 // XPCOM may not be initialized in some subprocesses. We don't want 1199 // to initialize XPCOM just for the directory service, especially 1200 // since LD_LIBRARY_PATH is already set correctly in subprocesses 1201 // (meaning that we don't need to set that up in the environment). 1202 if (ShouldHaveDirectoryService()) { 1203 MOZ_ASSERT(gGREBinPath); 1204 nsCString path; 1205 NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path); 1206 # if defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \ 1207 defined(XP_NETBSD) || defined(XP_OPENBSD) 1208 const char* ld_library_path = PR_GetEnv("LD_LIBRARY_PATH"); 1209 nsCString new_ld_lib_path(path.get()); 1210 1211 if (ld_library_path && *ld_library_path) { 1212 new_ld_lib_path.Append(':'); 1213 new_ld_lib_path.Append(ld_library_path); 1214 } 1215 mLaunchOptions->env_map["LD_LIBRARY_PATH"] = new_ld_lib_path.get(); 1216 1217 # elif XP_MACOSX 1218 // With signed production Mac builds, the dynamic linker (dyld) will 1219 // ignore dyld environment variables preventing the use of variables 1220 // such as DYLD_LIBRARY_PATH and DYLD_INSERT_LIBRARIES. 1221 1222 // If we're running with gtests, add the gtest XUL ahead of normal XUL on 1223 // the DYLD_LIBRARY_PATH so that plugin-container.app loads it instead. 1224 nsCString new_dyld_lib_path(path.get()); 1225 if (PR_GetEnv("MOZ_RUN_GTEST")) { 1226 new_dyld_lib_path = path + "/gtest:"_ns + new_dyld_lib_path; 1227 mLaunchOptions->env_map["DYLD_LIBRARY_PATH"] = new_dyld_lib_path.get(); 1228 } 1229 1230 // DYLD_INSERT_LIBRARIES is currently unused by default but we allow 1231 // it to be set by the external environment. 1232 const char* interpose = PR_GetEnv("DYLD_INSERT_LIBRARIES"); 1233 if (interpose && strlen(interpose) > 0) { 1234 mLaunchOptions->env_map["DYLD_INSERT_LIBRARIES"] = interpose; 1235 } 1236 1237 // Prevent connection attempts to diagnosticd(8) to save cycles. Log 1238 // messages can trigger these connection attempts, but access to 1239 // diagnosticd is blocked in sandboxed child processes. 1240 # if defined(MOZ_SANDBOX) && defined(XP_MACOSX) 1241 if (mDisableOSActivityMode) { 1242 mLaunchOptions->env_map["OS_ACTIVITY_MODE"] = "disable"; 1243 } 1244 # endif // defined(MOZ_SANDBOX) 1245 # endif 1246 } 1247 1248 FilePath exePath; 1249 BinPathType pathType = GetPathToBinary(exePath, mProcessType); 1250 1251 // Make sure the executable path is present at the start of our argument list. 1252 // If we're using BinPathType::Self, also add the `-contentproc` argument. 1253 if (pathType == BinPathType::Self) { 1254 std::string args[]{exePath.value(), "-contentproc"}; 1255 mChildArgs.mArgs.insert(mChildArgs.mArgs.begin(), std::begin(args), 1256 std::end(args)); 1257 } else { 1258 mChildArgs.mArgs.insert(mChildArgs.mArgs.begin(), exePath.value()); 1259 } 1260 1261 if ((mProcessType == GeckoProcessType_Content || 1262 mProcessType == GeckoProcessType_ForkServer) && 1263 Omnijar::IsInitialized()) { 1264 // Make sure that child processes can find the omnijar, if they 1265 // use full XPCOM. See Omnijar::ChildProcessInit and its callers. 1266 nsAutoCString path; 1267 nsCOMPtr<nsIFile> greFile = Omnijar::GetPath(Omnijar::GRE); 1268 if (greFile && NS_SUCCEEDED(greFile->GetNativePath(path))) { 1269 geckoargs::sGREOmni.Put(path.get(), mChildArgs); 1270 } 1271 nsCOMPtr<nsIFile> appFile = Omnijar::GetPath(Omnijar::APP); 1272 if (appFile && NS_SUCCEEDED(appFile->GetNativePath(path))) { 1273 geckoargs::sAppOmni.Put(path.get(), mChildArgs); 1274 } 1275 } 1276 1277 if (mProcessType != GeckoProcessType_GMPlugin) { 1278 // Add the application directory path (-appdir path) 1279 # ifdef XP_MACOSX 1280 AddAppDirToCommandLine(mChildArgs, mAppDir, mProfileDir); 1281 # else 1282 AddAppDirToCommandLine(mChildArgs, mAppDir, nullptr); 1283 # endif 1284 } 1285 1286 // XXX Command line params past this point are expected to be at 1287 // the end of the command line string, and in a specific order. 1288 // See XRE_InitChildProcess in nsEmbedFunction. 1289 1290 # ifdef MOZ_WIDGET_COCOA 1291 { 1292 auto* thisMac = static_cast<MacProcessLauncher*>(this); 1293 kern_return_t kr = 1294 bootstrap_check_in(bootstrap_port, thisMac->mMachConnectionName.c_str(), 1295 getter_Transfers(thisMac->mParentRecvPort)); 1296 if (kr != KERN_SUCCESS) { 1297 CHROMIUM_LOG(ERROR) << "parent bootstrap_check_in failed: " 1298 << mach_error_string(kr); 1299 return Err(LaunchError("bootstrap_check_in", kr)); 1300 } 1301 mChildArgs.mArgs.push_back(thisMac->mMachConnectionName.c_str()); 1302 } 1303 # endif // MOZ_WIDGET_COCOA 1304 1305 mChildArgs.mArgs.push_back(mChildIDString); 1306 1307 mChildArgs.mArgs.push_back(ChildProcessType()); 1308 1309 # ifdef MOZ_ENABLE_FORKSERVER 1310 // Any unexpected fds given to the fork server could be leaked into 1311 // child processes if they aren't closed properly; this assertion is 1312 // a reminder to deal with that. 1313 MOZ_ASSERT(mProcessType != GeckoProcessType_ForkServer || 1314 mChildArgs.mFiles.size() == 2, 1315 "wrong number of FDs for the fork server"); 1316 # endif 1317 1318 # if !defined(MOZ_WIDGET_ANDROID) 1319 // Add any files which need to be transferred to fds_to_remap. 1320 // NOTE: This doesn't transfer ownership of the files out of `mChildArgs`. 1321 geckoargs::AddToFdsToRemap(mChildArgs, mLaunchOptions->fds_to_remap); 1322 # endif 1323 1324 return Ok(); 1325 } 1326 #endif // XP_UNIX 1327 1328 #if defined(MOZ_WIDGET_ANDROID) 1329 RefPtr<ProcessLaunchPromise> AndroidProcessLauncher::DoLaunch() { 1330 return LaunchAndroidService(mProcessType, mChildArgs) 1331 ->Then( 1332 mLaunchThread, __func__, 1333 [self = RefPtr{this}](ProcessHandle aHandle) { 1334 self->mResults.mHandle = aHandle; 1335 return ProcessLaunchPromise::CreateAndResolve( 1336 std::move(self->mResults), __func__); 1337 }, 1338 [](LaunchError aError) { 1339 return ProcessLaunchPromise::CreateAndReject(aError, __func__); 1340 }); 1341 } 1342 #endif // MOZ_WIDGET_ANDROID 1343 1344 #ifdef XP_UNIX 1345 RefPtr<ProcessLaunchPromise> PosixProcessLauncher::DoLaunch() { 1346 Result<Ok, LaunchError> result = Err(LaunchError{"Launch not attempted"}); 1347 # ifdef MOZ_ENABLE_FORKSERVER 1348 if (mProcessType != GeckoProcessType_ForkServer && ForkServiceChild::Get()) { 1349 result = ForkServiceChild::Get()->SendForkNewSubprocess( 1350 std::move(mChildArgs), std::move(*mLaunchOptions), &mResults.mHandle); 1351 } else 1352 # endif 1353 { 1354 result = base::LaunchApp(mChildArgs.mArgs, std::move(*mLaunchOptions), 1355 &mResults.mHandle); 1356 } 1357 1358 if (result.isErr()) { 1359 return ProcessLaunchPromise::CreateAndReject(result.unwrapErr(), __func__); 1360 } 1361 return ProcessLaunchPromise::CreateAndResolve(std::move(mResults), __func__); 1362 } 1363 #endif // XP_UNIX 1364 1365 #ifdef XP_IOS 1366 Result<Ok, LaunchError> IosProcessLauncher::DoSetup() { 1367 Result<Ok, LaunchError> aError = PosixProcessLauncher::DoSetup(); 1368 if (aError.isErr()) { 1369 return aError; 1370 } 1371 1372 // Unlike on other platforms, the child process will not inherit the parent 1373 // process's environment, so we need to manually copy over environment 1374 // variables. 1375 for (char** envp = environ; *envp != 0; ++envp) { 1376 // Only copy over `MOZ_` keys. 1377 if (strncmp(*envp, "MOZ_", 4) != 0) { 1378 continue; 1379 } 1380 1381 std::string_view env{*envp}; 1382 size_t eqIdx = env.find('='); 1383 if (eqIdx == std::string_view::npos) { 1384 continue; 1385 } 1386 1387 std::string key{env.substr(0, eqIdx)}; 1388 if (mLaunchOptions->env_map.count(key)) { 1389 // If the key already exists in the map, we don't want to overwrite it. 1390 continue; 1391 } 1392 1393 mLaunchOptions->env_map[key] = env.substr(eqIdx + 1); 1394 } 1395 return Ok(); 1396 } 1397 1398 RefPtr<ProcessLaunchPromise> IosProcessLauncher::DoLaunch() { 1399 ExtensionKitProcess::Kind kind = ExtensionKitProcess::Kind::WebContent; 1400 if (mProcessType == GeckoProcessType_GPU) { 1401 kind = ExtensionKitProcess::Kind::Rendering; 1402 } else if (mProcessType == GeckoProcessType_Socket) { 1403 kind = ExtensionKitProcess::Kind::Networking; 1404 } 1405 1406 DarwinObjectPtr<xpc_object_t> bootstrapMessage = 1407 AdoptDarwinObject(xpc_dictionary_create_empty()); 1408 xpc_dictionary_set_string(bootstrapMessage.get(), "message-name", 1409 "bootstrap"); 1410 1411 DarwinObjectPtr<xpc_object_t> environDict = 1412 AdoptDarwinObject(xpc_dictionary_create_empty()); 1413 for (auto& [envKey, envValue] : mLaunchOptions->env_map) { 1414 xpc_dictionary_set_string(environDict.get(), envKey.c_str(), 1415 envValue.c_str()); 1416 } 1417 xpc_dictionary_set_value(bootstrapMessage.get(), "environ", 1418 environDict.get()); 1419 1420 // Setup stdout and stderr to inherit. 1421 xpc_dictionary_set_fd(bootstrapMessage.get(), "stdout", STDOUT_FILENO); 1422 xpc_dictionary_set_fd(bootstrapMessage.get(), "stderr", STDERR_FILENO); 1423 1424 DarwinObjectPtr<xpc_object_t> argsArray = 1425 AdoptDarwinObject(xpc_array_create_empty()); 1426 for (auto& argv : mChildArgs.mArgs) { 1427 xpc_array_set_string(argsArray.get(), XPC_ARRAY_APPEND, argv.c_str()); 1428 } 1429 MOZ_ASSERT(xpc_array_get_count(argsArray.get()) == mChildArgs.mArgs.size()); 1430 xpc_dictionary_set_value(bootstrapMessage.get(), "argv", argsArray.get()); 1431 1432 DarwinObjectPtr<xpc_object_t> fdsArray = 1433 AdoptDarwinObject(xpc_array_create_empty()); 1434 for (auto& file : mChildArgs.mFiles) { 1435 xpc_array_set_fd(fdsArray.get(), XPC_ARRAY_APPEND, file.get()); 1436 } 1437 MOZ_ASSERT(xpc_array_get_count(fdsArray.get()) == mChildArgs.mFiles.size()); 1438 xpc_dictionary_set_value(bootstrapMessage.get(), "fds", fdsArray.get()); 1439 1440 DarwinObjectPtr<xpc_object_t> sendRightsArray = 1441 AdoptDarwinObject(xpc_array_create_empty()); 1442 for (auto& sendRight : mChildArgs.mSendRights) { 1443 // NOTE: As iOS doesn't expose an xpc_array_set_mach_send function, send 1444 // rights are wrapped with single-key dictionaries. 1445 DarwinObjectPtr<xpc_object_t> sendRightWrapper = 1446 AdoptDarwinObject(xpc_dictionary_create_empty()); 1447 xpc_dictionary_set_mach_send(sendRightWrapper.get(), "port", 1448 sendRight.get()); 1449 xpc_array_set_value(sendRightsArray.get(), XPC_ARRAY_APPEND, 1450 sendRightWrapper.get()); 1451 } 1452 MOZ_ASSERT(xpc_array_get_count(sendRightsArray.get()) == 1453 mChildArgs.mSendRights.size()); 1454 xpc_dictionary_set_value(bootstrapMessage.get(), "sendRights", 1455 sendRightsArray.get()); 1456 1457 auto promise = MakeRefPtr<ProcessLaunchPromise::Private>(__func__); 1458 ExtensionKitProcess::StartProcess(kind, [self = RefPtr{this}, promise, 1459 bootstrapMessage = 1460 std::move(bootstrapMessage)]( 1461 Result<ExtensionKitProcess, 1462 LaunchError>&& result) { 1463 if (result.isErr()) { 1464 CHROMIUM_LOG(ERROR) << "ExtensionKitProcess::StartProcess failed"; 1465 promise->Reject(result.unwrapErr(), __func__); 1466 return; 1467 } 1468 1469 auto process = result.unwrap(); 1470 self->mResults.mForegroundCapabilityGrant = 1471 process.GrantForegroundCapability(); 1472 self->mResults.mXPCConnection = process.MakeLibXPCConnection(); 1473 self->mResults.mExtensionKitProcess = Some(std::move(process)); 1474 1475 // We don't actually use the event handler for anything other than 1476 // watching for errors. Once the promise is resolved, this becomes a 1477 // no-op. 1478 xpc_connection_set_event_handler(self->mResults.mXPCConnection.get(), ^( 1479 xpc_object_t event) { 1480 if (!event || xpc_get_type(event) == XPC_TYPE_ERROR) { 1481 CHROMIUM_LOG(WARNING) << "XPC connection received encountered an error"; 1482 promise->Reject(LaunchError("xpc_connection_event_handler"), __func__); 1483 } 1484 }); 1485 xpc_connection_resume(self->mResults.mXPCConnection.get()); 1486 1487 // Send our bootstrap message to the content and wait for it to reply with 1488 // the task port before resolving. 1489 // FIXME: Should we have a time-out for if the child process doesn't respond 1490 // in time? The main thread may be blocked while we're starting this 1491 // process. 1492 xpc_connection_send_message_with_reply( 1493 self->mResults.mXPCConnection.get(), bootstrapMessage.get(), nullptr, 1494 ^(xpc_object_t reply) { 1495 if (xpc_get_type(reply) == XPC_TYPE_ERROR) { 1496 CHROMIUM_LOG(ERROR) 1497 << "Got error sending XPC bootstrap message to child"; 1498 promise->Reject( 1499 LaunchError("xpc_connection_send_message_with_reply error"), 1500 __func__); 1501 return; 1502 } 1503 1504 if (xpc_get_type(reply) != XPC_TYPE_DICTIONARY) { 1505 CHROMIUM_LOG(ERROR) 1506 << "Unexpected reply type for bootstrap message from child"; 1507 promise->Reject( 1508 LaunchError( 1509 "xpc_connection_send_message_with_reply non-dictionary"), 1510 __func__); 1511 return; 1512 } 1513 1514 // NOTE: We have to trust the child to tell us its pid. The child is 1515 // blocked by sandbox from sending its mach task. 1516 // WebKit uses `xpc_connection_get_pid` to get the pid, however this 1517 // is marked as unavailable on iOS. 1518 // 1519 // The process hasn't had a chance to load any untrusted content at 1520 // this point, so we should be able to trust it. 1521 pid_t pid = 1522 static_cast<pid_t>(xpc_dictionary_get_int64(reply, "pid")); 1523 CHROMIUM_LOG(INFO) << "ExtensionKit process started, pid: " << pid; 1524 1525 self->mResults.mHandle = pid; 1526 promise->Resolve(std::move(self->mResults), __func__); 1527 }); 1528 }); 1529 1530 return promise; 1531 } 1532 #endif 1533 1534 #ifdef XP_MACOSX 1535 RefPtr<ProcessLaunchPromise> MacProcessLauncher::DoLaunch() { 1536 return PosixProcessLauncher::DoLaunch()->Then( 1537 XRE_GetAsyncIOEventTarget(), __func__, 1538 [self = RefPtr{this}]( 1539 LaunchResults&& aResults) -> RefPtr<ProcessLaunchPromise> { 1540 // Wait for the child process to send us its 'task_t' data, then 1541 // send it the mach send/receive rights which are being passed on 1542 // the commandline. 1543 return MachHandleProcessCheckIn(std::move(self->mParentRecvPort), 1544 base::GetProcId(aResults.mHandle), 1545 mozilla::TimeDuration::FromSeconds(10), 1546 std::move(self->mChildArgs.mSendRights)) 1547 ->Then( 1548 XRE_GetAsyncIOEventTarget(), __func__, 1549 [self, results = std::move(aResults)](task_t aTask) mutable { 1550 results.mChildTask = aTask; 1551 return ProcessLaunchPromise::CreateAndResolve( 1552 std::move(results), __func__); 1553 }, 1554 [](LaunchError aError) { 1555 return ProcessLaunchPromise::CreateAndReject(aError, 1556 __func__); 1557 }); 1558 }, 1559 [](LaunchError aError) { 1560 return ProcessLaunchPromise::CreateAndReject(aError, __func__); 1561 }); 1562 } 1563 #endif // XP_MACOSX 1564 1565 #ifdef XP_WIN 1566 Result<Ok, LaunchError> WindowsProcessLauncher::DoSetup() { 1567 Result<Ok, LaunchError> aError = BaseProcessLauncher::DoSetup(); 1568 if (aError.isErr()) { 1569 return aError; 1570 } 1571 1572 FilePath exePath; 1573 BinPathType pathType = GetPathToBinary(exePath, mProcessType); 1574 1575 mCmdLine.emplace(exePath.ToWStringHack()); 1576 1577 if (pathType == BinPathType::Self) { 1578 mCmdLine->AppendLooseValue(UTF8ToWide("-contentproc")); 1579 } 1580 1581 # ifdef HAS_DLL_BLOCKLIST 1582 if (IsDynamicBlocklistDisabled( 1583 gSafeMode, 1584 CommandLine::ForCurrentProcess()->HasSwitch(UTF8ToWide( 1585 mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch)))) { 1586 mCmdLine->AppendLooseValue( 1587 UTF8ToWide(mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch)); 1588 } 1589 # endif // HAS_DLL_BLOCKLIST 1590 1591 for (const std::string& arg : mChildArgs.mArgs) { 1592 mCmdLine->AppendLooseValue(UTF8ToWide(arg)); 1593 } 1594 1595 # if defined(MOZ_SANDBOX) 1596 mResults.mSandboxBroker = MakeUnique<SandboxBroker>(); 1597 1598 // XXX: Bug 1124167: We should get rid of the process specific logic for 1599 // sandboxing in this class at some point. Unfortunately it will take a bit 1600 // of reorganizing so I don't think this patch is the right time. 1601 switch (mProcessType) { 1602 case GeckoProcessType_Content: 1603 if (mSandboxLevel > 0) { 1604 // For now we treat every failure as fatal in 1605 // SetSecurityLevelForContentProcess and just crash there right away. 1606 // Should this change in the future then we should also handle the error 1607 // here. 1608 mResults.mSandboxBroker->SetSecurityLevelForContentProcess( 1609 mSandboxLevel, mIsFileContent); 1610 mUseSandbox = true; 1611 } 1612 break; 1613 case GeckoProcessType_IPDLUnitTest: 1614 // XXX: We don't sandbox this process type yet 1615 break; 1616 case GeckoProcessType_GMPlugin: 1617 if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) { 1618 auto gmpSandboxKind = GMPSandboxKind::Default; 1619 if (Contains(mChildArgs, "gmp-widevinecdm")) { 1620 gmpSandboxKind = GMPSandboxKind::Widevine; 1621 } else if (Contains(mChildArgs, "gmp-clearkey")) { 1622 gmpSandboxKind = GMPSandboxKind::Clearkey; 1623 } else if (Contains(mChildArgs, "gmp-fake")) { 1624 gmpSandboxKind = GMPSandboxKind::Fake; 1625 } 1626 1627 if (NS_WARN_IF(!mResults.mSandboxBroker->SetSecurityLevelForGMPlugin( 1628 gmpSandboxKind))) { 1629 return Err(LaunchError("SetSecurityLevelForGMPlugin")); 1630 } 1631 mUseSandbox = true; 1632 } 1633 break; 1634 case GeckoProcessType_GPU: 1635 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) { 1636 // For now we treat every failure as fatal in 1637 // SetSecurityLevelForGPUProcess and just crash there right away. Should 1638 // this change in the future then we should also handle the error here. 1639 mResults.mSandboxBroker->SetSecurityLevelForGPUProcess(mSandboxLevel); 1640 mUseSandbox = true; 1641 } 1642 break; 1643 case GeckoProcessType_VR: 1644 if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) { 1645 // TODO: Implement sandbox for VR process, Bug 1430043. 1646 } 1647 break; 1648 case GeckoProcessType_RDD: 1649 if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) { 1650 if (NS_WARN_IF( 1651 !mResults.mSandboxBroker->SetSecurityLevelForRDDProcess())) { 1652 return Err(LaunchError("SetSecurityLevelForRDDProcess")); 1653 } 1654 mUseSandbox = true; 1655 } 1656 break; 1657 case GeckoProcessType_Socket: 1658 if (!PR_GetEnv("MOZ_DISABLE_SOCKET_PROCESS_SANDBOX")) { 1659 if (NS_WARN_IF( 1660 !mResults.mSandboxBroker->SetSecurityLevelForSocketProcess())) { 1661 return Err(LaunchError("SetSecurityLevelForSocketProcess")); 1662 } 1663 mUseSandbox = true; 1664 } 1665 break; 1666 case GeckoProcessType_Utility: 1667 if (IsUtilitySandboxEnabled(mSandbox)) { 1668 if (!mResults.mSandboxBroker->SetSecurityLevelForUtilityProcess( 1669 mSandbox)) { 1670 return Err(LaunchError("SetSecurityLevelForUtilityProcess")); 1671 } 1672 mUseSandbox = true; 1673 } 1674 break; 1675 case GeckoProcessType_Default: 1676 default: 1677 MOZ_CRASH("Bad process type in GeckoChildProcessHost"); 1678 break; 1679 }; 1680 1681 if (mUseSandbox) { 1682 for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end(); 1683 ++it) { 1684 mResults.mSandboxBroker->AllowReadFile(it->c_str()); 1685 } 1686 1687 if (mResults.mSandboxBroker->IsWin32kLockedDown()) { 1688 mCmdLine->AppendLooseValue( 1689 UTF8ToWide(geckoargs::sWin32kLockedDown.Name())); 1690 } 1691 } 1692 # endif // defined(MOZ_SANDBOX) 1693 1694 // Add the application directory path (-appdir path) 1695 AddAppDirToCommandLine(mCmdLine.ref(), mAppDir); 1696 1697 // XXX Command line params past this point are expected to be at 1698 // the end of the command line string, and in a specific order. 1699 // See XRE_InitChildProcess in nsEmbedFunction. 1700 1701 // Win app model id 1702 mCmdLine->AppendLooseValue(mGroupId.get()); 1703 1704 // Gecko child id 1705 mCmdLine->AppendLooseValue(UTF8ToWide(mChildIDString)); 1706 1707 // Process type 1708 mCmdLine->AppendLooseValue(UTF8ToWide(ChildProcessType())); 1709 1710 // Add any files which need to be transferred to handles_to_inherit. 1711 for (auto& file : mChildArgs.mFiles) { 1712 mLaunchOptions->handles_to_inherit.push_back(file.get()); 1713 } 1714 1715 # ifdef MOZ_SANDBOX 1716 if (mUseSandbox) { 1717 // Mark the handles to inherit as inheritable. 1718 for (HANDLE h : mLaunchOptions->handles_to_inherit) { 1719 mResults.mSandboxBroker->AddHandleToShare(h); 1720 } 1721 } 1722 # endif // MOZ_SANDBOX 1723 1724 return Ok(); 1725 } 1726 1727 RefPtr<ProcessLaunchPromise> WindowsProcessLauncher::DoLaunch() { 1728 # ifdef MOZ_SANDBOX 1729 if (mUseSandbox) { 1730 const IMAGE_THUNK_DATA* cachedNtdllThunk = 1731 mCachedNtdllThunk ? mCachedNtdllThunk->begin() : nullptr; 1732 Result<Ok, LaunchError> err = mResults.mSandboxBroker->LaunchApp( 1733 mCmdLine->program().c_str(), mCmdLine->command_line_string().c_str(), 1734 mLaunchOptions->env_map, mProcessType, mEnableSandboxLogging, 1735 cachedNtdllThunk, &mResults.mHandle); 1736 if (err.isOk()) { 1737 EnvironmentLog("MOZ_PROCESS_LOG") 1738 .print("==> process %d launched child process %d (%S)\n", 1739 base::GetCurrentProcId(), base::GetProcId(mResults.mHandle), 1740 mCmdLine->command_line_string().c_str()); 1741 return ProcessLaunchPromise::CreateAndResolve(std::move(mResults), 1742 __func__); 1743 } 1744 return ProcessLaunchPromise::CreateAndReject(err.unwrapErr(), __func__); 1745 } 1746 # endif // defined(MOZ_SANDBOX) 1747 1748 Result<Ok, LaunchError> launchErr = 1749 base::LaunchApp(mCmdLine.ref(), *mLaunchOptions, &mResults.mHandle); 1750 if (launchErr.isErr()) { 1751 return ProcessLaunchPromise::CreateAndReject(launchErr.unwrapErr(), 1752 __func__); 1753 } 1754 return ProcessLaunchPromise::CreateAndResolve(std::move(mResults), __func__); 1755 } 1756 #endif // XP_WIN 1757 1758 bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid) { 1759 if (mChildProcessHandle) { 1760 MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle)); 1761 return true; 1762 } 1763 1764 return base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle); 1765 } 1766 1767 void GeckoChildProcessHost::OnChannelConnected(base::ProcessId peer_pid) { 1768 { 1769 mozilla::AutoWriteLock hLock(mHandleLock); 1770 if (!OpenPrivilegedHandle(peer_pid)) { 1771 MOZ_CRASH("can't open handle to child process"); 1772 } 1773 } 1774 MonitorAutoLock lock(mMonitor); 1775 mProcessState = PROCESS_CONNECTED; 1776 lock.Notify(); 1777 } 1778 1779 RefPtr<ProcessHandlePromise> GeckoChildProcessHost::WhenProcessHandleReady() { 1780 MOZ_ASSERT(mHandlePromise != nullptr); 1781 return mHandlePromise; 1782 } 1783 1784 #ifdef MOZ_WIDGET_ANDROID 1785 RefPtr<ProcessHandlePromise> AndroidProcessLauncher::LaunchAndroidService( 1786 const GeckoProcessType aType, const geckoargs::ChildProcessArgs& args) { 1787 JNIEnv* const env = mozilla::jni::GetEnvForThread(); 1788 MOZ_ASSERT(env); 1789 1790 const size_t argvSize = args.mArgs.size(); 1791 jni::ObjectArray::LocalRef jargs = 1792 jni::ObjectArray::New<jni::String>(argvSize); 1793 for (size_t ix = 0; ix < argvSize; ix++) { 1794 jargs->SetElement(ix, jni::StringParam(args.mArgs[ix].c_str(), env)); 1795 } 1796 1797 std::vector<int> fds(args.mFiles.size()); 1798 for (size_t ix = 0; ix < fds.size(); ix++) { 1799 fds[ix] = args.mFiles[ix].get(); 1800 } 1801 jni::IntArray::LocalRef jfds = jni::IntArray::New(fds.data(), fds.size()); 1802 1803 auto type = java::GeckoProcessType::FromInt(aType); 1804 auto genericResult = java::GeckoProcessManager::Start(type, jargs, jfds); 1805 auto typedResult = java::GeckoResult::LocalRef(std::move(genericResult)); 1806 return ProcessHandlePromise::FromGeckoResult(typedResult); 1807 } 1808 #endif 1809 1810 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) 1811 bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector& aArgs) { 1812 MacSandboxInfo info; 1813 if (NS_WARN_IF(!FillMacSandboxInfo(info))) { 1814 return false; 1815 } 1816 info.AppendAsParams(aArgs); 1817 return true; 1818 } 1819 1820 // Fill |aInfo| with the flags needed to launch the utility sandbox 1821 bool GeckoChildProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) { 1822 aInfo.type = GetDefaultMacSandboxType(); 1823 aInfo.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled") || 1824 PR_GetEnv("MOZ_SANDBOX_LOGGING"); 1825 1826 nsAutoCString appPath; 1827 if (!nsMacUtilsImpl::GetAppPath(appPath)) { 1828 MOZ_CRASH("Failed to get app path"); 1829 } 1830 aInfo.appPath.assign(appPath.get()); 1831 return true; 1832 } 1833 1834 void GeckoChildProcessHost::DisableOSActivityMode() { 1835 mDisableOSActivityMode = true; 1836 } 1837 1838 // 1839 // If early sandbox startup is enabled for this process type, map the 1840 // process type to the sandbox type and enable the sandbox. Returns true 1841 // if no errors were encountered or if early sandbox startup is not 1842 // enabled for this process. Returns false if an error was encountered. 1843 // 1844 /* static */ 1845 bool GeckoChildProcessHost::StartMacSandbox(int aArgc, char** aArgv, 1846 std::string& aErrorMessage) { 1847 MacSandboxType sandboxType = MacSandboxType_Invalid; 1848 switch (XRE_GetProcessType()) { 1849 // For now, only support early sandbox startup for content, 1850 // RDD, and GMP processes. Add case statements for the additional 1851 // process types once early sandbox startup is implemented for them. 1852 case GeckoProcessType_Content: 1853 // Content processes don't use GeckoChildProcessHost 1854 // to configure sandboxing so hard code the sandbox type. 1855 sandboxType = MacSandboxType_Content; 1856 break; 1857 case GeckoProcessType_RDD: 1858 sandboxType = RDDProcessHost::GetMacSandboxType(); 1859 break; 1860 case GeckoProcessType_Socket: 1861 sandboxType = net::SocketProcessHost::GetMacSandboxType(); 1862 break; 1863 case GeckoProcessType_GMPlugin: 1864 sandboxType = gmp::GMPProcessParent::GetMacSandboxType(); 1865 break; 1866 case GeckoProcessType_Utility: 1867 sandboxType = ipc::UtilityProcessHost::GetMacSandboxType(); 1868 break; 1869 case GeckoProcessType_GPU: 1870 sandboxType = gfx::GPUProcessHost::GetMacSandboxType(); 1871 break; 1872 default: 1873 return true; 1874 } 1875 1876 return mozilla::StartMacSandboxIfEnabled(sandboxType, aArgc, aArgv, 1877 aErrorMessage); 1878 } 1879 1880 #endif /* XP_MACOSX && MOZ_SANDBOX */ 1881 1882 /* static */ 1883 void GeckoChildProcessHost::GetAll(const GeckoProcessCallback& aCallback) { 1884 StaticMutexAutoLock lock(sMutex); 1885 if (!sGeckoChildProcessHosts) { 1886 return; 1887 } 1888 for (GeckoChildProcessHost* gp = sGeckoChildProcessHosts->getFirst(); gp; 1889 gp = static_cast<mozilla::LinkedListElement<GeckoChildProcessHost>*>(gp) 1890 ->getNext()) { 1891 aCallback(gp); 1892 } 1893 } 1894 1895 RefPtr<ProcessLaunchPromise> BaseProcessLauncher::Launch( 1896 GeckoChildProcessHost* aHost) { 1897 AssertIOThread(); 1898 1899 // The ForkServer doesn't use IPC::Channel for communication, so we can skip 1900 // initializing it. 1901 if (mProcessType != GeckoProcessType_ForkServer) { 1902 IPC::Channel::ChannelHandle clientHandle; 1903 if (!aHost->InitializeChannel(&clientHandle)) { 1904 return ProcessLaunchPromise::CreateAndReject( 1905 LaunchError("InitializeChannel"), __func__); 1906 } 1907 1908 if (auto* handle = std::get_if<UniqueFileHandle>(&clientHandle)) { 1909 geckoargs::sIPCHandle.Put(std::move(*handle), mChildArgs); 1910 } 1911 #ifdef XP_DARWIN 1912 // NOTE: We don't support passing UniqueMachReceiveRight instances on the 1913 // command line, so clientHandle must be a send right. 1914 else if (auto* port = std::get_if<UniqueMachSendRight>(&clientHandle)) { 1915 geckoargs::sIPCPort.Put(std::move(*port), mChildArgs); 1916 } 1917 #endif 1918 else { 1919 MOZ_ASSERT_UNREACHABLE(); 1920 return ProcessLaunchPromise::CreateAndReject(LaunchError("BadPipeType"), 1921 __func__); 1922 } 1923 } 1924 1925 return InvokeAsync(mLaunchThread, this, __func__, 1926 &BaseProcessLauncher::PerformAsyncLaunch); 1927 } 1928 1929 } // namespace ipc 1930 } // namespace mozilla