diff --git a/kernel/aster-nix/src/syscall/nanosleep.rs b/kernel/aster-nix/src/syscall/nanosleep.rs index bd74f8dfe..68749c204 100644 --- a/kernel/aster-nix/src/syscall/nanosleep.rs +++ b/kernel/aster-nix/src/syscall/nanosleep.rs @@ -54,7 +54,7 @@ fn do_clock_nanosleep( ) -> Result { let request_time = { let timespec = read_val_from_user::(request_timespec_addr)?; - Duration::from(timespec) + Duration::try_from(timespec)? }; debug!( diff --git a/kernel/aster-nix/src/syscall/pselect6.rs b/kernel/aster-nix/src/syscall/pselect6.rs index 37d636948..618e71ff4 100644 --- a/kernel/aster-nix/src/syscall/pselect6.rs +++ b/kernel/aster-nix/src/syscall/pselect6.rs @@ -1,12 +1,13 @@ // SPDX-License-Identifier: MPL-2.0 -use core::sync::atomic::Ordering; +use core::{sync::atomic::Ordering, time::Duration}; -use super::{select::sys_select, SyscallReturn}; +use super::{select::do_sys_select, SyscallReturn}; use crate::{ fs::file_table::FileDesc, prelude::*, process::{posix_thread::PosixThreadExt, signal::sig_mask::SigMask}, + time::timespec_t, util::read_val_from_user, }; @@ -15,28 +16,35 @@ pub fn sys_pselect6( readfds_addr: Vaddr, writefds_addr: Vaddr, exceptfds_addr: Vaddr, - timeval_addr: Vaddr, + timespec_addr: Vaddr, sigmask_addr: Vaddr, ) -> Result { let current_thread = current_thread!(); let posix_thread = current_thread.as_posix_thread().unwrap(); let old_simask = if sigmask_addr != 0 { - let new_sigmask: SigMask = read_val_from_user(sigmask_addr)?; - let old_sigmask = posix_thread.sig_mask().swap(new_sigmask, Ordering::Relaxed); + let sigmask_with_size: SigMaskWithSize = read_val_from_user(sigmask_addr)?; + + if !sigmask_with_size.is_valid() { + return_errno_with_message!(Errno::EINVAL, "sigmask size is invalid") + } + let old_sigmask = posix_thread + .sig_mask() + .swap(sigmask_with_size.sigmask, Ordering::Relaxed); Some(old_sigmask) } else { None }; - let res = sys_select( - nfds, - readfds_addr, - writefds_addr, - exceptfds_addr, - timeval_addr, - ); + let timeout = if timespec_addr != 0 { + let time_spec: timespec_t = read_val_from_user(timespec_addr)?; + Some(Duration::try_from(time_spec)?) + } else { + None + }; + + let res = do_sys_select(nfds, readfds_addr, writefds_addr, exceptfds_addr, timeout); if let Some(old_mask) = old_simask { posix_thread.sig_mask().store(old_mask, Ordering::Relaxed); @@ -44,3 +52,16 @@ pub fn sys_pselect6( res } + +#[repr(C)] +#[derive(Debug, Clone, Copy, Pod)] +struct SigMaskWithSize { + sigmask: SigMask, + sigmasksize: usize, +} + +impl SigMaskWithSize { + const fn is_valid(&self) -> bool { + self.sigmask.is_empty() || self.sigmasksize == size_of::() + } +} diff --git a/kernel/aster-nix/src/syscall/select.rs b/kernel/aster-nix/src/syscall/select.rs index 070388cb2..4b16e0652 100644 --- a/kernel/aster-nix/src/syscall/select.rs +++ b/kernel/aster-nix/src/syscall/select.rs @@ -22,6 +22,23 @@ pub fn sys_select( writefds_addr: Vaddr, exceptfds_addr: Vaddr, timeval_addr: Vaddr, +) -> Result { + let timeout = if timeval_addr == 0 { + None + } else { + let timeval = read_val_from_user::(timeval_addr)?; + Some(Duration::from(timeval)) + }; + + do_sys_select(nfds, readfds_addr, writefds_addr, exceptfds_addr, timeout) +} + +pub fn do_sys_select( + nfds: FileDesc, + readfds_addr: Vaddr, + writefds_addr: Vaddr, + exceptfds_addr: Vaddr, + timeout: Option, ) -> Result { if nfds < 0 || nfds as usize > FD_SETSIZE { return_errno_with_message!(Errno::EINVAL, "nfds is negative or exceeds the FD_SETSIZE"); @@ -40,13 +57,6 @@ pub fn sys_select( let mut writefds = get_fdset(writefds_addr)?; let mut exceptfds = get_fdset(exceptfds_addr)?; - let timeout = if timeval_addr == 0 { - None - } else { - let timeval = read_val_from_user::(timeval_addr)?; - Some(Duration::from(timeval)) - }; - debug!( "nfds = {}, readfds = {:?}, writefds = {:?}, exceptfds = {:?}, timeout = {:?}", nfds, readfds, writefds, exceptfds, timeout diff --git a/kernel/aster-nix/src/syscall/timer_settime.rs b/kernel/aster-nix/src/syscall/timer_settime.rs index 9061540ad..2932e97b3 100644 --- a/kernel/aster-nix/src/syscall/timer_settime.rs +++ b/kernel/aster-nix/src/syscall/timer_settime.rs @@ -20,8 +20,8 @@ pub fn sys_timer_settime( } let new_itimerspec = read_val_from_user::(new_itimerspec_addr)?; - let interval = Duration::from(new_itimerspec.it_interval); - let expire_time = Duration::from(new_itimerspec.it_value); + let interval = Duration::try_from(new_itimerspec.it_interval)?; + let expire_time = Duration::try_from(new_itimerspec.it_value)?; let current_process = current!(); let Some(timer) = current_process.timer_manager().find_posix_timer(timer_id) else { diff --git a/kernel/aster-nix/src/syscall/utimens.rs b/kernel/aster-nix/src/syscall/utimens.rs index f27136119..c253a1c64 100644 --- a/kernel/aster-nix/src/syscall/utimens.rs +++ b/kernel/aster-nix/src/syscall/utimens.rs @@ -120,14 +120,14 @@ fn vfs_utimes(dentry: &Arc, times: Option) -> Result for timespec_t { } } -impl From for Duration { - fn from(timespec: timespec_t) -> Self { - Duration::new(timespec.sec as u64, timespec.nsec as u32) +impl TryFrom for Duration { + type Error = crate::Error; + + fn try_from(value: timespec_t) -> Result { + if value.sec < 0 || value.nsec < 0 { + return_errno_with_message!(Errno::EINVAL, "timesepc_t cannot be negative"); + } + + if value.nsec > 1_000_000_000 { + // The value of nanoseconds cannot exceed 10^9, + // otherwise the value for seconds should be set. + return_errno_with_message!(Errno::EINVAL, "nsec is not normalized"); + } + + Ok(Duration::new(value.sec as u64, value.nsec as u32)) } } diff --git a/test/syscall_test/Makefile b/test/syscall_test/Makefile index 27fdb65a8..898cafc28 100644 --- a/test/syscall_test/Makefile +++ b/test/syscall_test/Makefile @@ -28,6 +28,7 @@ TESTS ?= \ open_test \ pread64_test \ preadv2_test \ + pselect_test \ pwrite64_test \ pwritev2_test \ pty_test \ diff --git a/test/syscall_test/blocklists/pselect_test b/test/syscall_test/blocklists/pselect_test new file mode 100644 index 000000000..036af11f7 --- /dev/null +++ b/test/syscall_test/blocklists/pselect_test @@ -0,0 +1,4 @@ +PselectTest.NoTimeout_NoRandomSave +PselectTest.NullFds +PselectTest.SignalMaskBlocksSignal +PselectTest.SignalMaskAllowsSignal \ No newline at end of file