commit 2485ac302318c676883060feb0dc099a8a73191b parent 57603811195db25088f3a41bc12007f3ee1a1fe7 Author: Yannis Juglaret <yjuglaret@mozilla.com> Date: Wed, 17 Dec 2025 15:21:19 +0000 Bug 1957156 - Add a new utility process kind for PKCS#11 module loading. r=haik,ipc-reviewers,fluent-reviewers,bolsson,keeler,nika We add a new sandboxing kind PKCS11_MODULE that we will ultimately use to load PKCS#11 modules in a dedicated process. In particular, this will prevent PKCS#11 module crashes from impacting the main process. In this patch, this new sandboxing kind is only ever used in tests. The patch that actually makes use of this new utility process kind comes later in the stack of patches. Based on prior work by Haik Aftandilian and Alexandre Lissy (D243556, D243557, D243558). Differential Revision: https://phabricator.services.mozilla.com/D270690 Diffstat:
19 files changed, 332 insertions(+), 0 deletions(-)
diff --git a/dom/chrome-webidl/ChromeUtils.webidl b/dom/chrome-webidl/ChromeUtils.webidl @@ -941,6 +941,7 @@ enum WebIDLUtilityActorName { "jSOracle", "windowsUtils", "windowsFileDialog", + "pkcs11Module", }; dictionary UtilityActorsDictionary { diff --git a/ipc/glue/PUtilityProcess.ipdl b/ipc/glue/PUtilityProcess.ipdl @@ -16,6 +16,10 @@ include protocol PWindowsUtils; include protocol PWinFileDialog; #endif +#ifndef MOZ_NO_SMART_CARDS +include protocol PPKCS11Module; +#endif // !MOZ_NO_SMART_CARDS + #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) include protocol PSandboxTesting; #endif @@ -107,6 +111,10 @@ child: async StartJSOracleService(Endpoint<PJSOracleChild> aEndpoint); +#ifndef MOZ_NO_SMART_CARDS + async StartPKCS11ModuleService(Endpoint<PPKCS11ModuleChild> aEndpoint); +#endif // !MOZ_NO_SMART_CARDS + #if defined(XP_WIN) async StartWindowsUtilsService(Endpoint<PWindowsUtilsChild> aEndpoint); async StartWinFileDialogService(Endpoint<PWinFileDialogChild> aEndpoint); diff --git a/ipc/glue/UtilityProcessChild.cpp b/ipc/glue/UtilityProcessChild.cpp @@ -233,6 +233,19 @@ mozilla::ipc::IPCResult UtilityProcessChild::RecvRequestMemoryReport( return IPC_OK(); } +#ifndef MOZ_NO_SMART_CARDS +IPCResult UtilityProcessChild::RecvStartPKCS11ModuleService( + Endpoint<PPKCS11ModuleChild>&& aEndpoint) { + auto child = MakeRefPtr<psm::PKCS11ModuleChild>(); + if (!child || NS_FAILED(child->Start(std::move(aEndpoint)))) { + return IPC_FAIL(this, "Failed to create and start PKCS11ModuleChild"); + } + + mPKCS11ModuleInstance = std::move(child); + return IPC_OK(); +} +#endif // !MOZ_NO_SMART_CARDS + #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) mozilla::ipc::IPCResult UtilityProcessChild::RecvInitSandboxTesting( Endpoint<PSandboxTestingChild>&& aEndpoint) { @@ -387,6 +400,10 @@ void UtilityProcessChild::ActorDestroy(ActorDestroyReason aWhy) { mWindowsUtilsInstance = nullptr; # endif +# ifndef MOZ_NO_SMART_CARDS + mPKCS11ModuleInstance = nullptr; +# endif // !MOZ_NO_SMART_CARDS + // Wait until all RemoteMediaManagerParent have closed. // It is still possible some may not have clean up yet, and we might hit // timeout. Our xpcom-shutdown listener should take care of cleaning the diff --git a/ipc/glue/UtilityProcessChild.h b/ipc/glue/UtilityProcessChild.h @@ -10,6 +10,10 @@ #include "mozilla/ipc/UtilityMediaServiceParent.h" #include "ChildProfilerController.h" +#ifndef MOZ_NO_SMART_CARDS +# include "mozilla/psm/PKCS11ModuleChild.h" +#endif // !MOZ_NO_SMART_CARDS + #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) # include "mozilla/PSandboxTestingChild.h" #endif @@ -82,6 +86,11 @@ class UtilityProcessChild final : public PUtilityProcessChild { AsyncBlockers& AsyncShutdownService() { return mShutdownBlockers; } +#ifndef MOZ_NO_SMART_CARDS + IPCResult RecvStartPKCS11ModuleService( + Endpoint<PPKCS11ModuleChild>&& aEndpoint); +#endif // !MOZ_NO_SMART_CARDS + void ActorDestroy(ActorDestroyReason aWhy) override; #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) @@ -105,6 +114,9 @@ class UtilityProcessChild final : public PUtilityProcessChild { #ifdef XP_WIN RefPtr<PWindowsUtilsChild> mWindowsUtilsInstance; #endif +#ifndef MOZ_NO_SMART_CARDS + RefPtr<psm::PKCS11ModuleChild> mPKCS11ModuleInstance; +#endif // !MOZ_NO_SMART_CARDS AsyncBlockers mShutdownBlockers; }; diff --git a/ipc/glue/UtilityProcessManager.cpp b/ipc/glue/UtilityProcessManager.cpp @@ -29,6 +29,10 @@ #include "mozilla/GeckoArgs.h" +#ifndef MOZ_NO_SMART_CARDS +# include "mozilla/psm/PPKCS11ModuleChild.h" +#endif // !MOZ_NO_SMART_CARDS + namespace mozilla::ipc { extern LazyLogModule gUtilityProcessLog; @@ -514,6 +518,31 @@ UtilityProcessManager::CreateWinFileDialogActor() { #endif // XP_WIN +#ifndef MOZ_NO_SMART_CARDS +RefPtr<UtilityProcessManager::PKCS11ModulePromise> +UtilityProcessManager::StartPKCS11Module() { + using RetPromise = PKCS11ModulePromise; + auto parent = MakeRefPtr<psm::PKCS11ModuleParent>(); + auto startPromise = StartUtility(parent, SandboxingKind::PKCS11_MODULE); + return startPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [parent = std::move(parent)]() mutable { + if (!parent->CanSend()) { + MOZ_ASSERT(false, "PKCS11ModuleParent lost in the middle"); + return RetPromise::CreateAndReject( + LaunchError("StartPKCS11Module: !parent->CanSend()"), + __PRETTY_FUNCTION__); + } + return RetPromise::CreateAndResolve(std::move(parent), __func__); + }, + [](LaunchError&& aError) { + MOZ_ASSERT_UNREACHABLE( + "StartPKCS11Module: failure when starting actor"); + return RetPromise::CreateAndReject(std::move(aError), __func__); + }); +} +#endif // !MOZ_NO_SMART_CARDS + bool UtilityProcessManager::IsProcessLaunching(SandboxingKind aSandbox) { MOZ_ASSERT(NS_IsMainThread()); diff --git a/ipc/glue/UtilityProcessManager.h b/ipc/glue/UtilityProcessManager.h @@ -15,6 +15,10 @@ #include "mozilla/PRemoteMediaManagerChild.h" +#ifndef MOZ_NO_SMART_CARDS +# include "mozilla/psm/PKCS11ModuleParent.h" +#endif // !MOZ_NO_SMART_CARDS + namespace mozilla { class MemoryReportingProcess; @@ -53,6 +57,10 @@ class UtilityProcessManager final : public UtilityProcessHost::Listener { using WinFileDialogPromise = LaunchPromise<widget::filedialog::ProcessProxy>; #endif +#ifndef MOZ_NO_SMART_CARDS + using PKCS11ModulePromise = LaunchPromise<RefPtr<psm::PKCS11ModuleParent>>; +#endif // !MOZ_NO_SMART_CARDS + static RefPtr<UtilityProcessManager> GetSingleton(); static RefPtr<UtilityProcessManager> GetIfExists(); @@ -83,6 +91,10 @@ class UtilityProcessManager final : public UtilityProcessHost::Listener { RefPtr<WinFileDialogPromise> CreateWinFileDialogActor(); #endif +#ifndef MOZ_NO_SMART_CARDS + RefPtr<PKCS11ModulePromise> StartPKCS11Module(); +#endif // !MOZ_NO_SMART_CARDS + void OnProcessUnexpectedShutdown(UtilityProcessHost* aHost); // Returns the platform pid for this utility sandbox process. diff --git a/ipc/glue/UtilityProcessSandboxing.cpp b/ipc/glue/UtilityProcessSandboxing.cpp @@ -42,6 +42,15 @@ bool IsUtilitySandboxEnabled(const char* envVar, SandboxingKind aKind) { } #endif +#ifndef MOZ_NO_SMART_CARDS + // For now, don't enable sandboxing for the pkcs11 module loader process. + // pkcs11 modules have historically been loaded in the parent process and may + // have sandboxing-compatibility problems. + if (aKind == SandboxingKind::PKCS11_MODULE) { + return false; + } +#endif // !MOZ_NO_SMART_CARDS + if (envVar == nullptr) { return true; } diff --git a/ipc/glue/UtilityProcessSandboxing.h b/ipc/glue/UtilityProcessSandboxing.h @@ -31,6 +31,9 @@ enum SandboxingKind : uint64_t { WINDOWS_UTILS, WINDOWS_FILE_DIALOG, #endif +#ifndef MOZ_NO_SMART_CARDS + PKCS11_MODULE, +#endif // !MOZ_NO_SMART_CARDS COUNT, diff --git a/security/manager/ssl/PKCS11ModuleChild.cpp b/security/manager/ssl/PKCS11ModuleChild.cpp @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef MOZ_NO_SMART_CARDS +# error This file should not be used under MOZ_NO_SMART_CARDS. +#endif // MOZ_NO_SMART_CARDS + +#include "mozilla/psm/PKCS11ModuleChild.h" + +#include "mozilla/ipc/Endpoint.h" +#include "nsDebugImpl.h" + +namespace mozilla::psm { + +nsresult PKCS11ModuleChild::Start(Endpoint<PPKCS11ModuleChild>&& aEndpoint) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mTaskQueue); + + nsDebugImpl::SetMultiprocessMode("PKCS11ModuleChild"); + + nsresult rv = NS_CreateBackgroundTaskQueue("PKCS11ModuleChild", + getter_AddRefs(mTaskQueue)); + if (NS_FAILED(rv)) { + return rv; + } + + rv = mTaskQueue->Dispatch(NS_NewRunnableFunction( + "PKCS11ModuleChild::StartBind", + [self = RefPtr{this}, endpoint = std::move(aEndpoint)]() mutable { + MOZ_ALWAYS_TRUE(endpoint.Bind(self)); + })); + return rv; +} + +} // namespace mozilla::psm diff --git a/security/manager/ssl/PKCS11ModuleChild.h b/security/manager/ssl/PKCS11ModuleChild.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_psm_PKCS11ModuleChild_h +#define mozilla_psm_PKCS11ModuleChild_h + +#ifdef MOZ_NO_SMART_CARDS +# error This file should not be used under MOZ_NO_SMART_CARDS. +#endif // MOZ_NO_SMART_CARDS + +#include "mozilla/psm/PPKCS11ModuleChild.h" +#include "nsIObserver.h" +#include "nsISupports.h" + +namespace mozilla::psm { + +class PKCS11ModuleChild final : public PPKCS11ModuleChild { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PKCS11ModuleChild, override); + + PKCS11ModuleChild() = default; + + nsresult Start(Endpoint<PPKCS11ModuleChild>&& aEndpoint); + + private: + nsCOMPtr<nsISerialEventTarget> mTaskQueue; + + ~PKCS11ModuleChild() = default; +}; + +} // namespace mozilla::psm + +#endif // mozilla_psm_PKCS11ModuleChild_h diff --git a/security/manager/ssl/PKCS11ModuleParent.cpp b/security/manager/ssl/PKCS11ModuleParent.cpp @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef MOZ_NO_SMART_CARDS +# error This file should not be used under MOZ_NO_SMART_CARDS. +#endif // MOZ_NO_SMART_CARDS + +#include "mozilla/psm/PKCS11ModuleParent.h" + +namespace mozilla::psm { + +nsresult PKCS11ModuleParent::BindToUtilityProcess( + const RefPtr<ipc::UtilityProcessParent>& aUtilityParent) { + Endpoint<PPKCS11ModuleParent> parentEnd; + Endpoint<PPKCS11ModuleChild> childEnd; + nsresult rv = PPKCS11Module::CreateEndpoints( + ipc::EndpointProcInfo::Current(), aUtilityParent->OtherEndpointProcInfo(), + &parentEnd, &childEnd); + + if (NS_FAILED(rv)) { + MOZ_ASSERT_UNREACHABLE("Protocol endpoints failure"); + return NS_ERROR_FAILURE; + } + + if (!aUtilityParent->SendStartPKCS11ModuleService(std::move(childEnd))) { + MOZ_ASSERT_UNREACHABLE("StartPKCS11Module service failure"); + return NS_ERROR_FAILURE; + } + + if (!parentEnd.Bind(this)) { + MOZ_ASSERT_UNREACHABLE("StartPKCS11Module service failure"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +} // namespace mozilla::psm diff --git a/security/manager/ssl/PKCS11ModuleParent.h b/security/manager/ssl/PKCS11ModuleParent.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_psm_PKCS11ModuleParent_h +#define mozilla_psm_PKCS11ModuleParent_h + +#ifdef MOZ_NO_SMART_CARDS +# error This file should not be used under MOZ_NO_SMART_CARDS. +#endif // MOZ_NO_SMART_CARDS + +#include "mozilla/ProcInfo.h" + +#include "mozilla/ipc/UtilityProcessParent.h" +#include "mozilla/psm/PPKCS11ModuleParent.h" + +namespace mozilla::psm { + +class PKCS11ModuleParent final : public PPKCS11ModuleParent { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PKCS11ModuleParent, override); + + explicit PKCS11ModuleParent() = default; + + UtilityActorName GetActorName() { return UtilityActorName::Pkcs11Module; } + + nsresult BindToUtilityProcess( + const RefPtr<ipc::UtilityProcessParent>& aUtilityParent); + + private: + ~PKCS11ModuleParent() = default; +}; + +} // namespace mozilla::psm + +#endif // mozilla_psm_PKCS11ModuleParent_h diff --git a/security/manager/ssl/PPKCS11Module.ipdl b/security/manager/ssl/PPKCS11Module.ipdl @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +namespace mozilla { + +namespace psm { + +[ChildProc=Utility] +protocol PPKCS11Module +{ +}; + +} // namespace psm + +} // namespace mozilla diff --git a/security/manager/ssl/moz.build b/security/manager/ssl/moz.build @@ -213,6 +213,21 @@ if CONFIG["OS_ARCH"] == "WINNT": "CredentialManagerSecret.cpp", ] +if not CONFIG["MOZ_NO_SMART_CARDS"]: + EXPORTS.mozilla.psm += [ + "PKCS11ModuleChild.h", + "PKCS11ModuleParent.h", + ] + + UNIFIED_SOURCES += [ + "PKCS11ModuleChild.cpp", + "PKCS11ModuleParent.cpp", + ] + + IPDL_SOURCES += [ + "PPKCS11Module.ipdl", + ] + FINAL_LIBRARY = "xul" LOCAL_INCLUDES += [ diff --git a/security/manager/ssl/tests/gtest/UtilityPKCS11ModuleTest.cpp b/security/manager/ssl/tests/gtest/UtilityPKCS11ModuleTest.cpp @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef MOZ_NO_SMART_CARDS +# error This file should not be used under MOZ_NO_SMART_CARDS. +#endif // MOZ_NO_SMART_CARDS + +#include "gtest/gtest.h" +#include "mozilla/gtest/ipc/TestUtilityProcess.h" +#include "mozilla/gtest/WaitFor.h" +#include "mozilla/ipc/UtilityProcessManager.h" +#include "mozilla/psm/PKCS11ModuleParent.h" +#include "nsThreadUtils.h" + +using namespace mozilla; +using namespace mozilla::gtest::ipc; +using namespace mozilla::ipc; +using namespace mozilla::psm; + +class psm_UtilityPKCS11Module : public TestUtilityProcess {}; + +TEST_F(psm_UtilityPKCS11Module, Launch) { + auto manager = UtilityProcessManager::GetSingleton(); + ASSERT_TRUE(manager); + + auto res = WaitFor(manager->StartPKCS11Module()); + ASSERT_TRUE(res.isOk()) + << "LaunchError: " << res.inspectErr().FunctionName() << ", " + << res.inspectErr().ErrorCode(); + + auto parent = res.unwrap(); + ASSERT_TRUE(parent); + ASSERT_TRUE(parent->CanSend()); + + auto utilityPid = manager->ProcessPid(SandboxingKind::PKCS11_MODULE); + ASSERT_TRUE(utilityPid.isSome()); + ASSERT_GE(*utilityPid, base::ProcessId(1)); + + manager->CleanShutdown(SandboxingKind::PKCS11_MODULE); + + utilityPid = manager->ProcessPid(SandboxingKind::PKCS11_MODULE); + ASSERT_TRUE(utilityPid.isNothing()); + + // Drain the event queue. + NS_ProcessPendingEvents(nullptr); +} diff --git a/security/manager/ssl/tests/gtest/moz.build b/security/manager/ssl/tests/gtest/moz.build @@ -15,6 +15,11 @@ SOURCES += [ "TLSIntoleranceTest.cpp", ] +if not CONFIG["MOZ_NO_SMART_CARDS"]: + SOURCES += [ + "UtilityPKCS11ModuleTest.cpp", + ] + LOCAL_INCLUDES += [ "/security/certverifier", "/security/manager/ssl", diff --git a/toolkit/components/aboutprocesses/content/aboutProcesses.js b/toolkit/components/aboutprocesses/content/aboutProcesses.js @@ -917,6 +917,10 @@ var View = { fluentName = "about-processes-utility-actor-windows-file-dialog"; break; + case "pkcs11Module": + fluentName = "about-processes-utility-actor-pkcs11-module"; + break; + default: fluentName = "about-processes-utility-actor-unknown"; break; diff --git a/toolkit/components/processtools/ProcInfo_common.cpp b/toolkit/components/processtools/ProcInfo_common.cpp @@ -59,6 +59,8 @@ nsCString GetUtilityActorName(const UtilityActorName aActorName) { return "windows-utils"_ns; case UtilityActorName::WindowsFileDialog: return "windows-file-dialog"_ns; + case UtilityActorName::Pkcs11Module: + return "pkcs11-module"_ns; default: return "unknown"_ns; } diff --git a/toolkit/locales/en-US/toolkit/about/aboutProcesses.ftl b/toolkit/locales/en-US/toolkit/about/aboutProcesses.ftl @@ -135,6 +135,7 @@ about-processes-utility-actor-mf-media-engine = Windows Media Foundation Media E about-processes-utility-actor-js-oracle = JavaScript Oracle about-processes-utility-actor-windows-utils = Windows Utils about-processes-utility-actor-windows-file-dialog = Windows File Dialog +about-processes-utility-actor-pkcs11-module = Security Module Helper ## Displaying CPU (percentage and total) ## Variables: