From 28382a149133d3df5f8e3e45b811afa79d1c0367 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Fri, 10 Sep 2021 11:27:08 +0000 Subject: [PATCH] virtio-devices: determine tty size in console This prepares us to be able to handle console resizes in the console device's epoll loop, which we'll have to do if the output is a pty, since we won't get SIGWINCH from it. Signed-off-by: Alyssa Ross --- virtio-devices/src/console.rs | 51 +++++++++++++++++++-------- virtio-devices/src/seccomp_filters.rs | 6 ++++ vmm/src/device_manager.rs | 27 ++------------ vmm/src/vm.rs | 7 ++-- 4 files changed, 47 insertions(+), 44 deletions(-) diff --git a/virtio-devices/src/console.rs b/virtio-devices/src/console.rs index 9ceca6dff..325593228 100644 --- a/virtio-devices/src/console.rs +++ b/virtio-devices/src/console.rs @@ -11,7 +11,7 @@ use crate::seccomp_filters::Thread; use crate::thread_helper::spawn_virtio_thread; use crate::GuestMemoryMmap; use crate::VirtioInterrupt; -use libc::EFD_NONBLOCK; +use libc::{EFD_NONBLOCK, TIOCGWINSZ}; use seccompiler::SeccompAction; use std::cmp; use std::collections::VecDeque; @@ -46,7 +46,7 @@ const FILE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 5; //Console size feature bit const VIRTIO_CONSOLE_F_SIZE: u64 = 0; -#[derive(Copy, Clone, Debug, Default, Versionize)] +#[derive(Copy, Clone, Debug, Versionize)] #[repr(C, packed)] pub struct VirtioConsoleConfig { cols: u16, @@ -55,6 +55,17 @@ pub struct VirtioConsoleConfig { emerg_wr: u32, } +impl Default for VirtioConsoleConfig { + fn default() -> Self { + VirtioConsoleConfig { + cols: 0, + rows: 0, + max_nr_ports: 1, + emerg_wr: 0, + } + } +} + // Safe because it only has data and has no implicit padding. unsafe impl ByteValued for VirtioConsoleConfig {} @@ -287,12 +298,13 @@ pub struct ConsoleResizer { } impl ConsoleResizer { - pub fn update_console_size(&self, cols: u16, rows: u16) { + pub fn update_console_size(&self) { if self .acked_features .fetch_and(1u64 << VIRTIO_CONSOLE_F_SIZE, Ordering::AcqRel) != 0 { + let (cols, rows) = get_win_size(); self.config.lock().unwrap().update_console_size(cols, rows); //Send the interrupt to the driver let _ = self.config_evt.write(1); @@ -301,15 +313,6 @@ impl ConsoleResizer { } impl VirtioConsoleConfig { - pub fn new(cols: u16, rows: u16) -> Self { - VirtioConsoleConfig { - cols, - rows, - max_nr_ports: 1u32, - emerg_wr: 0u32, - } - } - pub fn update_console_size(&mut self, cols: u16, rows: u16) { self.cols = cols; self.rows = rows; @@ -336,6 +339,24 @@ pub struct ConsoleState { in_buffer: Vec, } +fn get_win_size() -> (u16, u16) { + #[repr(C)] + #[derive(Default)] + struct WindowSize { + rows: u16, + cols: u16, + xpixel: u16, + ypixel: u16, + } + let ws: WindowSize = WindowSize::default(); + + unsafe { + libc::ioctl(0, TIOCGWINSZ, &ws); + } + + (ws.cols, ws.rows) +} + impl VersionMapped for ConsoleState {} impl Console { @@ -343,8 +364,6 @@ impl Console { pub fn new( id: String, endpoint: Endpoint, - cols: u16, - rows: u16, iommu: bool, seccomp_action: SeccompAction, exit_evt: EventFd, @@ -356,13 +375,15 @@ impl Console { } let config_evt = EventFd::new(EFD_NONBLOCK).unwrap(); - let console_config = Arc::new(Mutex::new(VirtioConsoleConfig::new(cols, rows))); + let console_config = Arc::new(Mutex::new(VirtioConsoleConfig::default())); let resizer = Arc::new(ConsoleResizer { config_evt, config: console_config.clone(), acked_features: AtomicU64::new(0), }); + resizer.update_console_size(); + Ok(( Console { common: VirtioCommon { diff --git a/virtio-devices/src/seccomp_filters.rs b/virtio-devices/src/seccomp_filters.rs index af36d1345..b50250c59 100644 --- a/virtio-devices/src/seccomp_filters.rs +++ b/virtio-devices/src/seccomp_filters.rs @@ -48,6 +48,7 @@ macro_rules! or { } // See include/uapi/asm-generic/ioctls.h in the kernel code. +const TIOCGWINSZ: u64 = 0x5413; const FIONBIO: u64 = 0x5421; // See include/uapi/linux/vfio.h in the kernel code. @@ -57,6 +58,10 @@ const VFIO_IOMMU_UNMAP_DMA: u64 = 0x3b72; // See include/uapi/linux/if_tun.h in the kernel code. const TUNSETOFFLOAD: u64 = 0x4004_54d0; +fn create_virtio_console_ioctl_seccomp_rule() -> Vec { + or![and![Cond::new(1, ArgLen::Dword, Eq, TIOCGWINSZ).unwrap()]] +} + fn create_virtio_iommu_ioctl_seccomp_rule() -> Vec { or![ and![Cond::new(1, ArgLen::Dword, Eq, VFIO_IOMMU_MAP_DMA).unwrap()], @@ -99,6 +104,7 @@ fn virtio_block_thread_rules() -> Vec<(i64, Vec)> { fn virtio_console_thread_rules() -> Vec<(i64, Vec)> { vec![ + (libc::SYS_ioctl, create_virtio_console_ioctl_seccomp_rule()), (libc::SYS_mprotect, vec![]), (libc::SYS_prctl, vec![]), (libc::SYS_sched_getaffinity, vec![]), diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 7296e6bdc..316b662fd 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -62,7 +62,7 @@ use hypervisor::DeviceFd; use hypervisor::IoEventAddress; use libc::{ isatty, tcgetattr, tcsetattr, termios, ECHO, ICANON, ISIG, MAP_NORESERVE, MAP_PRIVATE, - MAP_SHARED, O_TMPFILE, PROT_READ, PROT_WRITE, TCSANOW, TIOCGWINSZ, + MAP_SHARED, O_TMPFILE, PROT_READ, PROT_WRITE, TCSANOW, }; use pci::VfioPciDevice; use pci::{ @@ -450,24 +450,6 @@ type VirtioDeviceArc = Arc>; #[cfg(feature = "acpi")] const DEVICE_MANAGER_ACPI_SIZE: usize = 0x10; -pub fn get_win_size() -> (u16, u16) { - #[repr(C)] - #[derive(Default)] - struct WindowSize { - rows: u16, - cols: u16, - xpixel: u16, - ypixel: u16, - } - let ws: WindowSize = WindowSize::default(); - - unsafe { - libc::ioctl(0, TIOCGWINSZ, &ws); - } - - (ws.cols, ws.rows) -} - const TIOCSPTLCK: libc::c_int = 0x4004_5431; const TIOCGTPEER: libc::c_int = 0x5441; @@ -543,9 +525,9 @@ impl Console { Ok(()) } - pub fn update_console_size(&self, cols: u16, rows: u16) { + pub fn update_console_size(&self) { if let Some(resizer) = self.console_resizer.as_ref() { - resizer.update_console_size(cols, rows) + resizer.update_console_size() } } } @@ -1716,14 +1698,11 @@ impl DeviceManager { ConsoleOutputMode::Null => Endpoint::Null, ConsoleOutputMode::Off => return Ok(None), }; - let (col, row) = get_win_size(); let id = String::from(CONSOLE_DEVICE_NAME); let (virtio_console_device, console_resizer) = virtio_devices::Console::new( id.clone(), endpoint, - col, - row, self.force_iommu | console_config.iommu, self.seccomp_action.clone(), self.exit_evt diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 6a1875fd9..79ead510e 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -17,9 +17,7 @@ use crate::config::{ ConsoleOutputMode, DeviceConfig, DiskConfig, FsConfig, HotplugMethod, NetConfig, PmemConfig, UserDeviceConfig, ValidationError, VmConfig, VsockConfig, }; -use crate::device_manager::{ - self, get_win_size, Console, DeviceManager, DeviceManagerError, PtyPair, -}; +use crate::device_manager::{self, Console, DeviceManager, DeviceManagerError, PtyPair}; use crate::device_tree::DeviceTree; use crate::memory_manager::{Error as MemoryManagerError, MemoryManager}; use crate::migration::{get_vm_snapshot, url_to_path, VM_SNAPSHOT_FILE}; @@ -1602,8 +1600,7 @@ impl Vm { for signal in signals.forever() { match signal { SIGWINCH => { - let (col, row) = get_win_size(); - console_input_clone.update_console_size(col, row); + console_input_clone.update_console_size(); } SIGTERM | SIGINT => { if on_tty {