Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 8 additions & 85 deletions kernel/src/arch/riscv64/process/syscall.rs
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -104,8 +29,6 @@ impl Syscall {
regs.status.update_fs(FS::Clean);
regs.status.update_sum(true);

drop(param);

return Ok(());
}

Expand Down
90 changes: 8 additions & 82 deletions kernel/src/arch/x86_64/process/syscall.rs
Original file line number Diff line number Diff line change
@@ -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的指针写到寄存器内
Expand All @@ -114,8 +42,6 @@ impl Syscall {
regs.rflags = 0x200;
regs.rax = 1;

drop(param);

// debug!("regs: {:?}\n", regs);

// crate::debug!(
Expand Down
118 changes: 115 additions & 3 deletions kernel/src/process/syscall.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand Down Expand Up @@ -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)?;
fslongjin marked this conversation as resolved.
Show resolved Hide resolved
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,
Expand Down Expand Up @@ -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