From 0f094e50dee4cc20efbbe32852a4c79e619c4806 Mon Sep 17 00:00:00 2001 From: LoGin Date: Tue, 12 Nov 2024 14:01:26 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=BA=86do=20execve?= =?UTF-8?q?=20=E5=8A=A0=E8=BD=BD=E7=A8=8B=E5=BA=8F=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E6=97=B6,=E6=B2=A1=E8=83=BD=E6=AD=A3=E7=A1=AE=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E9=94=99=E8=AF=AF=E7=A0=81=E7=BB=99=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=80=81=E7=9A=84=E9=97=AE=E9=A2=98=20(#1042)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 修复了do execve 加载程序失败时,没能正确返回错误码给用户态的问题 --- kernel/src/arch/riscv64/process/syscall.rs | 93 ++-------------- kernel/src/arch/x86_64/process/syscall.rs | 90 ++-------------- kernel/src/process/syscall.rs | 118 ++++++++++++++++++++- 3 files changed, 131 insertions(+), 170 deletions(-) diff --git a/kernel/src/arch/riscv64/process/syscall.rs b/kernel/src/arch/riscv64/process/syscall.rs index b60f347b..21ddbed3 100644 --- a/kernel/src/arch/riscv64/process/syscall.rs +++ b/kernel/src/arch/riscv64/process/syscall.rs @@ -1,96 +1,21 @@ -use alloc::{ffi::CString, string::String, vec::Vec}; use riscv::register::sstatus::{FS, SPP}; use system_error::SystemError; use crate::{ - arch::{interrupt::TrapFrame, CurrentIrqArch}, - exception::InterruptArch, - mm::ucontext::AddressSpace, - process::{ - exec::{load_binary_file, ExecParam, ExecParamFlags}, - ProcessManager, - }, + arch::interrupt::TrapFrame, + mm::VirtAddr, + process::exec::{BinaryLoaderResult, ExecParam}, syscall::Syscall, }; impl Syscall { - pub fn do_execve( - path: String, - argv: Vec, - envp: Vec, + pub fn arch_do_execve( regs: &mut TrapFrame, + param: &ExecParam, + load_result: &BinaryLoaderResult, + user_sp: VirtAddr, + argv_ptr: VirtAddr, ) -> Result<(), SystemError> { - // 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。 - let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; - let pcb = ProcessManager::current_pcb(); - // crate::debug!( - // "pid: {:?} do_execve: path: {:?}, argv: {:?}, envp: {:?}\n", - // pcb.pid(), - // path, - // argv, - // envp - // ); - - let mut basic_info = pcb.basic_mut(); - // 暂存原本的用户地址空间的引用(因为如果在切换页表之前释放了它,可能会造成内存use after free) - let old_address_space = basic_info.user_vm(); - - // 在pcb中原来的用户地址空间 - unsafe { - basic_info.set_user_vm(None); - } - // 创建新的地址空间并设置为当前地址空间 - let address_space = AddressSpace::new(true).expect("Failed to create new address space"); - unsafe { - basic_info.set_user_vm(Some(address_space.clone())); - } - - // to avoid deadlock - drop(basic_info); - - assert!( - AddressSpace::is_current(&address_space), - "Failed to set address space" - ); - // debug!("Switch to new address space"); - - // 切换到新的用户地址空间 - unsafe { address_space.read().user_mapper.utable.make_current() }; - - drop(old_address_space); - drop(irq_guard); - // debug!("to load binary file"); - let mut param = ExecParam::new(path.as_str(), address_space.clone(), ExecParamFlags::EXEC)?; - - // 加载可执行文件 - let load_result = load_binary_file(&mut param)?; - // debug!("load binary file done"); - // debug!("argv: {:?}, envp: {:?}", argv, envp); - param.init_info_mut().args = argv; - param.init_info_mut().envs = envp; - - // 把proc_init_info写到用户栈上 - let mut ustack_message = unsafe { - address_space - .write() - .user_stack_mut() - .expect("No user stack found") - .clone_info_only() - }; - let (user_sp, argv_ptr) = unsafe { - param - .init_info() - .push_at( - // address_space - // .write() - // .user_stack_mut() - // .expect("No user stack found"), - &mut ustack_message, - ) - .expect("Failed to push proc_init_info to user stack") - }; - address_space.write().user_stack = Some(ustack_message); - // debug!("write proc_init_info to user stack done"); regs.a0 = param.init_info().args.len(); @@ -104,8 +29,6 @@ impl Syscall { regs.status.update_fs(FS::Clean); regs.status.update_sum(true); - drop(param); - return Ok(()); } diff --git a/kernel/src/arch/x86_64/process/syscall.rs b/kernel/src/arch/x86_64/process/syscall.rs index d2652beb..a10bd57d 100644 --- a/kernel/src/arch/x86_64/process/syscall.rs +++ b/kernel/src/arch/x86_64/process/syscall.rs @@ -1,99 +1,27 @@ -use alloc::{ffi::CString, string::String, sync::Arc, vec::Vec}; +use alloc::sync::Arc; use system_error::SystemError; use crate::{ arch::{ interrupt::TrapFrame, process::table::{USER_CS, USER_DS}, - CurrentIrqArch, }, - exception::InterruptArch, - mm::ucontext::AddressSpace, + mm::VirtAddr, process::{ - exec::{load_binary_file, ExecParam, ExecParamFlags}, + exec::{BinaryLoaderResult, ExecParam}, ProcessControlBlock, ProcessManager, }, syscall::{user_access::UserBufferWriter, Syscall}, }; impl Syscall { - pub fn do_execve( - path: String, - argv: Vec, - envp: Vec, + pub fn arch_do_execve( regs: &mut TrapFrame, + param: &ExecParam, + load_result: &BinaryLoaderResult, + user_sp: VirtAddr, + argv_ptr: VirtAddr, ) -> Result<(), SystemError> { - // 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。 - let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; - let pcb = ProcessManager::current_pcb(); - // log::debug!( - // "pid: {:?} do_execve: path: {:?}, argv: {:?}, envp: {:?}\n", - // pcb.pid(), - // path, - // argv, - // envp - // ); - - let mut basic_info = pcb.basic_mut(); - // 暂存原本的用户地址空间的引用(因为如果在切换页表之前释放了它,可能会造成内存use after free) - let old_address_space = basic_info.user_vm(); - - // 在pcb中原来的用户地址空间 - unsafe { - basic_info.set_user_vm(None); - } - // 创建新的地址空间并设置为当前地址空间 - let address_space = AddressSpace::new(true).expect("Failed to create new address space"); - unsafe { - basic_info.set_user_vm(Some(address_space.clone())); - } - - // to avoid deadlock - drop(basic_info); - - assert!( - AddressSpace::is_current(&address_space), - "Failed to set address space" - ); - // debug!("Switch to new address space"); - - // 切换到新的用户地址空间 - unsafe { address_space.read().user_mapper.utable.make_current() }; - - drop(old_address_space); - drop(irq_guard); - // debug!("to load binary file"); - let mut param = ExecParam::new(path.as_str(), address_space.clone(), ExecParamFlags::EXEC)?; - - // 加载可执行文件 - let load_result = load_binary_file(&mut param)?; - // debug!("load binary file done"); - // debug!("argv: {:?}, envp: {:?}", argv, envp); - param.init_info_mut().args = argv; - param.init_info_mut().envs = envp; - - // 把proc_init_info写到用户栈上 - let mut ustack_message = unsafe { - address_space - .write() - .user_stack_mut() - .expect("No user stack found") - .clone_info_only() - }; - let (user_sp, argv_ptr) = unsafe { - param - .init_info() - .push_at( - // address_space - // .write() - // .user_stack_mut() - // .expect("No user stack found"), - &mut ustack_message, - ) - .expect("Failed to push proc_init_info to user stack") - }; - address_space.write().user_stack = Some(ustack_message); - // debug!("write proc_init_info to user stack done"); // (兼容旧版libc)把argv的指针写到寄存器内 @@ -114,8 +42,6 @@ impl Syscall { regs.rflags = 0x200; regs.rax = 1; - drop(param); - // debug!("regs: {:?}\n", regs); // crate::debug!( diff --git a/kernel/src/process/syscall.rs b/kernel/src/process/syscall.rs index 9ba37e82..ddcb9620 100644 --- a/kernel/src/process/syscall.rs +++ b/kernel/src/process/syscall.rs @@ -1,24 +1,34 @@ use core::ffi::c_void; -use alloc::{ffi::CString, string::ToString, sync::Arc, vec::Vec}; +use alloc::{ + ffi::CString, + string::{String, ToString}, + sync::Arc, + vec::Vec, +}; use log::error; use system_error::SystemError; use super::{ abi::WaitOption, cred::{Kgid, Kuid}, + exec::{load_binary_file, ExecParam, ExecParamFlags}, exit::kernel_wait4, fork::{CloneFlags, KernelCloneArgs}, resource::{RLimit64, RLimitID, RUsage, RUsageWho}, KernelStack, Pid, ProcessManager, }; use crate::{ - arch::{interrupt::TrapFrame, MMArch}, + arch::{interrupt::TrapFrame, CurrentIrqArch, MMArch}, + exception::InterruptArch, filesystem::{ procfs::procfs_register_pid, vfs::{file::FileDescriptorVec, MAX_PATHLEN}, }, - mm::{ucontext::UserStack, verify_area, MemoryManagementArch, VirtAddr}, + mm::{ + ucontext::{AddressSpace, UserStack}, + verify_area, MemoryManagementArch, VirtAddr, + }, process::ProcessControlBlock, sched::completion::Completion, syscall::{ @@ -139,6 +149,54 @@ impl Syscall { return Ok(()); } + pub fn do_execve( + path: String, + argv: Vec, + envp: Vec, + regs: &mut TrapFrame, + ) -> Result<(), SystemError> { + let address_space = AddressSpace::new(true).expect("Failed to create new address space"); + // debug!("to load binary file"); + let mut param = ExecParam::new(path.as_str(), address_space.clone(), ExecParamFlags::EXEC)?; + let old_vm = do_execve_switch_user_vm(address_space.clone()); + + // 加载可执行文件 + let load_result = load_binary_file(&mut param).inspect_err(|_| { + if let Some(old_vm) = old_vm { + do_execve_switch_user_vm(old_vm); + } + })?; + + // debug!("load binary file done"); + // debug!("argv: {:?}, envp: {:?}", argv, envp); + param.init_info_mut().args = argv; + param.init_info_mut().envs = envp; + + // 把proc_init_info写到用户栈上 + let mut ustack_message = unsafe { + address_space + .write() + .user_stack_mut() + .expect("No user stack found") + .clone_info_only() + }; + let (user_sp, argv_ptr) = unsafe { + param + .init_info() + .push_at( + // address_space + // .write() + // .user_stack_mut() + // .expect("No user stack found"), + &mut ustack_message, + ) + .expect("Failed to push proc_init_info to user stack") + }; + address_space.write().user_stack = Some(ustack_message); + + Self::arch_do_execve(regs, ¶m, &load_result, user_sp, argv_ptr) + } + pub fn wait4( pid: i64, wstatus: *mut i32, @@ -499,3 +557,57 @@ impl Syscall { return Ok(0); } } + +/// 切换用户虚拟内存空间 +/// +/// 该函数用于在执行系统调用 `execve` 时切换用户进程的虚拟内存空间。 +/// +/// # 参数 +/// - `new_vm`: 新的用户地址空间,类型为 `Arc`。 +/// +/// # 返回值 +/// - 返回旧的用户地址空间的引用,类型为 `Option>`。 +/// +/// # 错误处理 +/// 如果地址空间切换失败,函数会触发断言失败,并输出错误信息。 +fn do_execve_switch_user_vm(new_vm: Arc) -> Option> { + // 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。 + let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + let pcb = ProcessManager::current_pcb(); + // log::debug!( + // "pid: {:?} do_execve: path: {:?}, argv: {:?}, envp: {:?}\n", + // pcb.pid(), + // path, + // argv, + // envp + // ); + + let mut basic_info = pcb.basic_mut(); + // 暂存原本的用户地址空间的引用(因为如果在切换页表之前释放了它,可能会造成内存use after free) + let old_address_space = basic_info.user_vm(); + + // 在pcb中原来的用户地址空间 + unsafe { + basic_info.set_user_vm(None); + } + // 创建新的地址空间并设置为当前地址空间 + unsafe { + basic_info.set_user_vm(Some(new_vm.clone())); + } + + // to avoid deadlock + drop(basic_info); + + assert!( + AddressSpace::is_current(&new_vm), + "Failed to set address space" + ); + // debug!("Switch to new address space"); + + // 切换到新的用户地址空间 + unsafe { new_vm.read().user_mapper.utable.make_current() }; + + drop(irq_guard); + + old_address_space +}