diff --git a/regression/syscall_test/Makefile b/regression/syscall_test/Makefile index a8198e8de..8789dc56f 100644 --- a/regression/syscall_test/Makefile +++ b/regression/syscall_test/Makefile @@ -1,4 +1,4 @@ -TESTS ?= open_test read_test statfs_test chmod_test +TESTS ?= open_test read_test statfs_test chmod_test pty_test MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH))) diff --git a/regression/syscall_test/blocklists/pty_test b/regression/syscall_test/blocklists/pty_test new file mode 100644 index 000000000..3d712cd4f --- /dev/null +++ b/regression/syscall_test/blocklists/pty_test @@ -0,0 +1,42 @@ +PtyTrunc.Truncate +PtyTest.MasterTermiosUnchangable +PtyTest.TermiosICRNL +PtyTest.TermiosONLCR +PtyTest.TermiosINLCR +PtyTest.TermiosOCRNL +PtyTest.SwitchCanonToNonCanonNewline +PtyTest.TermiosICANONNewline +PtyTest.TermiosICANONEOF +PtyTest.CanonDiscard +PtyTest.CanonMultiline +PtyTest.SimpleEcho +PtyTest.TermiosIGNCR +PtyTest.TermiosONOCR +PtyTest.VEOLTermination +PtyTest.CanonBigWrite +PtyTest.SwitchCanonToNoncanon +PtyTest.SwitchNoncanonToCanonNewlineBig +PtyTest.SwitchNoncanonToCanonNoNewline +PtyTest.SwitchNoncanonToCanonNoNewlineBig +PtyTest.NoncanonBigWrite +PtyTest.SwitchNoncanonToCanonMultiline +PtyTest.SwitchTwiceMultiline +JobControlTest.SetTTYMaster +JobControlTest.SetTTY +JobControlTest.SetTTYNonLeader +JobControlTest.SetTTYBadArg +JobControlTest.SetTTYDifferentSession +JobControlTest.ReleaseTTY +JobControlTest.ReleaseUnsetTTY +JobControlTest.ReleaseWrongTTY +JobControlTest.ReleaseTTYNonLeader +JobControlTest.ReleaseTTYDifferentSession +JobControlTest.ReleaseTTYSignals +JobControlTest.GetForegroundProcessGroup +JobControlTest.GetForegroundProcessGroupNonControlling +JobControlTest.SetForegroundProcessGroup +JobControlTest.SetForegroundProcessGroupWrongTTY +JobControlTest.SetForegroundProcessGroupNegPgid +JobControlTest.SetForegroundProcessGroupEmptyProcessGroup +JobControlTest.SetForegroundProcessGroupDifferentSession +JobControlTest.OrphanRegression \ No newline at end of file diff --git a/services/libs/jinux-std/src/device/pty/master.rs b/services/libs/jinux-std/src/device/pty/master.rs index f7f97f202..a587e612a 100644 --- a/services/libs/jinux-std/src/device/pty/master.rs +++ b/services/libs/jinux-std/src/device/pty/master.rs @@ -55,11 +55,7 @@ impl PtyMaster { pub(super) fn slave_push_char(&self, item: u8) -> Result<()> { let mut buf = self.master_buffer.lock_irq_disabled(); - if buf.is_full() { - return_errno_with_message!(Errno::EIO, "the buffer is full"); - } - // Unwrap safety: the buf is not full, so push will always succeed. - buf.push(item).unwrap(); + buf.push_overwrite(item); self.update_state(&buf); Ok(()) } @@ -93,13 +89,11 @@ impl PtyMaster { } } - fn update_state(&self, buf: &HeapRb) { - if buf.is_full() { - self.pollee.del_events(IoEvents::OUT); - } else { - self.pollee.add_events(IoEvents::OUT); - } + pub(super) fn slave_buf_len(&self) -> usize { + self.ldisc.buffer_len() + } + fn update_state(&self, buf: &HeapRb) { if buf.is_empty() { self.pollee.del_events(IoEvents::IN) } else { @@ -139,18 +133,10 @@ impl FileLike for PtyMaster { fn write(&self, buf: &[u8]) -> Result { let mut master_buf = self.master_buffer.lock(); - if self.ldisc.termios().contain_echo() && master_buf.len() + buf.len() > BUFFER_CAPACITY { - return_errno_with_message!( - Errno::EIO, - "the written bytes exceeds the master buf capacity" - ); - } - for item in buf { self.ldisc.push_char(*item, |content| { for byte in content.as_bytes() { - // Unwrap safety: the master buf is ensured to have enough space. - master_buf.push(*byte).unwrap(); + master_buf.push_overwrite(*byte); } }); } @@ -203,9 +189,18 @@ impl FileLike for PtyMaster { }; Ok(fd) } - IoctlCmd::TIOCGWINSZ => Ok(0), + IoctlCmd::TIOCGWINSZ => { + let winsize = self.ldisc.window_size(); + write_val_to_user(arg, &winsize)?; + Ok(0) + } + IoctlCmd::TIOCSWINSZ => { + let winsize = read_val_from_user(arg)?; + self.ldisc.set_window_size(winsize); + Ok(0) + } IoctlCmd::TIOCSCTTY => { - // TODO + // TODO: reimplement when adding session. let foreground = { let current = current!(); let process_group = current.process_group().lock(); @@ -225,9 +220,15 @@ impl FileLike for PtyMaster { Ok(0) } IoctlCmd::TIOCNOTTY => { + // TODO: reimplement when adding session. self.ldisc.set_fg(Weak::new()); Ok(0) } + IoctlCmd::FIONREAD => { + let len = self.master_buffer.lock().len() as i32; + write_val_to_user(arg, &len)?; + Ok(0) + } _ => Ok(0), } } @@ -237,8 +238,6 @@ impl FileLike for PtyMaster { let poll_in_mask = mask & IoEvents::IN; loop { - let _master_buf = self.master_buffer.lock_irq_disabled(); - let mut poll_status = IoEvents::empty(); if !poll_in_mask.is_empty() { diff --git a/services/libs/jinux-std/src/device/pty/slave.rs b/services/libs/jinux-std/src/device/pty/slave.rs index dbb6d7e94..71a119ac7 100644 --- a/services/libs/jinux-std/src/device/pty/slave.rs +++ b/services/libs/jinux-std/src/device/pty/slave.rs @@ -2,6 +2,7 @@ use crate::fs::device::{Device, DeviceId, DeviceType}; use crate::fs::file_handle::FileLike; use crate::fs::utils::{IoEvents, IoctlCmd, Poller}; use crate::prelude::*; +use crate::util::write_val_to_user; use super::master::PtyMaster; @@ -45,8 +46,12 @@ impl Device for PtySlave { fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { match cmd { - IoctlCmd::TCGETS | IoctlCmd::TCSETS | IoctlCmd::TIOCGPGRP => self.0.ioctl(cmd, arg), - IoctlCmd::TIOCGWINSZ => Ok(0), + IoctlCmd::TCGETS + | IoctlCmd::TCSETS + | IoctlCmd::TIOCGPGRP + | IoctlCmd::TIOCGPTN + | IoctlCmd::TIOCGWINSZ + | IoctlCmd::TIOCSWINSZ => self.0.ioctl(cmd, arg), IoctlCmd::TIOCSCTTY => { // TODO: Ok(0) @@ -55,6 +60,11 @@ impl Device for PtySlave { // TODO: Ok(0) } + IoctlCmd::FIONREAD => { + let buffer_len = self.0.slave_buf_len() as i32; + write_val_to_user(arg, &buffer_len)?; + Ok(0) + } _ => Ok(0), } } diff --git a/services/libs/jinux-std/src/device/tty/line_discipline.rs b/services/libs/jinux-std/src/device/tty/line_discipline.rs index 66a53f120..2d52c318e 100644 --- a/services/libs/jinux-std/src/device/tty/line_discipline.rs +++ b/services/libs/jinux-std/src/device/tty/line_discipline.rs @@ -9,7 +9,7 @@ use alloc::format; use jinux_frame::trap::disable_local; use ringbuf::{ring_buffer::RbBase, Rb, StaticRb}; -use super::termio::{KernelTermios, CC_C_CHAR}; +use super::termio::{KernelTermios, WinSize, CC_C_CHAR}; // This implementation refers the implementation of linux // https://elixir.bootlin.com/linux/latest/source/include/linux/tty_ldisc.h @@ -25,6 +25,8 @@ pub struct LineDiscipline { foreground: SpinLock>, /// termios termios: SpinLock, + /// Windows size, + winsize: SpinLock, /// Pollee pollee: Pollee, } @@ -72,6 +74,7 @@ impl LineDiscipline { read_buffer: SpinLock::new(StaticRb::default()), foreground: SpinLock::new(Weak::new()), termios: SpinLock::new(KernelTermios::default()), + winsize: SpinLock::new(WinSize::default()), pollee: Pollee::new(IoEvents::empty()), } } @@ -350,6 +353,18 @@ impl LineDiscipline { self.current_line.lock().drain(); let _: Vec<_> = self.read_buffer.lock().pop_iter().collect(); } + + pub fn buffer_len(&self) -> usize { + self.read_buffer.lock().len() + } + + pub fn window_size(&self) -> WinSize { + self.winsize.lock().clone() + } + + pub fn set_window_size(&self, winsize: WinSize) { + *self.winsize.lock() = winsize; + } } fn meet_new_line(item: u8, termios: &KernelTermios) -> bool { diff --git a/services/libs/jinux-std/src/device/tty/mod.rs b/services/libs/jinux-std/src/device/tty/mod.rs index 1505ac3e4..1564266bf 100644 --- a/services/libs/jinux-std/src/device/tty/mod.rs +++ b/services/libs/jinux-std/src/device/tty/mod.rs @@ -130,7 +130,13 @@ impl Device for Tty { Ok(0) } IoctlCmd::TIOCGWINSZ => { - // TODO:get window size + let winsize = self.ldisc.window_size(); + write_val_to_user(arg, &winsize)?; + Ok(0) + } + IoctlCmd::TIOCSWINSZ => { + let winsize = read_val_from_user(arg)?; + self.ldisc.set_window_size(winsize); Ok(0) } _ => todo!(), diff --git a/services/libs/jinux-std/src/device/tty/termio.rs b/services/libs/jinux-std/src/device/tty/termio.rs index 60d3e5449..5eef22c3f 100644 --- a/services/libs/jinux-std/src/device/tty/termio.rs +++ b/services/libs/jinux-std/src/device/tty/termio.rs @@ -33,22 +33,76 @@ bitflags! { } } +impl C_IFLAGS { + pub fn new_default() -> Self { + C_IFLAGS::ICRNL | C_IFLAGS::IXON + } +} + bitflags! { #[repr(C)] #[derive(Pod)] pub struct C_OFLAGS: u32 { - const OPOST = 0x01; /* Perform output processing */ - const OCRNL = 0x08; - const ONOCR = 0x10; - const ONLRET= 0x20; - const OFILL = 0x40; - const OFDEL = 0x80; + const OPOST = 0x1 << 0; /* Perform output processing */ + const OLCUC = 0x1 << 1; + const ONLCR = 0x1 << 2; + const OCRNL = 0x1 << 3; + const ONOCR = 0x1 << 4; + const ONLRET= 0x1 << 5; + const OFILL = 0x1 << 6; + const OFDEL = 0x1 << 7; } } -#[repr(u32)] +impl C_OFLAGS { + pub fn new_default() -> Self { + C_OFLAGS::OPOST | C_OFLAGS::ONLCR + } +} + +#[repr(C)] #[derive(Debug, Clone, Copy, Pod)] -pub enum C_CFLAGS { +pub struct C_CFLAGS(u32); + +impl C_CFLAGS { + pub fn new_default() -> Self { + let cbaud = C_CFLAGS_BAUD::B38400 as u32; + let csize = C_CFLAGS_CSIZE::CS8 as u32; + let c_cflags = cbaud | csize | CREAD; + Self(c_cflags) + } + + pub fn cbaud(&self) -> Result { + let cbaud = self.0 & CBAUD_MASK; + Ok(C_CFLAGS_BAUD::try_from(cbaud)?) + } + + pub fn csize(&self) -> Result { + let csize = self.0 & CSIZE_MASK; + Ok(C_CFLAGS_CSIZE::try_from(csize)?) + } + + pub fn cread(&self) -> bool { + self.0 & CREAD != 0 + } +} + +const CREAD: u32 = 0x00000080; +const CBAUD_MASK: u32 = 0x0000100f; +const CSIZE_MASK: u32 = 0x00000030; + +#[repr(u32)] +#[derive(Clone, Copy, TryFromInt)] +pub enum C_CFLAGS_CSIZE { + CS5 = 0x00000000, + CS6 = 0x00000010, + CS7 = 0x00000020, + CS8 = 0x00000030, +} + +#[repr(u32)] +#[derive(Debug, Clone, Copy, TryFromInt)] +pub enum C_CFLAGS_BAUD { B0 = 0x00000000, /* hang up */ B50 = 0x00000001, B75 = 0x00000002, @@ -90,6 +144,19 @@ bitflags! { } } +impl C_LFLAGS { + pub fn new_default() -> Self { + C_LFLAGS::ICANON + | C_LFLAGS::ECHO + | C_LFLAGS::ISIG + | C_LFLAGS::ECHOE + | C_LFLAGS::ECHOK + | C_LFLAGS::ECHOCTL + | C_LFLAGS::ECHOKE + | C_LFLAGS::IEXTEN + } +} + /* c_cc characters index*/ #[repr(u32)] #[derive(Debug, Clone, Copy, Pod)] @@ -114,26 +181,26 @@ pub enum CC_C_CHAR { } impl CC_C_CHAR { - // The special char is the same as ubuntu - pub fn char(&self) -> u8 { + // The special char is from gvisor + pub fn default_char(&self) -> u8 { match self { - CC_C_CHAR::VINTR => 3, - CC_C_CHAR::VQUIT => 28, - CC_C_CHAR::VERASE => 127, - CC_C_CHAR::VKILL => 21, - CC_C_CHAR::VEOF => 4, - CC_C_CHAR::VTIME => 0, + CC_C_CHAR::VINTR => control_character('C'), + CC_C_CHAR::VQUIT => control_character('\\'), + CC_C_CHAR::VERASE => '\x7f' as u8, + CC_C_CHAR::VKILL => control_character('U'), + CC_C_CHAR::VEOF => control_character('D'), + CC_C_CHAR::VTIME => '\0' as u8, CC_C_CHAR::VMIN => 1, - CC_C_CHAR::VSWTC => 0, - CC_C_CHAR::VSTART => 17, - CC_C_CHAR::VSTOP => 19, - CC_C_CHAR::VSUSP => 26, - CC_C_CHAR::VEOL => 255, - CC_C_CHAR::VREPRINT => 18, - CC_C_CHAR::VDISCARD => 15, - CC_C_CHAR::VWERASE => 23, - CC_C_CHAR::VLNEXT => 22, - CC_C_CHAR::VEOL2 => 255, + CC_C_CHAR::VSWTC => '\0' as u8, + CC_C_CHAR::VSTART => control_character('Q'), + CC_C_CHAR::VSTOP => control_character('S'), + CC_C_CHAR::VSUSP => control_character('Z'), + CC_C_CHAR::VEOL => '\0' as u8, + CC_C_CHAR::VREPRINT => control_character('R'), + CC_C_CHAR::VDISCARD => control_character('O'), + CC_C_CHAR::VWERASE => control_character('W'), + CC_C_CHAR::VLNEXT => control_character('V'), + CC_C_CHAR::VEOL2 => '\0' as u8, } } @@ -142,28 +209,28 @@ impl CC_C_CHAR { } pub fn from_char(item: u8) -> Result { - if item == Self::VINTR.char() { + if item == Self::VINTR.default_char() { return Ok(Self::VINTR); } - if item == Self::VQUIT.char() { + if item == Self::VQUIT.default_char() { return Ok(Self::VQUIT); } - if item == Self::VINTR.char() { + if item == Self::VINTR.default_char() { return Ok(Self::VINTR); } - if item == Self::VERASE.char() { + if item == Self::VERASE.default_char() { return Ok(Self::VERASE); } - if item == Self::VEOF.char() { + if item == Self::VEOF.default_char() { return Ok(Self::VEOF); } - if item == Self::VSTART.char() { + if item == Self::VSTART.default_char() { return Ok(Self::VSTART); } - if item == Self::VSTOP.char() { + if item == Self::VSTOP.default_char() { return Ok(Self::VSTOP); } - if item == Self::VSUSP.char() { + if item == Self::VSUSP.default_char() { return Ok(Self::VSUSP); } @@ -185,44 +252,33 @@ pub struct KernelTermios { impl KernelTermios { pub fn default() -> Self { let mut termios = Self { - c_iflags: C_IFLAGS::ICRNL, - c_oflags: C_OFLAGS::empty(), - c_cflags: C_CFLAGS::B0, - c_lflags: C_LFLAGS::ICANON | C_LFLAGS::ECHO, + c_iflags: C_IFLAGS::new_default(), + c_oflags: C_OFLAGS::new_default(), + c_cflags: C_CFLAGS::new_default(), + c_lflags: C_LFLAGS::new_default(), c_line: 0, c_cc: [0; KERNEL_NCCS], }; - *termios.get_special_char_mut(CC_C_CHAR::VINTR) = CC_C_CHAR::VINTR.char(); - *termios.get_special_char_mut(CC_C_CHAR::VQUIT) = CC_C_CHAR::VQUIT.char(); - *termios.get_special_char_mut(CC_C_CHAR::VERASE) = CC_C_CHAR::VERASE.char(); - *termios.get_special_char_mut(CC_C_CHAR::VKILL) = CC_C_CHAR::VKILL.char(); - *termios.get_special_char_mut(CC_C_CHAR::VEOF) = CC_C_CHAR::VEOF.char(); - *termios.get_special_char_mut(CC_C_CHAR::VTIME) = CC_C_CHAR::VTIME.char(); - *termios.get_special_char_mut(CC_C_CHAR::VMIN) = CC_C_CHAR::VMIN.char(); - *termios.get_special_char_mut(CC_C_CHAR::VSWTC) = CC_C_CHAR::VSWTC.char(); - *termios.get_special_char_mut(CC_C_CHAR::VSTART) = CC_C_CHAR::VSTART.char(); - *termios.get_special_char_mut(CC_C_CHAR::VSTOP) = CC_C_CHAR::VSTOP.char(); - *termios.get_special_char_mut(CC_C_CHAR::VSUSP) = CC_C_CHAR::VSUSP.char(); - *termios.get_special_char_mut(CC_C_CHAR::VEOL) = CC_C_CHAR::VEOL.char(); - *termios.get_special_char_mut(CC_C_CHAR::VREPRINT) = CC_C_CHAR::VREPRINT.char(); - *termios.get_special_char_mut(CC_C_CHAR::VDISCARD) = CC_C_CHAR::VDISCARD.char(); - *termios.get_special_char_mut(CC_C_CHAR::VWERASE) = CC_C_CHAR::VWERASE.char(); - *termios.get_special_char_mut(CC_C_CHAR::VLNEXT) = CC_C_CHAR::VLNEXT.char(); - *termios.get_special_char_mut(CC_C_CHAR::VEOL2) = CC_C_CHAR::VEOL2.char(); + *termios.get_special_char_mut(CC_C_CHAR::VINTR) = CC_C_CHAR::VINTR.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VQUIT) = CC_C_CHAR::VQUIT.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VERASE) = CC_C_CHAR::VERASE.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VKILL) = CC_C_CHAR::VKILL.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VEOF) = CC_C_CHAR::VEOF.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VTIME) = CC_C_CHAR::VTIME.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VMIN) = CC_C_CHAR::VMIN.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VSWTC) = CC_C_CHAR::VSWTC.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VSTART) = CC_C_CHAR::VSTART.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VSTOP) = CC_C_CHAR::VSTOP.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VSUSP) = CC_C_CHAR::VSUSP.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VEOL) = CC_C_CHAR::VEOL.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VREPRINT) = CC_C_CHAR::VREPRINT.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VDISCARD) = CC_C_CHAR::VDISCARD.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VWERASE) = CC_C_CHAR::VWERASE.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VLNEXT) = CC_C_CHAR::VLNEXT.default_char(); + *termios.get_special_char_mut(CC_C_CHAR::VEOL2) = CC_C_CHAR::VEOL2.default_char(); termios } - fn new() -> Self { - KernelTermios { - c_iflags: C_IFLAGS::empty(), - c_oflags: C_OFLAGS::empty(), - c_cflags: C_CFLAGS::B0, - c_lflags: C_LFLAGS::empty(), - c_line: 0, - c_cc: [0; KERNEL_NCCS], - } - } - pub fn get_special_char(&self, cc_c_char: CC_C_CHAR) -> &CcT { &self.c_cc[cc_c_char.as_usize()] } @@ -265,3 +321,17 @@ impl KernelTermios { self.c_lflags.contains(C_LFLAGS::IEXTEN) } } + +const fn control_character(c: char) -> u8 { + debug_assert!(c as u8 >= 'A' as u8); + c as u8 - 'A' as u8 + 1u8 +} + +#[derive(Debug, Clone, Copy, Default, Pod)] +#[repr(C)] +pub struct WinSize { + ws_row: u16, + ws_col: u16, + ws_xpixel: u16, + ws_ypixel: u16, +} diff --git a/services/libs/jinux-std/src/fs/devpts/master.rs b/services/libs/jinux-std/src/fs/devpts/master.rs index e4d6c61e0..88a97cd0e 100644 --- a/services/libs/jinux-std/src/fs/devpts/master.rs +++ b/services/libs/jinux-std/src/fs/devpts/master.rs @@ -16,9 +16,10 @@ impl PtyMasterInode { impl Drop for PtyMasterInode { fn drop(&mut self) { // Remove the slave from fs. - let index = self.0.index(); let fs = self.0.ptmx().fs(); let devpts = fs.downcast_ref::().unwrap(); + + let index = self.0.index(); devpts.remove_slave(index); } } diff --git a/services/libs/jinux-std/src/fs/utils/ioctl.rs b/services/libs/jinux-std/src/fs/utils/ioctl.rs index bd97aac11..9a57cb020 100644 --- a/services/libs/jinux-std/src/fs/utils/ioctl.rs +++ b/services/libs/jinux-std/src/fs/utils/ioctl.rs @@ -16,6 +16,8 @@ pub enum IoctlCmd { TIOCGPGRP = 0x540f, /// Set the foreground process group ID of this terminal. TIOCSPGRP = 0x5410, + /// Get the number of bytes in the input buffer. + FIONREAD = 0x541B, /// Set window size TIOCGWINSZ = 0x5413, TIOCSWINSZ = 0x5414, diff --git a/services/libs/jinux-std/src/fs/utils/vnode.rs b/services/libs/jinux-std/src/fs/utils/vnode.rs index e8b944f98..617f6c36b 100644 --- a/services/libs/jinux-std/src/fs/utils/vnode.rs +++ b/services/libs/jinux-std/src/fs/utils/vnode.rs @@ -146,6 +146,7 @@ impl Vnode { if let Some(page_cache) = &inner.page_cache { page_cache.evict_range(0..file_len); } + inner.inode.read_at(0, &mut buf[..file_len]) } @@ -196,11 +197,13 @@ impl Vnode { } pub fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - self.inner.read().inode.poll(mask, poller) + let inode = self.inner.read().inode.clone(); + inode.poll(mask, poller) } pub fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result { - self.inner.read().inode.ioctl(cmd, arg) + let inode = self.inner.read().inode.clone(); + inode.ioctl(cmd, arg) } pub fn fs(&self) -> Arc { diff --git a/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs b/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs index 3e2d47c0a..f0011f354 100644 --- a/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs +++ b/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs @@ -150,12 +150,26 @@ impl VmMapping { } pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> { let vmo_read_offset = self.vmo_offset() + offset; + + let page_idx_range = get_page_idx_range(&(vmo_read_offset..vmo_read_offset + buf.len())); + let read_perm = VmPerm::R; + for page_idx in page_idx_range { + self.check_perm(&page_idx, &read_perm)?; + } + self.vmo.read_bytes(vmo_read_offset, buf)?; Ok(()) } pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> { let vmo_write_offset = self.vmo_offset() + offset; + + let page_idx_range = get_page_idx_range(&(vmo_write_offset..vmo_write_offset + buf.len())); + let write_perm = VmPerm::W; + for page_idx in page_idx_range { + self.check_perm(&page_idx, &write_perm)?; + } + self.vmo.write_bytes(vmo_write_offset, buf)?; Ok(()) } @@ -198,7 +212,9 @@ impl VmMapping { } else { self.vmo.check_rights(Rights::READ)?; } - self.check_perm(&page_idx, write)?; + + let required_perm = if write { VmPerm::W } else { VmPerm::R }; + self.check_perm(&page_idx, &required_perm)?; let frame = self.vmo.get_committed_frame(page_idx, write)?; @@ -300,8 +316,8 @@ impl VmMapping { self.inner.lock().trim_right(vm_space, vaddr) } - fn check_perm(&self, page_idx: &usize, write: bool) -> Result<()> { - self.inner.lock().check_perm(page_idx, write) + fn check_perm(&self, page_idx: &usize, perm: &VmPerm) -> Result<()> { + self.inner.lock().check_perm(page_idx, perm) } } @@ -457,16 +473,14 @@ impl VmMappingInner { self.map_to_addr..self.map_to_addr + self.map_size } - fn check_perm(&self, page_idx: &usize, write: bool) -> Result<()> { + fn check_perm(&self, page_idx: &usize, perm: &VmPerm) -> Result<()> { let page_perm = self .page_perms .get(&page_idx) .ok_or(Error::with_message(Errno::EINVAL, "invalid page idx"))?; - if !page_perm.contains(VmPerm::R) { - return_errno_with_message!(Errno::EINVAL, "perm should at least contain read"); - } - if write && !page_perm.contains(VmPerm::W) { - return_errno_with_message!(Errno::EINVAL, "perm should contain write for write access"); + + if !page_perm.contains(*perm) { + return_errno_with_message!(Errno::EACCES, "perm check fails"); } Ok(())