Bug 1964125 - osclientcerts: ensure os-backed resources are dropped before background threads go away r=jschanck

Differential Revision: https://phabricator.services.mozilla.com/D247655
This commit is contained in:
Dana Keeler
2025-05-02 21:48:48 +00:00
committed by dkeeler@mozilla.com
parent 40832e607b
commit d80fc606b6
3 changed files with 53 additions and 0 deletions

2
Cargo.lock generated
View File

@@ -4976,12 +4976,14 @@ dependencies = [
"android_logger", "android_logger",
"byteorder", "byteorder",
"core-foundation 0.9.999", "core-foundation 0.9.999",
"cstr",
"env_logger", "env_logger",
"futures-executor", "futures-executor",
"lazy_static", "lazy_static",
"libloading", "libloading",
"log", "log",
"moz_task", "moz_task",
"nserror",
"pkcs11-bindings", "pkcs11-bindings",
"rsclientcerts", "rsclientcerts",
"sha2", "sha2",

View File

@@ -8,10 +8,12 @@ license = "MPL-2.0"
[dependencies] [dependencies]
byteorder = "1.3" byteorder = "1.3"
cstr = "0.2"
env_logger = {version = "0.10", default-features = false } # disable `regex` to reduce code size env_logger = {version = "0.10", default-features = false } # disable `regex` to reduce code size
futures-executor = { version = "0.3" } futures-executor = { version = "0.3" }
lazy_static = "1" lazy_static = "1"
log = "0.4" log = "0.4"
nserror = { path = "../../../../xpcom/rust/nserror" }
moz_task = { path = "../../../../xpcom/rust/moz_task" } moz_task = { path = "../../../../xpcom/rust/moz_task" }
pkcs11-bindings = "0.1" pkcs11-bindings = "0.1"
rsclientcerts = { path = "../rsclientcerts" } rsclientcerts = { path = "../rsclientcerts" }

View File

@@ -9,6 +9,8 @@ extern crate byteorder;
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_use] #[macro_use]
extern crate core_foundation; extern crate core_foundation;
#[macro_use]
extern crate cstr;
extern crate env_logger; extern crate env_logger;
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_use] #[macro_use]
@@ -23,13 +25,17 @@ extern crate rsclientcerts;
extern crate sha2; extern crate sha2;
#[cfg(all(target_os = "windows", not(target_arch = "aarch64")))] #[cfg(all(target_os = "windows", not(target_arch = "aarch64")))]
extern crate winapi; extern crate winapi;
#[macro_use]
extern crate xpcom; extern crate xpcom;
use nserror::{nsresult, NS_OK};
use pkcs11_bindings::*; use pkcs11_bindings::*;
use rsclientcerts::manager::Manager; use rsclientcerts::manager::Manager;
use std::convert::TryInto; use std::convert::TryInto;
use std::os::raw::c_char;
use std::sync::Mutex; use std::sync::Mutex;
use std::thread; use std::thread;
use xpcom::interfaces::{nsIObserverService, nsISupports};
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
mod backend_android; mod backend_android;
@@ -93,6 +99,28 @@ macro_rules! log_with_thread_id {
}; };
} }
#[xpcom(implement(nsIObserver), nonatomic)]
struct ShutdownObserver {}
impl ShutdownObserver {
xpcom_method!(observe => Observe(_subject: *const nsISupports, topic: *const c_char, _data: *const u16));
/// Ensure any OS-backed resources are released on the proper thread before all non-main
/// threads are shut down. Also remove this observer.
fn observe(
&self,
_subject: &nsISupports,
topic: *const c_char,
_data: *const u16,
) -> Result<(), nsresult> {
// Ignore errors since we're shutting down and there's no sensible way to handle them.
let _ = C_Finalize(std::ptr::null_mut());
if let Ok(service) = xpcom::components::Observer::service::<nsIObserverService>() {
let _ = unsafe { service.RemoveObserver(self.coerce(), topic) };
}
Ok(())
}
}
/// This gets called to initialize the module. For this implementation, this consists of /// This gets called to initialize the module. For this implementation, this consists of
/// instantiating the `Manager`. /// instantiating the `Manager`.
extern "C" fn C_Initialize(_pInitArgs: CK_VOID_PTR) -> CK_RV { extern "C" fn C_Initialize(_pInitArgs: CK_VOID_PTR) -> CK_RV {
@@ -124,6 +152,27 @@ extern "C" fn C_Initialize(_pInitArgs: CK_VOID_PTR) -> CK_RV {
} }
None => {} None => {}
} }
// Register an observer to release any OS-backed resources on the background thread at shutdown,
// before the background thread goes away. Ideally this will have already happened due to
// nsNSSComponent shutting down, but if there are any lingering network connections, this module
// may not have been unloaded yet.
if let Ok(main_thread) = moz_task::get_main_thread() {
moz_task::spawn_onto("register shutdown observer", main_thread.coerce(), async {
if let Ok(service) = xpcom::components::Observer::service::<nsIObserverService>() {
let observer = ShutdownObserver::allocate(InitShutdownObserver {});
unsafe {
let _ = service.AddObserver(
observer.coerce(),
cstr!("xpcom-shutdown").as_ptr(),
false,
);
};
}
})
.detach();
}
log_with_thread_id!(debug, "C_Initialize: CKR_OK"); log_with_thread_id!(debug, "C_Initialize: CKR_OK");
CKR_OK CKR_OK
} }