GnoCiYeH 865f4ba4cd
修改shell执行exec时传参错误问题 (#399)
* 修改shell执行exec时传参错误问题
2023-10-09 01:10:14 +08:00

291 lines
8.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use core::{fmt::Debug, ptr::null};
use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
use crate::{
driver::base::block::SeekFrom,
filesystem::vfs::{
file::{File, FileMode},
ROOT_INODE,
},
libs::elf::ELF_LOADER,
mm::{
ucontext::{AddressSpace, UserStack},
VirtAddr,
},
syscall::SystemError,
};
/// 系统支持的所有二进制文件加载器的列表
const BINARY_LOADERS: [&'static dyn BinaryLoader; 1] = [&ELF_LOADER];
pub trait BinaryLoader: 'static + Debug {
/// 检查二进制文件是否为当前加载器支持的格式
fn probe(self: &'static Self, param: &ExecParam, buf: &[u8]) -> Result<(), ExecError>;
fn load(
self: &'static Self,
param: &mut ExecParam,
head_buf: &[u8],
) -> Result<BinaryLoaderResult, ExecError>;
}
/// 二进制文件加载结果
#[derive(Debug)]
pub struct BinaryLoaderResult {
/// 程序入口地址
entry_point: VirtAddr,
}
impl BinaryLoaderResult {
pub fn new(entry_point: VirtAddr) -> Self {
Self { entry_point }
}
pub fn entry_point(&self) -> VirtAddr {
self.entry_point
}
}
#[allow(dead_code)]
#[derive(Debug)]
pub enum ExecError {
/// 二进制文件不可执行
NotExecutable,
/// 二进制文件不是当前架构的
WrongArchitecture,
/// 访问权限不足
PermissionDenied,
/// 不支持的操作
NotSupported,
/// 解析文件本身的时候出现错误(比如一些字段本身不合法)
ParseError,
/// 内存不足
OutOfMemory,
/// 参数错误
InvalidParemeter,
/// 无效的地址
BadAddress(Option<VirtAddr>),
Other(String),
}
impl Into<SystemError> for ExecError {
fn into(self) -> SystemError {
match self {
ExecError::NotExecutable => SystemError::ENOEXEC,
ExecError::WrongArchitecture => SystemError::EOPNOTSUPP_OR_ENOTSUP,
ExecError::PermissionDenied => SystemError::EACCES,
ExecError::NotSupported => SystemError::EOPNOTSUPP_OR_ENOTSUP,
ExecError::ParseError => SystemError::ENOEXEC,
ExecError::OutOfMemory => SystemError::ENOMEM,
ExecError::InvalidParemeter => SystemError::EINVAL,
ExecError::BadAddress(_addr) => SystemError::EFAULT,
ExecError::Other(_msg) => SystemError::ENOEXEC,
}
}
}
bitflags! {
pub struct ExecParamFlags: u32 {
// 是否以可执行文件的形式加载
const EXEC = 1 << 0;
}
}
#[derive(Debug)]
pub struct ExecParam<'a> {
file_path: &'a str,
file: Option<File>,
vm: Arc<AddressSpace>,
/// 一些标志位
flags: ExecParamFlags,
/// 用来初始化进程的一些信息。这些信息由二进制加载器和exec机制来共同填充
init_info: ProcInitInfo,
}
#[derive(Debug, Eq, PartialEq)]
pub enum ExecLoadMode {
/// 以可执行文件的形式加载
Exec,
/// 以动态链接库的形式加载
DSO,
}
#[allow(dead_code)]
impl<'a> ExecParam<'a> {
pub fn new(file_path: &'a str, vm: Arc<AddressSpace>, flags: ExecParamFlags) -> Self {
Self {
file_path,
file: None,
vm,
flags,
init_info: ProcInitInfo::new(),
}
}
pub fn file_path(&self) -> &'a str {
self.file_path
}
pub fn vm(&self) -> &Arc<AddressSpace> {
&self.vm
}
pub fn flags(&self) -> &ExecParamFlags {
&self.flags
}
pub fn init_info(&self) -> &ProcInitInfo {
&self.init_info
}
pub fn init_info_mut(&mut self) -> &mut ProcInitInfo {
&mut self.init_info
}
/// 获取加载模式
pub fn load_mode(&self) -> ExecLoadMode {
if self.flags.contains(ExecParamFlags::EXEC) {
ExecLoadMode::Exec
} else {
ExecLoadMode::DSO
}
}
pub fn file_mut(&mut self) -> &mut File {
self.file.as_mut().unwrap()
}
}
/// ## 加载二进制文件
pub fn load_binary_file(param: &mut ExecParam) -> Result<BinaryLoaderResult, SystemError> {
let inode = ROOT_INODE().lookup(param.file_path)?;
// 读取文件头部,用于判断文件类型
let file = File::new(inode, FileMode::O_RDONLY)?;
param.file = Some(file);
let mut head_buf = [0u8; 512];
param.file_mut().lseek(SeekFrom::SeekSet(0))?;
let _bytes = param.file_mut().read(512, &mut head_buf)?;
// kdebug!("load_binary_file: read {} bytes", _bytes);
let mut loader = None;
for bl in BINARY_LOADERS.iter() {
let probe_result = bl.probe(param, &head_buf);
if probe_result.is_ok() {
loader = Some(bl);
break;
}
}
// kdebug!("load_binary_file: loader: {:?}", loader);
if loader.is_none() {
return Err(SystemError::ENOEXEC);
}
let loader: &&dyn BinaryLoader = loader.unwrap();
assert!(param.vm().is_current());
// kdebug!("load_binary_file: to load with param: {:?}", param);
let result: BinaryLoaderResult = loader
.load(param, &head_buf)
.unwrap_or_else(|e| panic!("load_binary_file failed: error: {e:?}, param: {param:?}"));
// kdebug!("load_binary_file: load success");
return Ok(result);
}
/// 程序初始化信息,这些信息会被压入用户栈中
#[derive(Debug)]
pub struct ProcInitInfo {
pub proc_name: String,
pub args: Vec<String>,
pub envs: Vec<String>,
pub auxv: BTreeMap<u8, usize>,
}
impl ProcInitInfo {
pub fn new() -> Self {
Self {
proc_name: String::new(),
args: Vec::new(),
envs: Vec::new(),
auxv: BTreeMap::new(),
}
}
/// 把程序初始化信息压入用户栈中
/// 这个函数会把参数、环境变量、auxv等信息压入用户栈中
///
/// ## 返回值
///
/// 返回值是一个元组第一个元素是最终的用户栈顶地址第二个元素是环境变量pointer数组的起始地址
pub unsafe fn push_at(
&self,
ustack: &mut UserStack,
) -> Result<(VirtAddr, VirtAddr), SystemError> {
// 先把程序的名称压入栈中
self.push_str(ustack, &self.proc_name)?;
// 然后把环境变量压入栈中
let envps = self
.envs
.iter()
.map(|s| {
self.push_str(ustack, s.as_str()).expect("push_str failed");
ustack.sp()
})
.collect::<Vec<_>>();
// 然后把参数压入栈中
let argps = self
.args
.iter()
.map(|s| {
self.push_str(ustack, s.as_str()).expect("push_str failed");
ustack.sp()
})
.collect::<Vec<_>>();
// 压入auxv
self.push_slice(ustack, &[null::<u8>(), null::<u8>()])?;
for (&k, &v) in self.auxv.iter() {
self.push_slice(ustack, &[k as usize, v])?;
}
// 把环境变量指针压入栈中
self.push_slice(ustack, &[null::<u8>()])?;
self.push_slice(ustack, envps.as_slice())?;
// 把参数指针压入栈中
self.push_slice(ustack, &[null::<u8>()])?;
self.push_slice(ustack, argps.as_slice())?;
let argv_ptr = ustack.sp();
// 把argc压入栈中
self.push_slice(ustack, &[self.args.len()])?;
return Ok((ustack.sp(), argv_ptr));
}
fn push_slice<T: Copy>(&self, ustack: &mut UserStack, slice: &[T]) -> Result<(), SystemError> {
let mut sp = ustack.sp();
sp -= slice.len() * core::mem::size_of::<T>();
sp -= sp.data() % core::mem::align_of::<T>();
unsafe { core::slice::from_raw_parts_mut(sp.data() as *mut T, slice.len()) }
.copy_from_slice(slice);
unsafe {
ustack.set_sp(sp);
}
return Ok(());
}
fn push_str(&self, ustack: &mut UserStack, s: &str) -> Result<(), SystemError> {
self.push_slice(ustack, &[b'\0'])?;
self.push_slice(ustack, s.as_bytes())?;
return Ok(());
}
}