From afc09a460b954ec4915554bc904dd2af6de4feae Mon Sep 17 00:00:00 2001 From: LoGin Date: Sat, 27 Sep 2025 22:01:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(process):=20=E6=96=B0=E5=A2=9E=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E8=B5=84=E6=BA=90=E9=99=90=E5=88=B6=EF=BC=88rlimit?= =?UTF-8?q?=EF=BC=89=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=E5=8F=8A=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E7=B3=BB=E7=BB=9F=E8=B0=83=E7=94=A8=20(#1300)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为ProcessControlBlock添加rlimits字段,存储进程资源限制,默认初始化典型值(如nofi le软限制1024、硬限制65536) - 实现进程rlimit的获取、设置及继承机制(inherit_rlimits_from) - 在dup2、fcntl等函数中添加RLIMIT_NOFILE检查,确保文件描述符不超过软限制 - 实现sys_prlimit64和sys_setrlimit系统调用,支持查询和设置进程资源限制 - 调整测试用例,添加dup_test到gvisor白名单,忽略未支持的测试 Signed-off-by: longjin --- kernel/src/filesystem/vfs/file.rs | 139 +++++++++++++++--- kernel/src/filesystem/vfs/syscall/dup2.rs | 10 +- .../src/filesystem/vfs/syscall/sys_fcntl.rs | 16 +- .../filesystem/vfs/syscall/sys_getdents.rs | 3 +- kernel/src/process/fork.rs | 3 + kernel/src/process/mod.rs | 121 +++++++++++++++ kernel/src/process/syscall/mod.rs | 4 +- kernel/src/process/syscall/sys_prlimit64.rs | 67 ++++----- kernel/src/process/syscall/sys_setrlimit.rs | 50 +++++++ kernel/src/syscall/mod.rs | 2 - .../tests/syscall/gvisor/blocklists/dup_test | 2 + user/apps/tests/syscall/gvisor/whitelist.txt | 1 + 12 files changed, 346 insertions(+), 72 deletions(-) create mode 100644 kernel/src/process/syscall/sys_setrlimit.rs create mode 100644 user/apps/tests/syscall/gvisor/blocklists/dup_test diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 8eccf4ec1..f0cd7a17c 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use alloc::{string::String, sync::Arc, vec::Vec}; use log::error; @@ -129,6 +129,8 @@ pub struct File { pub private_data: SpinLock, /// 文件的凭证 cred: Arc, + /// 文件描述符标志:是否在execve时关闭 + close_on_exec: AtomicBool, } impl File { @@ -136,7 +138,7 @@ impl File { /// /// @param inode 文件对象对应的inode /// @param mode 文件的打开模式 - pub fn new(inode: Arc, mode: FileMode) -> Result { + pub fn new(inode: Arc, mut mode: FileMode) -> Result { let mut inode = inode; let file_type = inode.metadata()?.file_type; if file_type == FileType::Pipe { @@ -144,6 +146,8 @@ impl File { inode = pipe_inode; } } + let close_on_exec = mode.contains(FileMode::O_CLOEXEC); + mode.remove(FileMode::O_CLOEXEC); let private_data = SpinLock::new(FilePrivateData::default()); inode.open(private_data.lock(), &mode)?; @@ -156,6 +160,7 @@ impl File { readdir_subdirs_name: SpinLock::new(Vec::default()), private_data, cred: ProcessManager::current_pcb().cred(), + close_on_exec: AtomicBool::new(close_on_exec), }; return Ok(f); @@ -409,6 +414,7 @@ impl File { readdir_subdirs_name: SpinLock::new(self.readdir_subdirs_name.lock().clone()), private_data: SpinLock::new(self.private_data.lock().clone()), cred: self.cred.clone(), + close_on_exec: AtomicBool::new(self.close_on_exec.load(Ordering::SeqCst)), }; // 调用inode的open方法,让inode知道有新的文件打开了这个inode // TODO: reopen is not a good idea for some inodes, need a better design @@ -438,25 +444,27 @@ impl File { /// 获取文件是否在execve时关闭 #[inline] pub fn close_on_exec(&self) -> bool { - return self.mode().contains(FileMode::O_CLOEXEC); + return self.close_on_exec.load(Ordering::SeqCst); } /// 设置文件是否在execve时关闭 #[inline] pub fn set_close_on_exec(&self, close_on_exec: bool) { - let mut mode_guard = self.mode.write(); - if close_on_exec { - mode_guard.insert(FileMode::O_CLOEXEC); - } else { - mode_guard.remove(FileMode::O_CLOEXEC); - } + self.close_on_exec.store(close_on_exec, Ordering::SeqCst); } - pub fn set_mode(&self, mode: FileMode) -> Result<(), SystemError> { + pub fn set_mode(&self, mut mode: FileMode) -> Result<(), SystemError> { // todo: 是否需要调用inode的open方法,以更新private data(假如它与mode有关的话)? // 也许需要加个更好的设计,让inode知晓文件的打开模式发生了变化,让它自己决定是否需要更新private data - // 直接修改文件的打开模式 + // 提取 O_CLOEXEC 状态并更新 close_on_exec 字段 + let close_on_exec = mode.contains(FileMode::O_CLOEXEC); + self.close_on_exec.store(close_on_exec, Ordering::SeqCst); + + // 从 mode 中移除 O_CLOEXEC 标志,保持与构造函数一致的行为 + mode.remove(FileMode::O_CLOEXEC); + + // 更新文件的打开模式 *self.mode.write() = mode; self.private_data.lock().update_mode(mode); return Ok(()); @@ -528,12 +536,15 @@ impl Default for FileDescriptorVec { } } impl FileDescriptorVec { - pub const PROCESS_MAX_FD: usize = 1024; + /// 文件描述符表的初始容量 + pub const INITIAL_CAPACITY: usize = 1024; + /// 文件描述符表的最大容量限制(防止无限扩容) + pub const MAX_CAPACITY: usize = 65536; #[inline(never)] pub fn new() -> FileDescriptorVec { - let mut data = Vec::with_capacity(FileDescriptorVec::PROCESS_MAX_FD); - data.resize(FileDescriptorVec::PROCESS_MAX_FD, None); + let mut data = Vec::with_capacity(FileDescriptorVec::INITIAL_CAPACITY); + data.resize(FileDescriptorVec::INITIAL_CAPACITY, None); // 初始化文件描述符数组结构体 return FileDescriptorVec { fds: data }; @@ -544,7 +555,10 @@ impl FileDescriptorVec { /// @return FileDescriptorVec 克隆后的文件描述符数组 pub fn clone(&self) -> FileDescriptorVec { let mut res = FileDescriptorVec::new(); - for i in 0..FileDescriptorVec::PROCESS_MAX_FD { + // 调整容量以匹配源文件描述符表 + let _ = res.resize_to_capacity(self.fds.len()); + + for i in 0..self.fds.len() { if let Some(file) = &self.fds[i] { if let Some(file) = file.try_clone() { res.fds[i] = Some(Arc::new(file)); @@ -554,6 +568,46 @@ impl FileDescriptorVec { return res; } + /// 返回当前已占用的最高文件描述符索引(若无则为None) + #[inline] + fn highest_open_index(&self) -> Option { + // 从高到低查找第一个占用的槽位 + (0..self.fds.len()).rev().find(|&i| self.fds[i].is_some()) + } + + /// 扩容文件描述符表到指定容量 + /// + /// ## 参数 + /// - `new_capacity`: 新的容量大小 + /// + /// ## 返回值 + /// - `Ok(())`: 扩容成功 + /// - `Err(SystemError)`: 扩容失败 + fn resize_to_capacity(&mut self, new_capacity: usize) -> Result<(), SystemError> { + if new_capacity > FileDescriptorVec::MAX_CAPACITY { + return Err(SystemError::EMFILE); + } + + let current_len = self.fds.len(); + if new_capacity > current_len { + // 扩容:扩展向量并填充None + // 使用 try_reserve 先检查内存分配是否可能成功 + if self.fds.try_reserve(new_capacity - current_len).is_err() { + return Err(SystemError::ENOMEM); + } + self.fds.resize(new_capacity, None); + } else if new_capacity < current_len { + // 缩容:允许,但不能丢弃仍在使用的高位fd。 + // 若高位fd仍在使用,将缩容目标提升到 (最高已用fd + 1)。 + let floor = self.highest_open_index().map(|idx| idx + 1).unwrap_or(0); + let target = core::cmp::max(new_capacity, floor); + if target < current_len { + self.fds.truncate(target); + } + } + Ok(()) + } + /// 返回 `已经打开的` 文件描述符的数量 pub fn fd_open_count(&self) -> usize { let mut size = 0; @@ -571,8 +625,8 @@ impl FileDescriptorVec { /// /// @return false 不合法 #[inline] - pub fn validate_fd(fd: i32) -> bool { - return !(fd < 0 || fd as usize > FileDescriptorVec::PROCESS_MAX_FD); + pub fn validate_fd(&self, fd: i32) -> bool { + return !(fd < 0 || fd as usize >= self.fds.len()); } /// 申请文件描述符,并把文件对象存入其中。 @@ -587,7 +641,22 @@ impl FileDescriptorVec { /// - `Ok(i32)` 申请成功,返回申请到的文件描述符 /// - `Err(SystemError)` 申请失败,返回错误码,并且,file对象将被drop掉 pub fn alloc_fd(&mut self, file: File, fd: Option) -> Result { + // 获取RLIMIT_NOFILE限制 + let nofile_limit = crate::process::ProcessManager::current_pcb() + .get_rlimit(crate::process::resource::RLimitID::Nofile) + .rlim_cur as usize; + if let Some(new_fd) = fd { + // 检查指定的文件描述符是否在有效范围内 + if new_fd < 0 || new_fd as usize >= nofile_limit { + return Err(SystemError::EMFILE); + } + + // 如果指定的fd超出当前容量,需要扩容 + if new_fd as usize >= self.fds.len() { + self.resize_to_capacity(new_fd as usize + 1)?; + } + let x = &mut self.fds[new_fd as usize]; if x.is_none() { *x = Some(Arc::new(file)); @@ -596,8 +665,9 @@ impl FileDescriptorVec { return Err(SystemError::EBADF); } } else { - // 没有指定要申请的文件描述符编号 - for i in 0..FileDescriptorVec::PROCESS_MAX_FD { + // 没有指定要申请的文件描述符编号,在有效范围内查找空位 + let max_search = core::cmp::min(self.fds.len(), nofile_limit); + for i in 0..max_search { if self.fds[i].is_none() { self.fds[i] = Some(Arc::new(file)); return Ok(i as i32); @@ -613,12 +683,37 @@ impl FileDescriptorVec { /// /// - `fd` 文件描述符序号 pub fn get_file_by_fd(&self, fd: i32) -> Option> { - if !FileDescriptorVec::validate_fd(fd) { + if !self.validate_fd(fd) { return None; } self.fds[fd as usize].clone() } + /// 当RLIMIT_NOFILE变化时调整文件描述符表容量 + /// + /// ## 参数 + /// - `new_rlimit_nofile`: 新的RLIMIT_NOFILE值 + /// + /// ## 返回值 + /// - `Ok(())`: 调整成功 + /// - `Err(SystemError)`: 调整失败 + pub fn adjust_for_rlimit_change( + &mut self, + new_rlimit_nofile: usize, + ) -> Result<(), SystemError> { + // 目标容量不超过实现上限 + let desired = core::cmp::min(new_rlimit_nofile, FileDescriptorVec::MAX_CAPACITY); + if desired >= self.fds.len() { + // rlimit 变大:扩容到 desired + self.resize_to_capacity(desired) + } else { + // rlimit 变小:按用户建议,缩容到 max(desired, 最高已用fd+1) + let floor = self.highest_open_index().map(|idx| idx + 1).unwrap_or(0); + let target = core::cmp::max(desired, floor); + self.resize_to_capacity(target) + } + } + /// 释放文件描述符,同时关闭文件。 /// /// ## 参数 @@ -638,7 +733,7 @@ impl FileDescriptorVec { } pub fn close_on_exec(&mut self) { - for i in 0..FileDescriptorVec::PROCESS_MAX_FD { + for i in 0..self.fds.len() { if let Some(file) = &self.fds[i] { let to_drop = file.close_on_exec(); if to_drop { @@ -672,7 +767,7 @@ impl Iterator for FileDescriptorIterator<'_> { type Item = (i32, Arc); fn next(&mut self) -> Option { - while self.index < FileDescriptorVec::PROCESS_MAX_FD { + while self.index < self.fds.fds.len() { let fd = self.index as i32; self.index += 1; if let Some(file) = self.fds.get_file_by_fd(fd) { diff --git a/kernel/src/filesystem/vfs/syscall/dup2.rs b/kernel/src/filesystem/vfs/syscall/dup2.rs index 91b59ebff..a0d848296 100644 --- a/kernel/src/filesystem/vfs/syscall/dup2.rs +++ b/kernel/src/filesystem/vfs/syscall/dup2.rs @@ -19,8 +19,16 @@ pub fn do_dup3( flags: FileMode, fd_table_guard: &mut RwLockWriteGuard<'_, FileDescriptorVec>, ) -> Result { + // 检查 RLIMIT_NOFILE:newfd 必须小于软限制 + let nofile = crate::process::ProcessManager::current_pcb() + .get_rlimit(crate::process::resource::RLimitID::Nofile) + .rlim_cur; + if newfd as u64 >= nofile { + return Err(SystemError::EMFILE); + } + // 确认oldfd, newid是否有效 - if !(FileDescriptorVec::validate_fd(oldfd) && FileDescriptorVec::validate_fd(newfd)) { + if !(fd_table_guard.validate_fd(oldfd) && fd_table_guard.validate_fd(newfd)) { return Err(SystemError::EBADF); } diff --git a/kernel/src/filesystem/vfs/syscall/sys_fcntl.rs b/kernel/src/filesystem/vfs/syscall/sys_fcntl.rs index 934deb36d..5a69e06f7 100644 --- a/kernel/src/filesystem/vfs/syscall/sys_fcntl.rs +++ b/kernel/src/filesystem/vfs/syscall/sys_fcntl.rs @@ -3,7 +3,7 @@ use crate::{ arch::interrupt::TrapFrame, filesystem::vfs::{ fcntl::{FcntlCommand, FD_CLOEXEC}, - file::{FileDescriptorVec, FileMode}, + file::FileMode, syscall::dup2::{do_dup2, do_dup3}, }, process::ProcessManager, @@ -70,13 +70,19 @@ impl SysFcntlHandle { // debug!("fcntl ({cmd:?}) fd: {fd}, arg={arg}"); match cmd { FcntlCommand::DupFd | FcntlCommand::DupFdCloexec => { - if arg < 0 || arg as usize >= FileDescriptorVec::PROCESS_MAX_FD { + // RLIMIT_NOFILE 检查 + let nofile = ProcessManager::current_pcb() + .get_rlimit(crate::process::resource::RLimitID::Nofile) + .rlim_cur as usize; + if arg < 0 || arg as usize >= nofile { return Err(SystemError::EBADF); } let arg = arg as usize; - for i in arg..FileDescriptorVec::PROCESS_MAX_FD { - let binding = ProcessManager::current_pcb().fd_table(); - let mut fd_table_guard = binding.write(); + let binding = ProcessManager::current_pcb().fd_table(); + let mut fd_table_guard = binding.write(); + + // 在RLIMIT_NOFILE范围内查找可用的文件描述符 + for i in arg..nofile { if fd_table_guard.get_file_by_fd(i as i32).is_none() { if cmd == FcntlCommand::DupFd { return do_dup2(fd, i as i32, &mut fd_table_guard); diff --git a/kernel/src/filesystem/vfs/syscall/sys_getdents.rs b/kernel/src/filesystem/vfs/syscall/sys_getdents.rs index bea4d971c..df37e6849 100644 --- a/kernel/src/filesystem/vfs/syscall/sys_getdents.rs +++ b/kernel/src/filesystem/vfs/syscall/sys_getdents.rs @@ -4,7 +4,6 @@ use system_error::SystemError; use crate::arch::interrupt::TrapFrame; use crate::arch::syscall::nr::{SYS_GETDENTS, SYS_GETDENTS64}; -use crate::filesystem::vfs::file::FileDescriptorVec; use crate::filesystem::vfs::FilldirContext; use crate::mm::{verify_area, VirtAddr}; use crate::process::ProcessManager; @@ -48,7 +47,7 @@ impl Syscall for SysGetdentsHandle { let buf: &mut [u8] = unsafe { core::slice::from_raw_parts_mut::<'static, u8>(buf_vaddr as *mut u8, len) }; - if fd < 0 || fd as usize > FileDescriptorVec::PROCESS_MAX_FD { + if fd < 0 { return Err(SystemError::EBADF); } diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index 207593817..234aa7aea 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -482,6 +482,9 @@ impl ProcessManager { ) }); + // 继承 rlimit + pcb.inherit_rlimits_from(current_pcb); + // log::debug!("fork: clone_flags: {:?}", clone_flags); // 设置线程组id、组长 if clone_flags.contains(CloneFlags::CLONE_THREAD) { diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index a603060ae..36fffc247 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -57,6 +57,7 @@ use crate::{ PhysAddr, VirtAddr, }, net::socket::Socket, + process::resource::{RLimit64, RLimitID}, sched::{ DequeueFlag, EnqueueFlag, OnRq, SchedMode, WakeupFlags, __schedule, completion::Completion, cpu_rq, fair::FairSchedEntity, prio::MAX_PRIO, @@ -778,6 +779,8 @@ pub struct ProcessControlBlock { /// 进程的可执行文件路径 executable_path: RwLock, + /// 资源限制(rlimit)数组 + rlimits: RwLock<[RLimit64; RLimitID::Nlimits as usize]>, } impl ProcessControlBlock { @@ -896,6 +899,7 @@ impl ProcessControlBlock { self_ref: weak.clone(), restart_block: SpinLock::new(None), executable_path: RwLock::new(name), + rlimits: RwLock::new(Self::default_rlimits()), }; pcb.sig_info.write().set_tty(tty); @@ -929,6 +933,123 @@ impl ProcessControlBlock { return pcb; } + fn default_rlimits() -> [crate::process::resource::RLimit64; RLimitID::Nlimits as usize] { + use crate::mm::ucontext::UserStack; + use crate::process::resource::{RLimit64, RLimitID}; + + let mut arr = [RLimit64 { + rlim_cur: 0, + rlim_max: 0, + }; RLimitID::Nlimits as usize]; + + // Linux 典型默认值:软限制1024,硬限制65536 + // 文件描述符表会根据RLIMIT_NOFILE自动扩容 + arr[RLimitID::Nofile as usize] = RLimit64 { + rlim_cur: 1024, + rlim_max: 65536, + }; + + arr[RLimitID::Stack as usize] = RLimit64 { + rlim_cur: UserStack::DEFAULT_USER_STACK_SIZE as u64, + rlim_max: UserStack::DEFAULT_USER_STACK_SIZE as u64, + }; + + arr[RLimitID::As as usize] = { + let end = ::USER_END_VADDR; + RLimit64 { + rlim_cur: end.data() as u64, + rlim_max: end.data() as u64, + } + }; + arr[RLimitID::Rss as usize] = arr[RLimitID::As as usize]; + + arr + } + + #[inline(always)] + pub fn get_rlimit(&self, res: RLimitID) -> crate::process::resource::RLimit64 { + self.rlimits.read()[res as usize] + } + + pub fn set_rlimit( + &self, + res: RLimitID, + newv: crate::process::resource::RLimit64, + ) -> Result<(), system_error::SystemError> { + use system_error::SystemError; + if newv.rlim_cur > newv.rlim_max { + return Err(SystemError::EINVAL); + } + + // 注意:允许RLIMIT_NOFILE设置为0,这是测试用例的预期行为 + // 当rlim_cur为0时,无法分配新的文件描述符,但现有fd仍可使用 + + // 对于RLIMIT_NOFILE,检查是否超过系统实现的最大容量限制 + if res == RLimitID::Nofile { + if newv.rlim_cur > FileDescriptorVec::MAX_CAPACITY as u64 { + return Err(SystemError::EINVAL); + } + if newv.rlim_max > FileDescriptorVec::MAX_CAPACITY as u64 { + return Err(SystemError::EINVAL); + } + } + + let cur = self.rlimits.read()[res as usize]; + if newv.rlim_max > cur.rlim_max { + let cred = self.cred(); + if !cred.has_capability(crate::process::cred::CAPFlags::CAP_SYS_RESOURCE) { + return Err(SystemError::EPERM); + } + } + + // 更新rlimit + self.rlimits.write()[res as usize] = newv; + + // 如果是RLIMIT_NOFILE变化,调整文件描述符表 + if res == RLimitID::Nofile { + if let Err(e) = self.adjust_fd_table_for_rlimit_change(newv.rlim_cur as usize) { + // 如果调整失败,回滚rlimit设置 + self.rlimits.write()[res as usize] = cur; + return Err(e); + } + } + + Ok(()) + } + + /// 继承父进程的全部rlimit + pub fn inherit_rlimits_from(&self, parent: &Arc) { + let src = *parent.rlimits.read(); + *self.rlimits.write() = src; + + // 继承后调整文件描述符表以匹配新的RLIMIT_NOFILE + let nofile_limit = src[RLimitID::Nofile as usize].rlim_cur as usize; + if let Err(e) = self.adjust_fd_table_for_rlimit_change(nofile_limit) { + // 如果调整失败,记录错误但不影响继承过程 + error!( + "Failed to adjust fd table after inheriting rlimits: {:?}", + e + ); + } + } + + /// 当RLIMIT_NOFILE变化时调整文件描述符表 + /// + /// ## 参数 + /// - `new_rlimit_nofile`: 新的RLIMIT_NOFILE值 + /// + /// ## 返回值 + /// - `Ok(())`: 调整成功 + /// - `Err(SystemError)`: 调整失败 + fn adjust_fd_table_for_rlimit_change( + &self, + new_rlimit_nofile: usize, + ) -> Result<(), system_error::SystemError> { + let fd_table = self.basic.read().try_fd_table().unwrap(); + let mut fd_table_guard = fd_table.write(); + fd_table_guard.adjust_for_rlimit_change(new_rlimit_nofile) + } + /// 返回当前进程的锁持有计数 #[inline(always)] pub fn preempt_count(&self) -> usize { diff --git a/kernel/src/process/syscall/mod.rs b/kernel/src/process/syscall/mod.rs index bbfeacc12..9a7fe4bac 100644 --- a/kernel/src/process/syscall/mod.rs +++ b/kernel/src/process/syscall/mod.rs @@ -15,7 +15,7 @@ mod sys_getsid; mod sys_gettid; mod sys_getuid; mod sys_groups; -mod sys_prlimit64; +pub mod sys_prlimit64; mod sys_set_tid_address; mod sys_setdomainname; mod sys_setfsgid; @@ -39,4 +39,6 @@ mod sys_getpgrp; #[cfg(target_arch = "x86_64")] mod sys_getrlimit; #[cfg(target_arch = "x86_64")] +mod sys_setrlimit; +#[cfg(target_arch = "x86_64")] mod sys_vfork; diff --git a/kernel/src/process/syscall/sys_prlimit64.rs b/kernel/src/process/syscall/sys_prlimit64.rs index 806376c72..937c513a5 100644 --- a/kernel/src/process/syscall/sys_prlimit64.rs +++ b/kernel/src/process/syscall/sys_prlimit64.rs @@ -2,14 +2,11 @@ use crate::arch::syscall::nr::SYS_PRLIMIT64; use crate::syscall::table::FormattedSyscallParam; use crate::syscall::table::Syscall; use crate::{ - arch::MMArch, - filesystem::vfs::file::FileDescriptorVec, - mm::{ucontext::UserStack, MemoryManagementArch}, process::{ resource::{RLimit64, RLimitID}, - RawPid, + ProcessManager, RawPid, }, - syscall::user_access::UserBufferWriter, + syscall::user_access::{UserBufferReader, UserBufferWriter}, }; use alloc::vec::Vec; use system_error::SystemError; @@ -83,15 +80,14 @@ syscall_table_macros::declare_syscall!(SYS_PRLIMIT64, SysPrlimit64); /// - 成功,0 /// - 如果old_limit不为NULL,则返回旧的资源限制到old_limit /// -pub(super) fn do_prlimit64( - _pid: RawPid, +pub fn do_prlimit64( + pid: RawPid, resource: usize, - _new_limit: *const RLimit64, + new_limit: *const RLimit64, old_limit: *mut RLimit64, ) -> Result { let resource = RLimitID::try_from(resource)?; let mut writer = None; - if !old_limit.is_null() { writer = Some(UserBufferWriter::new( old_limit, @@ -100,36 +96,29 @@ pub(super) fn do_prlimit64( )?); } - match resource { - RLimitID::Stack => { - if let Some(mut writer) = writer { - let mut rlimit = writer.buffer::(0).unwrap()[0]; - rlimit.rlim_cur = UserStack::DEFAULT_USER_STACK_SIZE as u64; - rlimit.rlim_max = UserStack::DEFAULT_USER_STACK_SIZE as u64; - } - return Ok(0); - } + // 找到目标进程(仅支持当前命名空间可见) + let target = if pid.data() == 0 { + ProcessManager::current_pcb() + } else { + ProcessManager::find_task_by_vpid(pid).ok_or(SystemError::ESRCH)? + }; - RLimitID::Nofile => { - if let Some(mut writer) = writer { - let mut rlimit = writer.buffer::(0).unwrap()[0]; - rlimit.rlim_cur = FileDescriptorVec::PROCESS_MAX_FD as u64; - rlimit.rlim_max = FileDescriptorVec::PROCESS_MAX_FD as u64; - } - return Ok(0); - } - - RLimitID::As | RLimitID::Rss => { - if let Some(mut writer) = writer { - let mut rlimit = writer.buffer::(0).unwrap()[0]; - rlimit.rlim_cur = MMArch::USER_END_VADDR.data() as u64; - rlimit.rlim_max = MMArch::USER_END_VADDR.data() as u64; - } - return Ok(0); - } - - _ => { - return Err(SystemError::ENOSYS); - } + // 读取旧限制 + if let Some(mut writer) = writer { + let cur = target.get_rlimit(resource); + let rlimit = writer.buffer::(0)?; + rlimit[0].rlim_cur = cur.rlim_cur; + rlimit[0].rlim_max = cur.rlim_max; } + + // 设置新限制 + if !new_limit.is_null() { + // 从用户拷贝新值 + let reader = UserBufferReader::new(new_limit, core::mem::size_of::(), true)?; + let newval = *reader.read_one_from_user::(0)?; + // 应用到目标进程 + target.set_rlimit(resource, newval)?; + } + + Ok(0) } diff --git a/kernel/src/process/syscall/sys_setrlimit.rs b/kernel/src/process/syscall/sys_setrlimit.rs new file mode 100644 index 000000000..13e13c385 --- /dev/null +++ b/kernel/src/process/syscall/sys_setrlimit.rs @@ -0,0 +1,50 @@ +use system_error::SystemError; + +use crate::arch::interrupt::TrapFrame; +use crate::arch::syscall::nr::SYS_SETRLIMIT; +use crate::process::resource::RLimit64; +use crate::process::syscall::sys_prlimit64::do_prlimit64; +use crate::process::ProcessManager; +use crate::syscall::table::FormattedSyscallParam; +use crate::syscall::table::Syscall; + +use alloc::vec::Vec; + +pub struct SysSetRlimit; + +impl SysSetRlimit { + fn resource(args: &[usize]) -> usize { + args[0] + } + + fn rlimit(args: &[usize]) -> *const RLimit64 { + args[1] as *const RLimit64 + } +} + +impl Syscall for SysSetRlimit { + fn num_args(&self) -> usize { + 2 + } + + fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result { + let resource = Self::resource(args); + let rlimit = Self::rlimit(args); + + do_prlimit64( + ProcessManager::current_pcb().raw_pid(), + resource, + rlimit, + core::ptr::null_mut::(), + ) + } + + fn entry_format(&self, args: &[usize]) -> Vec { + vec![ + FormattedSyscallParam::new("resource", format!("{:#x}", Self::resource(args))), + FormattedSyscallParam::new("rlimit", format!("{:#x}", Self::rlimit(args) as usize)), + ] + } +} + +syscall_table_macros::declare_syscall!(SYS_SETRLIMIT, SysSetRlimit); diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index be24aa17b..2a4f94d1f 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -477,8 +477,6 @@ impl Syscall { let flags = args[4] as u32; Self::sys_perf_event_open(attr, pid, cpu, group_fd, flags) } - #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] - SYS_SETRLIMIT => Ok(0), SYS_RT_SIGTIMEDWAIT => { log::warn!("SYS_RT_SIGTIMEDWAIT has not yet been implemented"); diff --git a/user/apps/tests/syscall/gvisor/blocklists/dup_test b/user/apps/tests/syscall/gvisor/blocklists/dup_test new file mode 100644 index 000000000..0155744ee --- /dev/null +++ b/user/apps/tests/syscall/gvisor/blocklists/dup_test @@ -0,0 +1,2 @@ +# 暂时不支持该测例,因为/proc/sys/fs/nr_open没支持 +RlimitTest.DupLimitedByNROpenSysctl diff --git a/user/apps/tests/syscall/gvisor/whitelist.txt b/user/apps/tests/syscall/gvisor/whitelist.txt index 3777362db..237e5b304 100644 --- a/user/apps/tests/syscall/gvisor/whitelist.txt +++ b/user/apps/tests/syscall/gvisor/whitelist.txt @@ -9,6 +9,7 @@ bad_test uname_test # 文件系统相关测试 +dup_test #stat_test #chmod_test #chown_test