mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 22:36:48 +00:00
fix: 修复了do execve 加载程序失败时,没能正确返回错误码给用户态的问题 (#1042)
* fix: 修复了do execve 加载程序失败时,没能正确返回错误码给用户态的问题
This commit is contained in:
parent
7c28051e8c
commit
0f094e50de
@ -1,96 +1,21 @@
|
|||||||
use alloc::{ffi::CString, string::String, vec::Vec};
|
|
||||||
use riscv::register::sstatus::{FS, SPP};
|
use riscv::register::sstatus::{FS, SPP};
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{interrupt::TrapFrame, CurrentIrqArch},
|
arch::interrupt::TrapFrame,
|
||||||
exception::InterruptArch,
|
mm::VirtAddr,
|
||||||
mm::ucontext::AddressSpace,
|
process::exec::{BinaryLoaderResult, ExecParam},
|
||||||
process::{
|
|
||||||
exec::{load_binary_file, ExecParam, ExecParamFlags},
|
|
||||||
ProcessManager,
|
|
||||||
},
|
|
||||||
syscall::Syscall,
|
syscall::Syscall,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Syscall {
|
impl Syscall {
|
||||||
pub fn do_execve(
|
pub fn arch_do_execve(
|
||||||
path: String,
|
|
||||||
argv: Vec<CString>,
|
|
||||||
envp: Vec<CString>,
|
|
||||||
regs: &mut TrapFrame,
|
regs: &mut TrapFrame,
|
||||||
|
param: &ExecParam,
|
||||||
|
load_result: &BinaryLoaderResult,
|
||||||
|
user_sp: VirtAddr,
|
||||||
|
argv_ptr: VirtAddr,
|
||||||
) -> Result<(), SystemError> {
|
) -> 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");
|
// debug!("write proc_init_info to user stack done");
|
||||||
|
|
||||||
regs.a0 = param.init_info().args.len();
|
regs.a0 = param.init_info().args.len();
|
||||||
@ -104,8 +29,6 @@ impl Syscall {
|
|||||||
regs.status.update_fs(FS::Clean);
|
regs.status.update_fs(FS::Clean);
|
||||||
regs.status.update_sum(true);
|
regs.status.update_sum(true);
|
||||||
|
|
||||||
drop(param);
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,99 +1,27 @@
|
|||||||
use alloc::{ffi::CString, string::String, sync::Arc, vec::Vec};
|
use alloc::sync::Arc;
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{
|
arch::{
|
||||||
interrupt::TrapFrame,
|
interrupt::TrapFrame,
|
||||||
process::table::{USER_CS, USER_DS},
|
process::table::{USER_CS, USER_DS},
|
||||||
CurrentIrqArch,
|
|
||||||
},
|
},
|
||||||
exception::InterruptArch,
|
mm::VirtAddr,
|
||||||
mm::ucontext::AddressSpace,
|
|
||||||
process::{
|
process::{
|
||||||
exec::{load_binary_file, ExecParam, ExecParamFlags},
|
exec::{BinaryLoaderResult, ExecParam},
|
||||||
ProcessControlBlock, ProcessManager,
|
ProcessControlBlock, ProcessManager,
|
||||||
},
|
},
|
||||||
syscall::{user_access::UserBufferWriter, Syscall},
|
syscall::{user_access::UserBufferWriter, Syscall},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Syscall {
|
impl Syscall {
|
||||||
pub fn do_execve(
|
pub fn arch_do_execve(
|
||||||
path: String,
|
|
||||||
argv: Vec<CString>,
|
|
||||||
envp: Vec<CString>,
|
|
||||||
regs: &mut TrapFrame,
|
regs: &mut TrapFrame,
|
||||||
|
param: &ExecParam,
|
||||||
|
load_result: &BinaryLoaderResult,
|
||||||
|
user_sp: VirtAddr,
|
||||||
|
argv_ptr: VirtAddr,
|
||||||
) -> Result<(), SystemError> {
|
) -> 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");
|
// debug!("write proc_init_info to user stack done");
|
||||||
|
|
||||||
// (兼容旧版libc)把argv的指针写到寄存器内
|
// (兼容旧版libc)把argv的指针写到寄存器内
|
||||||
@ -114,8 +42,6 @@ impl Syscall {
|
|||||||
regs.rflags = 0x200;
|
regs.rflags = 0x200;
|
||||||
regs.rax = 1;
|
regs.rax = 1;
|
||||||
|
|
||||||
drop(param);
|
|
||||||
|
|
||||||
// debug!("regs: {:?}\n", regs);
|
// debug!("regs: {:?}\n", regs);
|
||||||
|
|
||||||
// crate::debug!(
|
// crate::debug!(
|
||||||
|
@ -1,24 +1,34 @@
|
|||||||
use core::ffi::c_void;
|
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 log::error;
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
abi::WaitOption,
|
abi::WaitOption,
|
||||||
cred::{Kgid, Kuid},
|
cred::{Kgid, Kuid},
|
||||||
|
exec::{load_binary_file, ExecParam, ExecParamFlags},
|
||||||
exit::kernel_wait4,
|
exit::kernel_wait4,
|
||||||
fork::{CloneFlags, KernelCloneArgs},
|
fork::{CloneFlags, KernelCloneArgs},
|
||||||
resource::{RLimit64, RLimitID, RUsage, RUsageWho},
|
resource::{RLimit64, RLimitID, RUsage, RUsageWho},
|
||||||
KernelStack, Pid, ProcessManager,
|
KernelStack, Pid, ProcessManager,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{interrupt::TrapFrame, MMArch},
|
arch::{interrupt::TrapFrame, CurrentIrqArch, MMArch},
|
||||||
|
exception::InterruptArch,
|
||||||
filesystem::{
|
filesystem::{
|
||||||
procfs::procfs_register_pid,
|
procfs::procfs_register_pid,
|
||||||
vfs::{file::FileDescriptorVec, MAX_PATHLEN},
|
vfs::{file::FileDescriptorVec, MAX_PATHLEN},
|
||||||
},
|
},
|
||||||
mm::{ucontext::UserStack, verify_area, MemoryManagementArch, VirtAddr},
|
mm::{
|
||||||
|
ucontext::{AddressSpace, UserStack},
|
||||||
|
verify_area, MemoryManagementArch, VirtAddr,
|
||||||
|
},
|
||||||
process::ProcessControlBlock,
|
process::ProcessControlBlock,
|
||||||
sched::completion::Completion,
|
sched::completion::Completion,
|
||||||
syscall::{
|
syscall::{
|
||||||
@ -139,6 +149,54 @@ impl Syscall {
|
|||||||
return Ok(());
|
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, ¶m, &load_result, user_sp, argv_ptr)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn wait4(
|
pub fn wait4(
|
||||||
pid: i64,
|
pid: i64,
|
||||||
wstatus: *mut i32,
|
wstatus: *mut i32,
|
||||||
@ -499,3 +557,57 @@ impl Syscall {
|
|||||||
return Ok(0);
|
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
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user