From f65bbdd924e3c908c4df1b43147a2b77328490e3 Mon Sep 17 00:00:00 2001 From: "Hui, Chunyang" Date: Fri, 24 Dec 2021 07:59:44 +0000 Subject: [PATCH] Fix TCGETS/TCSETS using wrong termios type definition --- src/libos/src/fs/file_ops/ioctl/builtin.rs | 96 +++++++++++++++++++++- src/libos/src/fs/file_ops/ioctl/mod.rs | 4 +- src/libos/src/fs/stdio.rs | 38 +++++++-- 3 files changed, 126 insertions(+), 12 deletions(-) diff --git a/src/libos/src/fs/file_ops/ioctl/builtin.rs b/src/libos/src/fs/file_ops/ioctl/builtin.rs index 0af50d65..bc608b1c 100644 --- a/src/libos/src/fs/file_ops/ioctl/builtin.rs +++ b/src/libos/src/fs/file_ops/ioctl/builtin.rs @@ -26,11 +26,31 @@ pub struct IfReq { pub ifr_union: [u8; 24], } +/* + The termios structure used in the Linux kernel is not the same as we use in the glibc. Thus, we have two + definitions here. +*/ + +const KERNEL_NCCS: usize = 19; +const NCCS: usize = 32; + type TcflagT = u32; type CcT = u8; type SpeedT = u32; -const NCCS: usize = 32; -#[derive(Debug)] + +// Corresponds to the definition in glibc: sysdeps/unix/sysv/linux/kernel_termios.h +#[derive(Debug, Default, Copy, Clone)] +#[repr(C)] +pub struct KernelTermios { + pub c_iflag: TcflagT, + pub c_oflag: TcflagT, + pub c_cflag: TcflagT, + pub c_lflag: TcflagT, + pub c_line: CcT, + pub c_cc: [CcT; KERNEL_NCCS], +} + +#[derive(Debug, Default, Copy, Clone)] #[repr(C)] pub struct Termios { pub c_iflag: TcflagT, @@ -42,3 +62,75 @@ pub struct Termios { pub c_ispeed: SpeedT, pub c_ospeed: SpeedT, } + +impl KernelTermios { + fn to_termios(&self) -> Termios { + let mut c_cc = [0; NCCS]; + c_cc[..KERNEL_NCCS].copy_from_slice(&self.c_cc); + Termios { + c_iflag: self.c_iflag, + c_oflag: self.c_oflag, + c_cflag: self.c_cflag, + c_lflag: self.c_lflag, + c_line: self.c_line, + c_cc: c_cc, + c_ispeed: 0, + c_ospeed: 0, + } + } + + pub fn execute_tcgets(&mut self, host_fd: i32, cmd_num: i32) -> Result { + debug_assert!(cmd_num == 0x5401); + let mut termios = self.to_termios(); + let len = std::mem::size_of::(); + let ret = try_libc!({ + let mut retval: i32 = 0; + let status = occlum_ocall_ioctl( + &mut retval as *mut i32, + host_fd, + cmd_num, + &mut termios as *const Termios as *mut c_void, + len, + ); + assert!(status == sgx_status_t::SGX_SUCCESS); + retval + }); + *self = termios.to_kernel_termios(); + Ok(ret) + } + + pub fn execute_tcsets(&self, host_fd: i32, cmd_num: i32) -> Result { + debug_assert!(cmd_num == 0x5402); + let termios = self.to_termios(); + let len = std::mem::size_of::(); + let ret = try_libc!({ + let mut retval: i32 = 0; + let status = occlum_ocall_ioctl( + &mut retval as *mut i32, + host_fd, + cmd_num, + &termios as *const Termios as *mut c_void, + len, + ); + assert!(status == sgx_status_t::SGX_SUCCESS); + retval + }); + Ok(ret) + } +} + +impl Termios { + pub fn to_kernel_termios(&self) -> KernelTermios { + let mut c_cc = [0; KERNEL_NCCS]; + c_cc.copy_from_slice(&self.c_cc[..KERNEL_NCCS]); + + KernelTermios { + c_iflag: self.c_iflag, + c_oflag: self.c_oflag, + c_cflag: self.c_cflag, + c_lflag: self.c_lflag, + c_line: self.c_line, + c_cc: c_cc, + } + } +} diff --git a/src/libos/src/fs/file_ops/ioctl/mod.rs b/src/libos/src/fs/file_ops/ioctl/mod.rs index aef55253..579d2169 100644 --- a/src/libos/src/fs/file_ops/ioctl/mod.rs +++ b/src/libos/src/fs/file_ops/ioctl/mod.rs @@ -27,8 +27,8 @@ impl_ioctl_nums_and_cmds! { // ioctl_name => (ioctl_num, ioctl_type_arg) // Get terminal attributes - TCGETS => (0x5401, mut Termios), // ignore - TCSETS => (0x5402, Termios), + TCGETS => (0x5401, mut KernelTermios), // ignore + TCSETS => (0x5402, KernelTermios), // Get window size TIOCGWINSZ => (0x5413, mut WinSize), // Set window size diff --git a/src/libos/src/fs/stdio.rs b/src/libos/src/fs/stdio.rs index 991cc2a5..2e35540a 100644 --- a/src/libos/src/fs/stdio.rs +++ b/src/libos/src/fs/stdio.rs @@ -170,9 +170,22 @@ impl File for StdoutFile { } fn ioctl(&self, cmd: &mut IoctlCmd) -> Result { + let host_stdout_fd = self.host_fd() as i32; + let cmd_bits = cmd.cmd_num() as c_int; + + // Handle special case for TCGETS/TCSETS which use different structures + // in linux kernel and libc + match cmd { + IoctlCmd::TCGETS(kernel_termios) => { + return kernel_termios.execute_tcgets(host_stdout_fd, cmd_bits); + } + IoctlCmd::TCSETS(kernel_termios) => { + return kernel_termios.execute_tcsets(host_stdout_fd, cmd_bits); + } + _ => {} + }; + let can_delegate_to_host = match cmd { - IoctlCmd::TCGETS(_) => true, - IoctlCmd::TCSETS(_) => true, IoctlCmd::TIOCGWINSZ(_) => true, IoctlCmd::TIOCSWINSZ(_) => true, _ => false, @@ -181,9 +194,7 @@ impl File for StdoutFile { return_errno!(EINVAL, "unknown ioctl cmd for stdout"); } - let cmd_bits = cmd.cmd_num() as c_int; let cmd_arg_ptr = cmd.arg_ptr() as *mut c_void; - let host_stdout_fd = self.host_fd() as i32; let cmd_arg_len = cmd.arg_len(); let ret = try_libc!({ let mut retval: i32 = 0; @@ -321,9 +332,22 @@ impl File for StdinFile { } fn ioctl(&self, cmd: &mut IoctlCmd) -> Result { + let host_stdin_fd = self.host_fd() as i32; + let cmd_bits = cmd.cmd_num() as c_int; + + // Handle special case for TCGETS/TCSETS which use different structures + // in linux kernel and libc + match cmd { + IoctlCmd::TCGETS(kernel_termios) => { + return kernel_termios.execute_tcgets(host_stdin_fd, cmd_bits); + } + IoctlCmd::TCSETS(kernel_termios) => { + return kernel_termios.execute_tcsets(host_stdin_fd, cmd_bits); + } + _ => {} + }; + let can_delegate_to_host = match cmd { - IoctlCmd::TCGETS(_) => true, - IoctlCmd::TCSETS(_) => true, IoctlCmd::TIOCGWINSZ(_) => true, IoctlCmd::TIOCSWINSZ(_) => true, _ => false, @@ -332,9 +356,7 @@ impl File for StdinFile { return_errno!(EINVAL, "unknown ioctl cmd for stdin"); } - let cmd_bits = cmd.cmd_num() as c_int; let cmd_arg_ptr = cmd.arg_ptr() as *mut c_void; - let host_stdin_fd = self.host_fd() as i32; let cmd_arg_len = cmd.arg_len(); let ret = try_libc!({ let mut retval: i32 = 0;