tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

UtilityProcessChild.cpp (13486B)


      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 #include "UtilityProcessChild.h"
      7 
      8 #include "mozilla/AppShutdown.h"
      9 #include "mozilla/Logging.h"
     10 #include "mozilla/dom/ContentParent.h"
     11 #include "mozilla/dom/JSOracleChild.h"
     12 #include "mozilla/dom/MemoryReportRequest.h"
     13 #include "mozilla/ipc/CrashReporterClient.h"
     14 #include "mozilla/ipc/Endpoint.h"
     15 #include "mozilla/ipc/UtilityProcessManager.h"
     16 #include "mozilla/ipc/UtilityProcessSandboxing.h"
     17 #include "mozilla/Preferences.h"
     18 #include "mozilla/RemoteMediaManagerParent.h"
     19 
     20 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
     21 #  include "mozilla/Sandbox.h"
     22 #  include "mozilla/SandboxProfilerObserver.h"
     23 #endif
     24 
     25 #if defined(XP_OPENBSD) && defined(MOZ_SANDBOX)
     26 #  include "mozilla/SandboxSettings.h"
     27 #endif
     28 
     29 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
     30 #  include "mozilla/SandboxTestingChild.h"
     31 #endif
     32 
     33 #include "mozilla/Telemetry.h"
     34 
     35 #if defined(XP_WIN)
     36 #  include "mozilla/WinDllServices.h"
     37 #  include "mozilla/dom/WindowsUtilsChild.h"
     38 #  include "mozilla/widget/filedialog/WinFileDialogChild.h"
     39 #endif
     40 
     41 #include "nsDebugImpl.h"
     42 #include "nsIXULRuntime.h"
     43 #include "nsThreadManager.h"
     44 #include "GeckoProfiler.h"
     45 
     46 #include "mozilla/ipc/ProcessChild.h"
     47 #include "mozilla/FOGIPC.h"
     48 #include "mozilla/glean/GleanTestsTestMetrics.h"
     49 
     50 #include "mozilla/Services.h"
     51 
     52 namespace TelemetryScalar {
     53 void Set(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
     54 }
     55 
     56 namespace mozilla::ipc {
     57 
     58 using namespace layers;
     59 
     60 static StaticMutex sUtilityProcessChildMutex;
     61 static StaticRefPtr<UtilityProcessChild> sUtilityProcessChild
     62    MOZ_GUARDED_BY(sUtilityProcessChildMutex);
     63 
     64 UtilityProcessChild::UtilityProcessChild() : mChildStartTime(TimeStamp::Now()) {
     65  nsDebugImpl::SetMultiprocessMode("Utility");
     66 }
     67 
     68 UtilityProcessChild::~UtilityProcessChild() = default;
     69 
     70 /* static */
     71 RefPtr<UtilityProcessChild> UtilityProcessChild::GetSingleton() {
     72  MOZ_ASSERT(XRE_IsUtilityProcess());
     73  if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownFinal)) {
     74    return nullptr;
     75  }
     76  StaticMutexAutoLock lock(sUtilityProcessChildMutex);
     77  if (!sUtilityProcessChild) {
     78    sUtilityProcessChild = new UtilityProcessChild();
     79  }
     80  return sUtilityProcessChild;
     81 }
     82 
     83 /* static */
     84 RefPtr<UtilityProcessChild> UtilityProcessChild::Get() {
     85  StaticMutexAutoLock lock(sUtilityProcessChildMutex);
     86  return sUtilityProcessChild;
     87 }
     88 
     89 bool UtilityProcessChild::Init(mozilla::ipc::UntypedEndpoint&& aEndpoint,
     90                               const nsCString& aParentBuildID,
     91                               uint64_t aSandboxingKind) {
     92  MOZ_ASSERT(NS_IsMainThread());
     93 
     94  // Initialize the thread manager before starting IPC. Otherwise, messages
     95  // may be posted to the main thread and we won't be able to process them.
     96  if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
     97    return false;
     98  }
     99 
    100  // Now it's safe to start IPC.
    101  if (NS_WARN_IF(!aEndpoint.Bind(this))) {
    102    return false;
    103  }
    104 
    105  // This must be checked before any IPDL message, which may hit sentinel
    106  // errors due to parent and content processes having different
    107  // versions.
    108  MessageChannel* channel = GetIPCChannel();
    109  if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID.get())) {
    110    // We need to quit this process if the buildID doesn't match the parent's.
    111    // This can occur when an update occurred in the background.
    112    ipc::ProcessChild::QuickExit();
    113  }
    114 
    115  // Init crash reporter support.
    116  ipc::CrashReporterClient::InitSingleton(this);
    117 
    118  if (NS_FAILED(NS_InitMinimalXPCOM())) {
    119    return false;
    120  }
    121 
    122  mSandbox = (SandboxingKind)aSandboxingKind;
    123 
    124  // At the moment, only ORB uses JSContext in the
    125  // Utility Process and ORB uses GENERIC_UTILITY
    126  if (mSandbox == SandboxingKind::GENERIC_UTILITY) {
    127    if (!JS_FrontendOnlyInit()) {
    128      return false;
    129    }
    130 #if defined(__OpenBSD__) && defined(MOZ_SANDBOX)
    131    // Bug 1823458: delay pledge initialization, otherwise
    132    // JS_FrontendOnlyInit triggers sysctl(KERN_PROC_ID) which isnt
    133    // permitted with the current pledge.utility config
    134    StartOpenBSDSandbox(GeckoProcessType_Utility, mSandbox);
    135 #endif
    136  }
    137 
    138  profiler_set_process_name(nsCString("Utility Process"));
    139 
    140  // Notify the parent process that we have finished our init and that it can
    141  // now resolve the pending promise of process startup
    142  SendInitCompleted();
    143 
    144  PROFILER_MARKER_UNTYPED(
    145      "UtilityProcessChild::SendInitCompleted", IPC,
    146      MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime)));
    147 
    148  RunOnShutdown(
    149      [sandboxKind = mSandbox] {
    150        StaticMutexAutoLock lock(sUtilityProcessChildMutex);
    151        sUtilityProcessChild = nullptr;
    152        if (sandboxKind == SandboxingKind::GENERIC_UTILITY) {
    153          JS_FrontendOnlyShutDown();
    154        }
    155      },
    156      ShutdownPhase::XPCOMShutdownFinal);
    157 
    158  return true;
    159 }
    160 
    161 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
    162 extern "C" {
    163 void CGSShutdownServerConnections();
    164 };
    165 #endif
    166 
    167 mozilla::ipc::IPCResult UtilityProcessChild::RecvInit(
    168    const Maybe<FileDescriptor>& aBrokerFd,
    169    const bool& aCanRecordReleaseTelemetry,
    170    const bool& aIsReadyForBackgroundProcessing) {
    171  // Do this now (before closing WindowServer on macOS) to avoid risking
    172  // blocking in GetCurrentProcess() called on that platform
    173  mozilla::ipc::SetThisProcessName("Utility Process");
    174 
    175 #if defined(MOZ_SANDBOX)
    176 #  if defined(XP_MACOSX)
    177  // Close all current connections to the WindowServer. This ensures that the
    178  // Activity Monitor will not label the content process as "Not responding"
    179  // because it's not running a native event loop. See bug 1384336.
    180  CGSShutdownServerConnections();
    181 
    182 #  elif defined(XP_LINUX)
    183  int fd = -1;
    184  if (aBrokerFd.isSome()) {
    185    fd = aBrokerFd.value().ClonePlatformHandle().release();
    186  }
    187 
    188  RegisterProfilerObserversForSandboxProfiler();
    189  SetUtilitySandbox(fd, mSandbox);
    190 
    191 #  endif  // XP_MACOSX/XP_LINUX
    192 #endif    // MOZ_SANDBOX
    193 
    194 #if defined(XP_WIN)
    195  if (aCanRecordReleaseTelemetry) {
    196    RefPtr<DllServices> dllSvc(DllServices::Get());
    197    dllSvc->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing);
    198  }
    199 #endif  // defined(XP_WIN)
    200 
    201  PROFILER_MARKER_UNTYPED(
    202      "UtilityProcessChild::RecvInit", IPC,
    203      MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime)));
    204  return IPC_OK();
    205 }
    206 
    207 mozilla::ipc::IPCResult UtilityProcessChild::RecvPreferenceUpdate(
    208    const Pref& aPref) {
    209  Preferences::SetPreference(aPref);
    210  return IPC_OK();
    211 }
    212 
    213 mozilla::ipc::IPCResult UtilityProcessChild::RecvInitProfiler(
    214    Endpoint<PProfilerChild>&& aEndpoint) {
    215  mProfilerController = ChildProfilerController::Create(std::move(aEndpoint));
    216  return IPC_OK();
    217 }
    218 
    219 mozilla::ipc::IPCResult UtilityProcessChild::RecvRequestMemoryReport(
    220    const uint32_t& aGeneration, const bool& aAnonymize,
    221    const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile,
    222    const RequestMemoryReportResolver& aResolver) {
    223  nsPrintfCString processName("Utility (pid %" PRIPID
    224                              ", sandboxingKind %" PRIu64 ")",
    225                              base::GetCurrentProcId(), mSandbox);
    226 
    227  mozilla::dom::MemoryReportRequestClient::Start(
    228      aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName,
    229      [&](const MemoryReport& aReport) {
    230        (void)GetSingleton()->SendAddMemoryReport(aReport);
    231      },
    232      aResolver);
    233  return IPC_OK();
    234 }
    235 
    236 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
    237 mozilla::ipc::IPCResult UtilityProcessChild::RecvInitSandboxTesting(
    238    Endpoint<PSandboxTestingChild>&& aEndpoint) {
    239  if (!SandboxTestingChild::Initialize(std::move(aEndpoint))) {
    240    return IPC_FAIL(
    241        this, "InitSandboxTesting failed to initialise the child process.");
    242  }
    243  return IPC_OK();
    244 }
    245 #endif
    246 
    247 mozilla::ipc::IPCResult UtilityProcessChild::RecvFlushFOGData(
    248    FlushFOGDataResolver&& aResolver) {
    249  glean::FlushFOGData(std::move(aResolver));
    250  return IPC_OK();
    251 }
    252 
    253 mozilla::ipc::IPCResult UtilityProcessChild::RecvTestTriggerMetrics(
    254    TestTriggerMetricsResolver&& aResolve) {
    255  mozilla::glean::test_only_ipc::a_counter.Add(
    256      nsIXULRuntime::PROCESS_TYPE_UTILITY);
    257  aResolve(true);
    258  return IPC_OK();
    259 }
    260 
    261 mozilla::ipc::IPCResult UtilityProcessChild::RecvTestTelemetryProbes() {
    262  const uint32_t kExpectedUintValue = 42;
    263  TelemetryScalar::Set(Telemetry::ScalarID::TELEMETRY_TEST_UTILITY_ONLY_UINT,
    264                       kExpectedUintValue);
    265  return IPC_OK();
    266 }
    267 
    268 mozilla::ipc::IPCResult UtilityProcessChild::RecvStartUtilityMediaService(
    269    Endpoint<PUtilityMediaServiceParent>&& aEndpoint,
    270    nsTArray<gfx::GfxVarUpdate>&& aUpdates) {
    271  PROFILER_MARKER_UNTYPED(
    272      "UtilityProcessChild::RecvStartUtilityMediaService", MEDIA,
    273      MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime)));
    274  mUtilityMediaServiceInstance =
    275      new UtilityMediaServiceParent(std::move(aUpdates));
    276  if (!mUtilityMediaServiceInstance) {
    277    return IPC_FAIL(this, "Failed to create UtilityMediaServiceParent");
    278  }
    279 
    280  mUtilityMediaServiceInstance->Start(std::move(aEndpoint));
    281  return IPC_OK();
    282 }
    283 
    284 mozilla::ipc::IPCResult UtilityProcessChild::RecvStartJSOracleService(
    285    Endpoint<PJSOracleChild>&& aEndpoint) {
    286  PROFILER_MARKER_UNTYPED(
    287      "UtilityProcessChild::RecvStartJSOracleService", JS,
    288      MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime)));
    289  mJSOracleInstance = new mozilla::dom::JSOracleChild();
    290  if (!mJSOracleInstance) {
    291    return IPC_FAIL(this, "Failed to create JSOracleParent");
    292  }
    293 
    294  mJSOracleInstance->Start(std::move(aEndpoint));
    295  return IPC_OK();
    296 }
    297 
    298 #if defined(XP_WIN)
    299 mozilla::ipc::IPCResult UtilityProcessChild::RecvStartWindowsUtilsService(
    300    Endpoint<dom::PWindowsUtilsChild>&& aEndpoint) {
    301  PROFILER_MARKER_UNTYPED(
    302      "UtilityProcessChild::RecvStartWindowsUtilsService", OTHER,
    303      MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime)));
    304  mWindowsUtilsInstance = new dom::WindowsUtilsChild();
    305  if (!mWindowsUtilsInstance) {
    306    return IPC_FAIL(this, "Failed to create WindowsUtilsChild");
    307  }
    308 
    309  [[maybe_unused]] bool ok = std::move(aEndpoint).Bind(mWindowsUtilsInstance);
    310  MOZ_ASSERT(ok);
    311  return IPC_OK();
    312 }
    313 
    314 mozilla::ipc::IPCResult UtilityProcessChild::RecvStartWinFileDialogService(
    315    Endpoint<widget::filedialog::PWinFileDialogChild>&& aEndpoint) {
    316  PROFILER_MARKER_UNTYPED(
    317      "UtilityProcessChild::RecvStartWinFileDialogService", OTHER,
    318      MarkerOptions(MarkerTiming::IntervalUntilNowFrom(mChildStartTime)));
    319 
    320  auto instance = MakeRefPtr<widget::filedialog::WinFileDialogChild>();
    321  if (!instance) {
    322    return IPC_FAIL(this, "Failed to create WinFileDialogChild");
    323  }
    324 
    325  bool const ok = std::move(aEndpoint).Bind(instance.get());
    326  if (!ok) {
    327    return IPC_FAIL(this, "Failed to bind created WinFileDialogChild");
    328  }
    329 
    330  return IPC_OK();
    331 }
    332 
    333 mozilla::ipc::IPCResult UtilityProcessChild::RecvGetUntrustedModulesData(
    334    GetUntrustedModulesDataResolver&& aResolver) {
    335  RefPtr<DllServices> dllSvc(DllServices::Get());
    336  dllSvc->GetUntrustedModulesData()->Then(
    337      GetMainThreadSerialEventTarget(), __func__,
    338      [aResolver](Maybe<UntrustedModulesData>&& aData) {
    339        aResolver(std::move(aData));
    340      },
    341      [aResolver](nsresult aReason) { aResolver(Nothing()); });
    342  return IPC_OK();
    343 }
    344 
    345 mozilla::ipc::IPCResult
    346 UtilityProcessChild::RecvUnblockUntrustedModulesThread() {
    347  if (nsCOMPtr<nsIObserverService> obs =
    348          mozilla::services::GetObserverService()) {
    349    obs->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr);
    350  }
    351  return IPC_OK();
    352 }
    353 #endif  // defined(XP_WIN)
    354 
    355 void UtilityProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
    356 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
    357  DestroySandboxProfiler();
    358 #endif
    359 
    360  if (AbnormalShutdown == aWhy) {
    361    NS_WARNING("Shutting down Utility process early due to a crash!");
    362    ipc::ProcessChild::QuickExit();
    363  }
    364 
    365  // Send the last bits of Glean data over to the main process.
    366  glean::FlushFOGData(
    367      [](ByteBuf&& aBuf) { glean::SendFOGData(std::move(aBuf)); });
    368 
    369 #ifndef NS_FREE_PERMANENT_DATA
    370  ProcessChild::QuickExit();
    371 #else
    372 
    373  if (mProfilerController) {
    374    mProfilerController->Shutdown();
    375    mProfilerController = nullptr;
    376  }
    377 
    378  uint32_t timeout = 0;
    379  if (mUtilityMediaServiceInstance) {
    380    mUtilityMediaServiceInstance = nullptr;
    381    timeout = 10 * 1000;
    382  }
    383 
    384  mJSOracleInstance = nullptr;
    385 
    386 #  ifdef XP_WIN
    387  mWindowsUtilsInstance = nullptr;
    388 #  endif
    389 
    390  // Wait until all RemoteMediaManagerParent have closed.
    391  // It is still possible some may not have clean up yet, and we might hit
    392  // timeout. Our xpcom-shutdown listener should take care of cleaning the
    393  // reference of our singleton.
    394  //
    395  // FIXME: Should move from using AsyncBlockers to proper
    396  // nsIAsyncShutdownService once it is not JS, see bug 1760855
    397  mShutdownBlockers.WaitUntilClear(timeout)->Then(
    398      GetCurrentSerialEventTarget(), __func__, [&]() {
    399 #  ifdef XP_WIN
    400        {
    401          RefPtr<DllServices> dllSvc(DllServices::Get());
    402          dllSvc->DisableFull();
    403        }
    404 #  endif  // defined(XP_WIN)
    405 
    406        ipc::CrashReporterClient::DestroySingleton();
    407        XRE_ShutdownChildProcess();
    408      });
    409 #endif    // NS_FREE_PERMANENT_DATA
    410 }
    411 
    412 }  // namespace mozilla::ipc