Explorar el Código

fix: 修复了do execve 加载程序失败时,没能正确返回错误码给用户态的问题 (#1042)

* fix: 修复了do execve 加载程序失败时,没能正确返回错误码给用户态的问题
LoGin hace 4 meses
padre
commit
0f094e50de

+ 8 - 85
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<CString>,
-        envp: Vec<CString>,
+    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(());
     }
 

+ 8 - 82
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<CString>,
-        envp: Vec<CString>,
+    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!(

+ 115 - 3
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<CString>,
+        envp: Vec<CString>,
+        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, &param, &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<AddressSpace>`。
+///
+/// # 返回值
+/// - 返回旧的用户地址空间的引用,类型为 `Option<Arc<AddressSpace>>`。
+///
+/// # 错误处理
+/// 如果地址空间切换失败,函数会触发断言失败,并输出错误信息。
+fn do_execve_switch_user_vm(new_vm: Arc<AddressSpace>) -> Option<Arc<AddressSpace>> {
+    // 关中断,防止在设置地址空间的时候,发生中断,然后进调度器,出现错误。
+    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
+}