1
0
Fork 0
forked from wry/wry

clientmem: store more information about mappings

This commit is contained in:
Julian Orth 2024-09-07 17:00:08 +02:00
parent 92f7cb56fd
commit 604974c927
6 changed files with 67 additions and 18 deletions

View file

@ -353,8 +353,9 @@ impl Input {
async fn handle_keymap(&self, input: JayInputId) -> Vec<u8> { async fn handle_keymap(&self, input: JayInputId) -> Vec<u8> {
let data = Rc::new(RefCell::new(Vec::new())); let data = Rc::new(RefCell::new(Vec::new()));
jay_input::Keymap::handle(&self.tc, input, data.clone(), |d, map| { 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()) let mem =
.offset(0); Rc::new(ClientMem::new(&map.keymap, map.keymap_len as _, true, None).unwrap())
.offset(0);
mem.read(d.borrow_mut().deref_mut()).unwrap(); mem.read(d.borrow_mut().deref_mut()).unwrap();
}); });
self.tc.round_trip().await; self.tc.round_trip().await;

View file

@ -1,5 +1,5 @@
use { use {
crate::utils::vec_ext::VecExt, crate::{client::Client, utils::vec_ext::VecExt},
std::{ std::{
cell::Cell, cell::Cell,
mem::MaybeUninit, mem::MaybeUninit,
@ -8,7 +8,10 @@ use {
sync::atomic::{compiler_fence, Ordering}, sync::atomic::{compiler_fence, Ordering},
}, },
thiserror::Error, thiserror::Error,
uapi::{c, c::raise}, uapi::{
c::{self, raise},
OwnedFd,
},
}; };
#[derive(Debug, Error)] #[derive(Debug, Error)]
@ -22,6 +25,7 @@ pub enum ClientMemError {
} }
pub struct ClientMem { pub struct ClientMem {
fd: Rc<OwnedFd>,
failed: Cell<bool>, failed: Cell<bool>,
sigbus_impossible: bool, sigbus_impossible: bool,
data: *const [Cell<u8>], data: *const [Cell<u8>],
@ -30,19 +34,34 @@ pub struct ClientMem {
#[derive(Clone)] #[derive(Clone)]
pub struct ClientMemOffset { pub struct ClientMemOffset {
mem: Rc<ClientMem>, mem: Rc<ClientMem>,
offset: usize,
data: *const [Cell<u8>], data: *const [Cell<u8>],
} }
impl ClientMem { impl ClientMem {
pub fn new(fd: i32, len: usize, read_only: bool) -> Result<Self, ClientMemError> { pub fn new(
fd: &Rc<OwnedFd>,
len: usize,
read_only: bool,
client: Option<&Client>,
) -> Result<Self, ClientMemError> {
let mut sigbus_impossible = false; 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 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; 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 { let data = if len == 0 {
&mut [][..] &mut [][..]
} else { } else {
@ -51,7 +70,7 @@ impl ClientMem {
false => c::PROT_READ | c::PROT_WRITE, false => c::PROT_READ | c::PROT_WRITE,
}; };
unsafe { 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 { if data == c::MAP_FAILED {
return Err(ClientMemError::MmapFailed(uapi::Errno::default().into())); return Err(ClientMemError::MmapFailed(uapi::Errno::default().into()));
} }
@ -59,6 +78,7 @@ impl ClientMem {
} }
}; };
Ok(Self { Ok(Self {
fd: fd.clone(),
failed: Cell::new(false), failed: Cell::new(false),
sigbus_impossible, sigbus_impossible,
data, data,
@ -73,12 +93,38 @@ impl ClientMem {
let mem = unsafe { &*self.data }; let mem = unsafe { &*self.data };
ClientMemOffset { ClientMemOffset {
mem: self.clone(), mem: self.clone(),
offset,
data: &mem[offset..], data: &mem[offset..],
} }
} }
#[expect(dead_code)]
pub fn fd(&self) -> &Rc<OwnedFd> {
&self.fd
}
#[expect(dead_code)]
pub fn sigbus_impossible(&self) -> bool {
self.sigbus_impossible
}
} }
impl ClientMemOffset { 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<u8>] {
self.data
}
pub fn access<T, F: FnOnce(&[Cell<u8>]) -> T>(&self, f: F) -> Result<T, ClientMemError> { pub fn access<T, F: FnOnce(&[Cell<u8>]) -> T>(&self, f: F) -> Result<T, ClientMemError> {
unsafe { unsafe {
if self.mem.sigbus_impossible { if self.mem.sigbus_impossible {

View file

@ -165,11 +165,11 @@ impl JayInput {
} }
} }
fn set_keymap_impl<F>(&self, keymap: &OwnedFd, len: u32, f: F) -> Result<(), JayInputError> fn set_keymap_impl<F>(&self, keymap: &Rc<OwnedFd>, len: u32, f: F) -> Result<(), JayInputError>
where where
F: FnOnce(&Rc<XkbKeymap>) -> Result<(), JayInputError>, F: FnOnce(&Rc<XkbKeymap>) -> 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![]; let mut map = vec![];
cm.read(&mut map)?; cm.read(&mut map)?;
self.or_error(|| { self.or_error(|| {

View file

@ -56,7 +56,7 @@ impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 {
if req.size > MAX_SIZE { if req.size > MAX_SIZE {
return Err(ZwpVirtualKeyboardV1Error::OversizedKeymap); 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(Rc::new)
.map_err(ZwpVirtualKeyboardV1Error::MapKeymap)?; .map_err(ZwpVirtualKeyboardV1Error::MapKeymap)?;
let mut map = vec![]; let mut map = vec![];

View file

@ -34,7 +34,7 @@ impl WlShmPool {
Ok(Self { Ok(Self {
id, id,
client: client.clone(), 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, fd,
tracker: Default::default(), tracker: Default::default(),
version, version,
@ -82,9 +82,10 @@ impl WlShmPoolRequestHandler for WlShmPool {
return Err(WlShmPoolError::CannotShrink); return Err(WlShmPoolError::CannotShrink);
} }
self.mem.set(Rc::new(ClientMem::new( self.mem.set(Rc::new(ClientMem::new(
self.fd.raw(), &self.fd,
req.size as usize, req.size as usize,
false, false,
Some(&self.client),
)?)); )?));
Ok(()) Ok(())
} }

View file

@ -7,6 +7,7 @@ use {
}, },
bstr::ByteSlice, bstr::ByteSlice,
std::rc::Rc, std::rc::Rc,
uapi::OwnedFd,
}; };
testcase!(); testcase!();
@ -15,7 +16,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
let virtual_keymap_str = { let virtual_keymap_str = {
let xkb = XkbContext::new()?; let xkb = XkbContext::new()?;
let map = xkb.keymap_from_str(VIRTUAL_KEYMAP).unwrap(); 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?; let ds = run.create_default_setup().await?;
@ -51,7 +52,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
s_client.sync().await; s_client.sync().await;
let (start, keymap) = s_keymap.next().expect("virtual keymap"); let (start, keymap) = s_keymap.next().expect("virtual keymap");
tassert_eq!( tassert_eq!(
&read_keymap(keymap.fd.raw(), keymap.size as _), &read_keymap(&keymap.fd, keymap.size as _),
&virtual_keymap_str &virtual_keymap_str
); );
{ {
@ -119,7 +120,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
s_client.sync().await; s_client.sync().await;
let (pos, keymap) = s_keymap.next().expect("seat keymap"); let (pos, keymap) = s_keymap.next().expect("seat keymap");
tassert_eq!(pos, start + 8); 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"); let (pos, mods) = s_modifiers.next().expect("mods 0");
tassert_eq!(pos, start + 9); tassert_eq!(pos, start + 9);
@ -147,8 +148,8 @@ async fn test(run: Rc<TestRun>) -> TestResult {
Ok(()) Ok(())
} }
fn read_keymap(fd: i32, size: usize) -> String { fn read_keymap(fd: &Rc<OwnedFd>, size: usize) -> String {
let client_mem = ClientMem::new(fd, size - 1, true).unwrap(); let client_mem = ClientMem::new(fd, size - 1, true, None).unwrap();
let client_mem = Rc::new(client_mem).offset(0); let client_mem = Rc::new(client_mem).offset(0);
let mut v = vec![]; let mut v = vec![];
client_mem.read(&mut v).unwrap(); client_mem.read(&mut v).unwrap();