tor-browser

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

commit af8df68927a9db0a0eb0392356355e182bc78ab9
parent 121f01a45180816c6f57f157caea101dd94d20d5
Author: Gabriele Svelto <gsvelto@mozilla.com>
Date:   Thu, 27 Nov 2025 15:29:51 +0000

Bug 1989686 - Stop duplicating handles when scheduling overlapped operations r=afranchuk

This removes the owned handle we used in overlapped operations to avoid
the crash in bug 1974259. The handle is now replaced with a counted
reference to the source handle.

Differential Revision: https://phabricator.services.mozilla.com/D270528

Diffstat:
Mtoolkit/crashreporter/crash_helper_common/src/ipc_connector/windows.rs | 26+++++++++-----------------
Mtoolkit/crashreporter/crash_helper_common/src/ipc_listener/windows.rs | 37++++++++++++++++++++++++-------------
Mtoolkit/crashreporter/crash_helper_common/src/platform/windows.rs | 15++++++++-------
3 files changed, 41 insertions(+), 37 deletions(-)

diff --git a/toolkit/crashreporter/crash_helper_common/src/ipc_connector/windows.rs b/toolkit/crashreporter/crash_helper_common/src/ipc_connector/windows.rs @@ -14,6 +14,7 @@ use std::{ io::Error, os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle}, ptr::null_mut, + rc::Rc, str::FromStr, time::{Duration, Instant}, }; @@ -68,7 +69,7 @@ fn extract_buffer_and_handle(buffer: Vec<u8>) -> Result<(Vec<u8>, Option<OwnedHa pub struct IPCConnector { /// A connected pipe handle - handle: OwnedHandle, + handle: Rc<OwnedHandle>, /// A handle to an event which will be used for overlapped I/O on the pipe event: OwnedHandle, /// Stores the only pending operation we might have on the pipe @@ -83,7 +84,7 @@ impl IPCConnector { let event = create_manual_reset_event()?; Ok(IPCConnector { - handle, + handle: Rc::new(handle), event, overlapped: None, process: None, @@ -205,11 +206,11 @@ impl IPCConnector { } pub fn into_ancillary(self) -> AncillaryData { - self.handle + Rc::try_unwrap(self.handle).expect("Multiple references to the underlying handle") } pub fn into_raw_ancillary(self) -> RawAncillaryData { - self.handle.into_raw() + self.into_ancillary().into_raw() } pub fn send_message<T>(&self, message: T) -> Result<(), IPCError> @@ -252,9 +253,7 @@ impl IPCConnector { } self.overlapped = Some(OverlappedOperation::sched_recv( - self.handle - .try_clone() - .map_err(IPCError::CloneHandleFailed)?, + &self.handle, self.event_raw_handle(), HANDLE_SIZE + messages::HEADER_SIZE, )?); @@ -281,21 +280,14 @@ impl IPCConnector { buffer.extend(handle.to_ne_bytes()); buffer.extend(buff); - let overlapped = OverlappedOperation::sched_send( - self.handle - .try_clone() - .map_err(IPCError::CloneHandleFailed)?, - self.event_raw_handle(), - buffer, - )?; + let overlapped = + OverlappedOperation::sched_send(&self.handle, self.event_raw_handle(), buffer)?; overlapped.complete_send(/* wait */ true) } pub fn recv(&self, expected_size: usize) -> Result<(Vec<u8>, Option<AncillaryData>), IPCError> { let overlapped = OverlappedOperation::sched_recv( - self.handle - .try_clone() - .map_err(IPCError::CloneHandleFailed)?, + &self.handle, self.event_raw_handle(), HANDLE_SIZE + expected_size, )?; diff --git a/toolkit/crashreporter/crash_helper_common/src/ipc_listener/windows.rs b/toolkit/crashreporter/crash_helper_common/src/ipc_listener/windows.rs @@ -12,6 +12,7 @@ use std::{ ffi::{CStr, CString, OsString}, os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle, RawHandle}, ptr::null_mut, + rc::Rc, str::FromStr, }; use windows_sys::Win32::{ @@ -27,9 +28,13 @@ use windows_sys::Win32::{ }; pub struct IPCListener { + /// The name of the pipe this listener will be bound to server_addr: CString, - handle: OwnedHandle, + /// A named pipe handle listening for incoming connections + handle: Rc<OwnedHandle>, + /// Stores the only pending operation we might have on the pipe overlapped: Option<OverlappedOperation>, + /// A handle to an event which will be used for overlapped I/O on the pipe event: OwnedHandle, } @@ -40,7 +45,7 @@ impl IPCListener { Ok(IPCListener { server_addr, - handle: pipe, + handle: Rc::new(pipe), overlapped: None, event, }) @@ -56,28 +61,34 @@ impl IPCListener { pub(crate) fn listen(&mut self) -> Result<(), IPCError> { self.overlapped = Some(OverlappedOperation::listen( - self.handle - .try_clone() - .map_err(IPCError::CloneHandleFailed)?, + &self.handle, self.event_raw_handle(), )?); Ok(()) } pub fn accept(&mut self) -> Result<IPCConnector, IPCError> { - // We should never call accept() on a listener that wasn't - // already waiting, so panic in that scenario. - let overlapped = self.overlapped.take().unwrap(); - overlapped.accept(self.handle.as_raw_handle() as HANDLE)?; - let new_pipe = create_named_pipe(&self.server_addr, /* first_instance */ false)?; - let connected_pipe = std::mem::replace(&mut self.handle, new_pipe); + let connected_pipe = { + // We extract the overlapped operation within this scope so + // that it's dropped right away. This ensures that only one + // reference to the listener's handle remains. + let overlapped = self + .overlapped + .take() + .expect("Accepting a connection without listening first"); + overlapped.accept(self.handle.as_raw_handle() as HANDLE)?; + let new_pipe = create_named_pipe(&self.server_addr, /* first_instance */ false)?; + std::mem::replace(&mut self.handle, Rc::new(new_pipe)) + }; // Once we've accepted a new connection and replaced the listener's // pipe we need to listen again before we return, so that we're ready // for the next iteration. self.listen()?; - IPCConnector::from_ancillary(connected_pipe) + // We can guarantee that there's only one reference to this handle at + // this point in time. + IPCConnector::from_ancillary(Rc::<OwnedHandle>::try_unwrap(connected_pipe).unwrap()) } /// Serialize this listener into a string that can be passed on the @@ -100,7 +111,7 @@ impl IPCListener { let mut listener = IPCListener { server_addr, - handle, + handle: Rc::new(handle), overlapped: None, event, }; diff --git a/toolkit/crashreporter/crash_helper_common/src/platform/windows.rs b/toolkit/crashreporter/crash_helper_common/src/platform/windows.rs @@ -11,6 +11,7 @@ use std::{ mem::zeroed, os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle, RawHandle}, ptr::{null, null_mut}, + rc::Rc, }; use windows_sys::Win32::{ Foundation::{ @@ -96,7 +97,7 @@ fn cancel_overlapped_io(handle: HANDLE, overlapped: &mut OVERLAPPED) -> bool { } pub(crate) struct OverlappedOperation { - handle: OwnedHandle, + handle: Rc<OwnedHandle>, overlapped: Option<Box<OVERLAPPED>>, buffer: Option<Vec<u8>>, } @@ -108,7 +109,7 @@ enum OverlappedOperationType { impl OverlappedOperation { pub(crate) fn listen( - handle: OwnedHandle, + handle: &Rc<OwnedHandle>, event: HANDLE, ) -> Result<OverlappedOperation, IPCError> { let mut overlapped = Self::overlapped_with_event(event)?; @@ -134,7 +135,7 @@ impl OverlappedOperation { } Ok(OverlappedOperation { - handle, + handle: handle.clone(), overlapped: Some(overlapped), buffer: None, }) @@ -209,7 +210,7 @@ impl OverlappedOperation { } pub(crate) fn sched_recv( - handle: OwnedHandle, + handle: &Rc<OwnedHandle>, event: HANDLE, expected_size: usize, ) -> Result<OverlappedOperation, IPCError> { @@ -239,7 +240,7 @@ impl OverlappedOperation { } Ok(OverlappedOperation { - handle, + handle: handle.clone(), overlapped: Some(overlapped), buffer: Some(buffer), }) @@ -250,7 +251,7 @@ impl OverlappedOperation { } pub(crate) fn sched_send( - handle: OwnedHandle, + handle: &Rc<OwnedHandle>, event: HANDLE, mut buffer: Vec<u8>, ) -> Result<OverlappedOperation, IPCError> { @@ -279,7 +280,7 @@ impl OverlappedOperation { } Ok(OverlappedOperation { - handle, + handle: handle.clone(), overlapped: Some(overlapped), buffer: Some(buffer), })