wayland.seat: send keymaps in individual tempfiles

Send keymaps to client using a new tempfile for each client, rather than
a single shared tempfile. Doing so prevents a client from tempering with
the contents of the tempfile, which would then cause other clients to
read a corrupted keymap.

See this bug report for details:
https://bugs.freedesktop.org/show_bug.cgi?id=101595
This commit is contained in:
Victor Berger 2018-10-08 14:09:58 +02:00
parent 1618c45d4e
commit f9bd83c3b5
No known key found for this signature in database
GPG Key ID: 5866DDBC86BE4680
1 changed files with 23 additions and 19 deletions

View File

@ -237,23 +237,12 @@ pub(crate) fn create_keyboard_handler(
info!(log, "Loaded Keymap"; "name" => internal.keymap.layouts().next()); info!(log, "Loaded Keymap"; "name" => internal.keymap.layouts().next());
// prepare a tempfile with the keymap, to send it to clients let keymap = internal.keymap.get_as_string(xkb::KEYMAP_FORMAT_TEXT_V1);
let mut keymap_file = tempfile().map_err(Error::IoError)?;
let keymap_data = internal.keymap.get_as_string(xkb::KEYMAP_FORMAT_TEXT_V1);
keymap_file
.write_all(keymap_data.as_bytes())
.map_err(Error::IoError)?;
keymap_file.flush().map_err(Error::IoError)?;
trace!(log, "Keymap loaded and copied to tempfile.";
"fd" => keymap_file.as_raw_fd(), "len" => keymap_data.as_bytes().len()
);
Ok(KeyboardHandle { Ok(KeyboardHandle {
arc: Arc::new(KbdArc { arc: Arc::new(KbdArc {
internal: Mutex::new(internal), internal: Mutex::new(internal),
keymap_file, keymap,
keymap_len: keymap_data.as_bytes().len() as u32,
logger: log, logger: log,
}), }),
}) })
@ -261,8 +250,7 @@ pub(crate) fn create_keyboard_handler(
struct KbdArc { struct KbdArc {
internal: Mutex<KbdInternal>, internal: Mutex<KbdInternal>,
keymap_file: ::std::fs::File, keymap: String,
keymap_len: u32,
logger: ::slog::Logger, logger: ::slog::Logger,
} }
@ -411,11 +399,27 @@ impl KeyboardHandle {
/// This should be done first, before anything else is done with this keyboard. /// This should be done first, before anything else is done with this keyboard.
pub(crate) fn new_kbd(&self, kbd: Resource<WlKeyboard>) { pub(crate) fn new_kbd(&self, kbd: Resource<WlKeyboard>) {
trace!(self.arc.logger, "Sending keymap to client"); trace!(self.arc.logger, "Sending keymap to client");
// prepare a tempfile with the keymap, to send it to the client
let ret = tempfile().and_then(|mut f| {
f.write_all(self.arc.keymap.as_bytes())?;
f.flush()?;
kbd.send(Event::Keymap { kbd.send(Event::Keymap {
format: KeymapFormat::XkbV1, format: KeymapFormat::XkbV1,
fd: self.arc.keymap_file.as_raw_fd(), fd: f.as_raw_fd(),
size: self.arc.keymap_len, size: self.arc.keymap.as_bytes().len() as u32,
}); });
Ok(())
});
if let Err(e) = ret {
warn!(self.arc.logger,
"Failed write keymap to client in a tempfile";
"err" => format!("{:?}", e)
);
return;
};
let mut guard = self.arc.internal.lock().unwrap(); let mut guard = self.arc.internal.lock().unwrap();
if kbd.version() >= 4 { if kbd.version() >= 4 {
kbd.send(Event::RepeatInfo { kbd.send(Event::RepeatInfo {