Fix TCGETS/TCSETS using wrong termios type definition

This commit is contained in:
Hui, Chunyang 2021-12-24 07:59:44 +00:00 committed by Zongmin.Gu
parent 79bacb8bf4
commit f65bbdd924
3 changed files with 126 additions and 12 deletions

@ -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<i32> {
debug_assert!(cmd_num == 0x5401);
let mut termios = self.to_termios();
let len = std::mem::size_of::<Termios>();
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<i32> {
debug_assert!(cmd_num == 0x5402);
let termios = self.to_termios();
let len = std::mem::size_of::<Termios>();
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,
}
}
}

@ -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

@ -170,9 +170,22 @@ impl File for StdoutFile {
}
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
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<i32> {
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;