mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +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 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(());
|
||||
}
|
||||
|
||||
|
@ -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!(
|
||||
|
@ -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, ¶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<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