feat(servo): isolate profiles with hardware sidecars

This commit is contained in:
2026-07-09 20:27:22 -04:00
parent 78dc86b18e
commit c28ec2bee8
92 changed files with 10306 additions and 1485 deletions
@@ -0,0 +1,176 @@
use std::{error::Error, ffi::CString, io, mem, time::Duration};
use mach2::{
bootstrap::{bootstrap_port, bootstrap_register},
kern_return::KERN_SUCCESS,
mach_port::{
mach_port_allocate, mach_port_deallocate, mach_port_destroy, mach_port_insert_right,
},
message::{
MACH_MSG_PORT_DESCRIPTOR, MACH_MSG_SUCCESS, MACH_MSG_TYPE_MAKE_SEND, MACH_RCV_MSG,
MACH_RCV_TIMED_OUT, MACH_RCV_TIMEOUT, mach_msg, mach_msg_body_t, mach_msg_header_t,
mach_msg_port_descriptor_t, mach_msg_trailer_t,
},
port::{MACH_PORT_NULL, MACH_PORT_RIGHT_RECEIVE, mach_port_t},
traps::mach_task_self,
};
const IOSURFACE_PORT_MESSAGE_ID: i32 = 0x454c_5901;
pub(super) struct MachSurfaceReceiver {
service_name: String,
receive_port: mach_port_t,
}
impl MachSurfaceReceiver {
pub(super) fn new() -> Result<Self, Box<dyn Error>> {
let service_name =
format!("com.ely.browser.iosurface.test.{}", ely_domain::ProfileId::new().as_str());
let service_name_c = CString::new(service_name.as_str())?;
let mut receive_port = MACH_PORT_NULL;
#[expect(unsafe_code)]
let task = unsafe { mach_task_self() };
#[expect(unsafe_code)]
let allocate =
unsafe { mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &mut receive_port) };
if allocate != KERN_SUCCESS {
return Err(io::Error::other(format!("mach_port_allocate returned {allocate}")).into());
}
#[expect(unsafe_code)]
let insert = unsafe {
mach_port_insert_right(task, receive_port, receive_port, MACH_MSG_TYPE_MAKE_SEND)
};
if insert != KERN_SUCCESS {
destroy_port(receive_port);
return Err(
io::Error::other(format!("mach_port_insert_right returned {insert}")).into()
);
}
#[expect(unsafe_code)]
#[allow(deprecated)]
let register = unsafe {
bootstrap_register(bootstrap_port, service_name_c.as_ptr() as *mut _, receive_port)
};
if register != KERN_SUCCESS {
destroy_port(receive_port);
return Err(io::Error::other(format!("bootstrap_register returned {register}")).into());
}
Ok(Self { service_name, receive_port })
}
pub(super) fn service_name(&self) -> &str {
self.service_name.as_str()
}
pub(super) fn receive(
&self,
expected_surface_id: u64,
timeout: Duration,
) -> Result<mach_port_t, Box<dyn Error>> {
#[expect(unsafe_code)]
let mut received: ReceivedIOSurfacePortMessage = unsafe { mem::zeroed() };
#[expect(unsafe_code)]
let result = unsafe {
mach_msg(
&mut received.message.header,
MACH_RCV_MSG | MACH_RCV_TIMEOUT,
0,
mem::size_of::<ReceivedIOSurfacePortMessage>() as u32,
self.receive_port,
timeout_millis(timeout),
MACH_PORT_NULL,
)
};
if result == MACH_RCV_TIMED_OUT {
return Err(io::Error::new(
io::ErrorKind::TimedOut,
format!("Mach receive timed out for surface {expected_surface_id}"),
)
.into());
}
if result != MACH_MSG_SUCCESS {
return Err(io::Error::other(format!("mach_msg receive returned {result}")).into());
}
let message = &mut received.message;
if message.header.msgh_id != IOSURFACE_PORT_MESSAGE_ID
|| message.body.msgh_descriptor_count != 1
|| message.surface_port.type_ != MACH_MSG_PORT_DESCRIPTOR as u8
|| message.surface_port.name == MACH_PORT_NULL
|| message.surface_id != expected_surface_id
{
destroy_message(message);
return Err(io::Error::other("received invalid IOSurface Mach message").into());
}
Ok(message.surface_port.name)
}
}
impl Drop for MachSurfaceReceiver {
fn drop(&mut self) {
destroy_port(self.receive_port);
}
}
pub(super) fn verify_iosurface(
mach_port: mach_port_t,
width: u32,
height: u32,
) -> Result<(), Box<dyn Error>> {
let surface = objc2_io_surface::IOSurfaceRef::lookup_from_mach_port(mach_port)
.ok_or_else(|| io::Error::other("IOSurfaceLookupFromMachPort returned null"))?;
let actual_width = u32::try_from(surface.width())?;
let actual_height = u32::try_from(surface.height())?;
deallocate_port(mach_port)?;
if actual_width != width || actual_height != height {
return Err(io::Error::other(format!(
"imported IOSurface was {actual_width}x{actual_height}; expected {width}x{height}"
))
.into());
}
Ok(())
}
#[repr(C)]
struct IOSurfacePortMessage {
header: mach_msg_header_t,
body: mach_msg_body_t,
surface_port: mach_msg_port_descriptor_t,
surface_id: u64,
}
#[repr(C)]
struct ReceivedIOSurfacePortMessage {
message: IOSurfacePortMessage,
_trailer: mach_msg_trailer_t,
}
fn timeout_millis(timeout: Duration) -> u32 {
u32::try_from(timeout.as_millis()).unwrap_or(u32::MAX).max(1)
}
fn destroy_message(message: &mut IOSurfacePortMessage) {
#[expect(unsafe_code)]
unsafe {
mach2::message::mach_msg_destroy(&mut message.header);
}
}
fn destroy_port(port: mach_port_t) {
#[expect(unsafe_code)]
let task = unsafe { mach_task_self() };
#[expect(unsafe_code)]
unsafe {
let _ = mach_port_destroy(task, port);
}
}
fn deallocate_port(port: mach_port_t) -> Result<(), Box<dyn Error>> {
#[expect(unsafe_code)]
let task = unsafe { mach_task_self() };
#[expect(unsafe_code)]
let result = unsafe { mach_port_deallocate(task, port) };
if result != KERN_SUCCESS {
return Err(io::Error::other(format!("mach_port_deallocate returned {result}")).into());
}
Ok(())
}