diff --git a/drivers/inputd/src/main.rs b/drivers/inputd/src/main.rs index ababa13a4c..b0cb882f99 100644 --- a/drivers/inputd/src/main.rs +++ b/drivers/inputd/src/main.rs @@ -402,11 +402,26 @@ impl SchemeSync for InputScheme { return Ok(1); } - let mut events = Cow::from(unsafe { - core::slice::from_raw_parts( - buf.as_ptr() as *const Event, - buf.len() / size_of::(), - ) + // The producer's write buffer comes from an arbitrary scheme write and + // is only byte-aligned. Constructing a `&[Event]` directly over it is + // undefined behaviour (misaligned loads) and faults on aarch64/riscv, so + // copy the whole events into a properly aligned `Vec` and drop any + // trailing partial event. + let count = buf.len() / size_of::(); + let mut events: Cow<[Event]> = Cow::Owned({ + let mut v: Vec = Vec::with_capacity(count); + // SAFETY: `Event` is `repr(C)` POD; copy exactly `count * + // size_of::()` bytes from the (possibly unaligned) source into + // the aligned Vec allocation, then set the length. + unsafe { + core::ptr::copy_nonoverlapping( + buf.as_ptr(), + v.as_mut_ptr() as *mut u8, + count * size_of::(), + ); + v.set_len(count); + } + v }); for i in 0..events.len() { @@ -516,18 +531,20 @@ impl SchemeSync for InputScheme { } fn on_close(&mut self, id: usize) { - match self.handles.remove(id).unwrap() { - Handle::Consumer { vt, .. } => { - self.vts.remove(&vt); - if self.active_vt == Some(vt) { - if let Some(&new_vt) = self.vts.last() { - self.switch_vt(new_vt); - } else { - self.active_vt = None; - } + // A close for an unknown/already-removed handle must not panic — that + // would take inputd (and therefore all keyboard/console input) down. + let Some(handle) = self.handles.remove(id) else { + return; + }; + if let Handle::Consumer { vt, .. } = handle { + self.vts.remove(&vt); + if self.active_vt == Some(vt) { + if let Some(&new_vt) = self.vts.last() { + self.switch_vt(new_vt); + } else { + self.active_vt = None; } } - _ => {} } } }