diff --git a/src/cli/input.rs b/src/cli/input.rs index b41c2c4b..46625bd5 100644 --- a/src/cli/input.rs +++ b/src/cli/input.rs @@ -353,8 +353,9 @@ impl Input { async fn handle_keymap(&self, input: JayInputId) -> Vec { let data = Rc::new(RefCell::new(Vec::new())); jay_input::Keymap::handle(&self.tc, input, data.clone(), |d, map| { - let mem = Rc::new(ClientMem::new(map.keymap.raw(), map.keymap_len as _, true).unwrap()) - .offset(0); + let mem = + Rc::new(ClientMem::new(&map.keymap, map.keymap_len as _, true, None).unwrap()) + .offset(0); mem.read(d.borrow_mut().deref_mut()).unwrap(); }); self.tc.round_trip().await; diff --git a/src/clientmem.rs b/src/clientmem.rs index f85dc5e7..1c8e9c98 100644 --- a/src/clientmem.rs +++ b/src/clientmem.rs @@ -1,5 +1,5 @@ use { - crate::utils::vec_ext::VecExt, + crate::{client::Client, utils::vec_ext::VecExt}, std::{ cell::Cell, mem::MaybeUninit, @@ -8,7 +8,10 @@ use { sync::atomic::{compiler_fence, Ordering}, }, thiserror::Error, - uapi::{c, c::raise}, + uapi::{ + c::{self, raise}, + OwnedFd, + }, }; #[derive(Debug, Error)] @@ -22,6 +25,7 @@ pub enum ClientMemError { } pub struct ClientMem { + fd: Rc, failed: Cell, sigbus_impossible: bool, data: *const [Cell], @@ -30,19 +34,34 @@ pub struct ClientMem { #[derive(Clone)] pub struct ClientMemOffset { mem: Rc, + offset: usize, data: *const [Cell], } impl ClientMem { - pub fn new(fd: i32, len: usize, read_only: bool) -> Result { + pub fn new( + fd: &Rc, + len: usize, + read_only: bool, + client: Option<&Client>, + ) -> Result { let mut sigbus_impossible = false; - if let Ok(seals) = uapi::fcntl_get_seals(fd) { + if let Ok(seals) = uapi::fcntl_get_seals(fd.raw()) { if seals & c::F_SEAL_SHRINK != 0 { - if let Ok(stat) = uapi::fstat(fd) { + if let Ok(stat) = uapi::fstat(fd.raw()) { sigbus_impossible = stat.st_size as u64 >= len as u64; } } } + if !sigbus_impossible { + if let Some(client) = client { + log::debug!( + "Client {} ({}) has created a shm buffer that might cause SIGBUS", + client.pid_info.comm, + client.id, + ); + } + } let data = if len == 0 { &mut [][..] } else { @@ -51,7 +70,7 @@ impl ClientMem { false => c::PROT_READ | c::PROT_WRITE, }; unsafe { - let data = c::mmap64(ptr::null_mut(), len, prot, c::MAP_SHARED, fd, 0); + let data = c::mmap64(ptr::null_mut(), len, prot, c::MAP_SHARED, fd.raw(), 0); if data == c::MAP_FAILED { return Err(ClientMemError::MmapFailed(uapi::Errno::default().into())); } @@ -59,6 +78,7 @@ impl ClientMem { } }; Ok(Self { + fd: fd.clone(), failed: Cell::new(false), sigbus_impossible, data, @@ -73,12 +93,38 @@ impl ClientMem { let mem = unsafe { &*self.data }; ClientMemOffset { mem: self.clone(), + offset, data: &mem[offset..], } } + + #[expect(dead_code)] + pub fn fd(&self) -> &Rc { + &self.fd + } + + #[expect(dead_code)] + pub fn sigbus_impossible(&self) -> bool { + self.sigbus_impossible + } } impl ClientMemOffset { + #[expect(dead_code)] + pub fn pool(&self) -> &ClientMem { + &self.mem + } + + #[expect(dead_code)] + pub fn offset(&self) -> usize { + self.offset + } + + #[expect(dead_code)] + pub fn ptr(&self) -> *const [Cell] { + self.data + } + pub fn access]) -> T>(&self, f: F) -> Result { unsafe { if self.mem.sigbus_impossible { diff --git a/src/ifs/jay_input.rs b/src/ifs/jay_input.rs index f0362763..8d196063 100644 --- a/src/ifs/jay_input.rs +++ b/src/ifs/jay_input.rs @@ -165,11 +165,11 @@ impl JayInput { } } - fn set_keymap_impl(&self, keymap: &OwnedFd, len: u32, f: F) -> Result<(), JayInputError> + fn set_keymap_impl(&self, keymap: &Rc, len: u32, f: F) -> Result<(), JayInputError> where F: FnOnce(&Rc) -> Result<(), JayInputError>, { - let cm = Rc::new(ClientMem::new(keymap.raw(), len as _, true)?).offset(0); + let cm = Rc::new(ClientMem::new(keymap, len as _, true, Some(&self.client))?).offset(0); let mut map = vec![]; cm.read(&mut map)?; self.or_error(|| { diff --git a/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs b/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs index 2dde71f4..914ac247 100644 --- a/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs +++ b/src/ifs/wl_seat/zwp_virtual_keyboard_v1.rs @@ -56,7 +56,7 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 { if req.size > MAX_SIZE { return Err(ZwpVirtualKeyboardV1Error::OversizedKeymap); } - let client_mem = ClientMem::new(req.fd.raw(), req.size as usize - 1, true) + let client_mem = ClientMem::new(&req.fd, req.size as usize - 1, true, Some(&self.client)) .map(Rc::new) .map_err(ZwpVirtualKeyboardV1Error::MapKeymap)?; let mut map = vec![]; diff --git a/src/ifs/wl_shm_pool.rs b/src/ifs/wl_shm_pool.rs index 30687f6c..6ea0c670 100644 --- a/src/ifs/wl_shm_pool.rs +++ b/src/ifs/wl_shm_pool.rs @@ -34,7 +34,7 @@ impl WlShmPool { Ok(Self { id, client: client.clone(), - mem: CloneCell::new(Rc::new(ClientMem::new(fd.raw(), len, false)?)), + mem: CloneCell::new(Rc::new(ClientMem::new(&fd, len, false, Some(client))?)), fd, tracker: Default::default(), version, @@ -82,9 +82,10 @@ impl WlShmPoolRequestHandler for WlShmPool { return Err(WlShmPoolError::CannotShrink); } self.mem.set(Rc::new(ClientMem::new( - self.fd.raw(), + &self.fd, req.size as usize, false, + Some(&self.client), )?)); Ok(()) } diff --git a/src/it/tests/t0040_virtual_keyboard.rs b/src/it/tests/t0040_virtual_keyboard.rs index bf6519f2..bc0627c3 100644 --- a/src/it/tests/t0040_virtual_keyboard.rs +++ b/src/it/tests/t0040_virtual_keyboard.rs @@ -7,6 +7,7 @@ use { }, bstr::ByteSlice, std::rc::Rc, + uapi::OwnedFd, }; testcase!(); @@ -15,7 +16,7 @@ async fn test(run: Rc) -> TestResult { let virtual_keymap_str = { let xkb = XkbContext::new()?; let map = xkb.keymap_from_str(VIRTUAL_KEYMAP).unwrap(); - read_keymap(map.map.raw(), map.map_len) + read_keymap(&map.map, map.map_len) }; let ds = run.create_default_setup().await?; @@ -51,7 +52,7 @@ async fn test(run: Rc) -> TestResult { s_client.sync().await; let (start, keymap) = s_keymap.next().expect("virtual keymap"); tassert_eq!( - &read_keymap(keymap.fd.raw(), keymap.size as _), + &read_keymap(&keymap.fd, keymap.size as _), &virtual_keymap_str ); { @@ -119,7 +120,7 @@ async fn test(run: Rc) -> TestResult { s_client.sync().await; let (pos, keymap) = s_keymap.next().expect("seat keymap"); tassert_eq!(pos, start + 8); - tassert!(read_keymap(keymap.fd.raw(), keymap.size as _) != virtual_keymap_str); + tassert!(read_keymap(&keymap.fd, keymap.size as _) != virtual_keymap_str); { let (pos, mods) = s_modifiers.next().expect("mods 0"); tassert_eq!(pos, start + 9); @@ -147,8 +148,8 @@ async fn test(run: Rc) -> TestResult { Ok(()) } -fn read_keymap(fd: i32, size: usize) -> String { - let client_mem = ClientMem::new(fd, size - 1, true).unwrap(); +fn read_keymap(fd: &Rc, size: usize) -> String { + let client_mem = ClientMem::new(fd, size - 1, true, None).unwrap(); let client_mem = Rc::new(client_mem).offset(0); let mut v = vec![]; client_mem.read(&mut v).unwrap();