mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-15 16:26:48 +00:00
Add syscall execveat
This commit is contained in:
parent
5815f248fc
commit
dcfbeb270d
@ -41,6 +41,10 @@ impl InodeType {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_reguler_file(&self) -> bool {
|
||||
*self == InodeType::File
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DeviceType> for InodeType {
|
||||
|
@ -2,7 +2,7 @@ use jinux_frame::{cpu::UserContext, user::UserSpace};
|
||||
use jinux_rights::Full;
|
||||
|
||||
use crate::{
|
||||
fs::fs_resolver::FsResolver,
|
||||
fs::fs_resolver::{FsPath, FsResolver, AT_FDCWD},
|
||||
prelude::*,
|
||||
process::{program_loader::load_program_to_root_vmar, Process},
|
||||
thread::{Thread, Tid},
|
||||
@ -34,14 +34,12 @@ impl PosixThreadExt for Thread {
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
) -> Result<Arc<Self>> {
|
||||
let (_, elf_load_info) = load_program_to_root_vmar(
|
||||
root_vmar,
|
||||
executable_path.to_string(),
|
||||
argv,
|
||||
envp,
|
||||
fs_resolver,
|
||||
1,
|
||||
)?;
|
||||
let elf_file = {
|
||||
let fs_path = FsPath::new(AT_FDCWD, executable_path)?;
|
||||
fs_resolver.lookup(&fs_path)?
|
||||
};
|
||||
let elf_load_info =
|
||||
load_program_to_root_vmar(root_vmar, elf_file, argv, envp, fs_resolver, 1)?;
|
||||
|
||||
let vm_space = root_vmar.vm_space().clone();
|
||||
let mut cpu_ctx = UserContext::default();
|
||||
|
@ -2,6 +2,7 @@ pub mod elf;
|
||||
mod shebang;
|
||||
|
||||
use crate::fs::fs_resolver::{FsPath, FsResolver, AT_FDCWD};
|
||||
use crate::fs::utils::Dentry;
|
||||
use crate::prelude::*;
|
||||
use crate::vm::vmar::Vmar;
|
||||
use jinux_rights::Full;
|
||||
@ -18,21 +19,12 @@ use self::shebang::parse_shebang_line;
|
||||
/// because the interpreter is usually an elf binary(e.g., /bin/bash)
|
||||
pub fn load_program_to_root_vmar(
|
||||
root_vmar: &Vmar<Full>,
|
||||
executable_path: String,
|
||||
elf_file: Arc<Dentry>,
|
||||
argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
fs_resolver: &FsResolver,
|
||||
recursion_limit: usize,
|
||||
) -> Result<(String, ElfLoadInfo)> {
|
||||
// Temporary use because fs_resolver cannot deal with procfs now.
|
||||
// FIXME: removes this when procfs is ready.
|
||||
let executable_path = if &executable_path == "/proc/self/exe" {
|
||||
current!().executable_path().read().clone()
|
||||
} else {
|
||||
executable_path
|
||||
};
|
||||
let fs_path = FsPath::new(AT_FDCWD, &executable_path)?;
|
||||
let elf_file = fs_resolver.lookup(&fs_path)?;
|
||||
) -> Result<ElfLoadInfo> {
|
||||
let abs_path = elf_file.abs_path();
|
||||
let vnode = elf_file.vnode();
|
||||
let file_header = {
|
||||
@ -46,7 +38,11 @@ pub fn load_program_to_root_vmar(
|
||||
return_errno_with_message!(Errno::EINVAL, "the recursieve limit is reached");
|
||||
}
|
||||
new_argv.extend_from_slice(&argv);
|
||||
let interpreter = new_argv[0].to_str()?.to_string();
|
||||
let interpreter = {
|
||||
let filename = new_argv[0].to_str()?.to_string();
|
||||
let fs_path = FsPath::new(AT_FDCWD, &filename)?;
|
||||
fs_resolver.lookup(&fs_path)?
|
||||
};
|
||||
return load_program_to_root_vmar(
|
||||
root_vmar,
|
||||
interpreter,
|
||||
@ -56,9 +52,7 @@ pub fn load_program_to_root_vmar(
|
||||
recursion_limit - 1,
|
||||
);
|
||||
}
|
||||
|
||||
debug!("load executable, path = {}", executable_path);
|
||||
let elf_load_info =
|
||||
load_elf_to_root_vmar(root_vmar, &*file_header, elf_file, fs_resolver, argv, envp)?;
|
||||
Ok((abs_path, elf_load_info))
|
||||
Ok(elf_load_info)
|
||||
}
|
||||
|
@ -1,12 +1,16 @@
|
||||
use jinux_frame::cpu::UserContext;
|
||||
|
||||
use super::{constants::*, SyscallReturn};
|
||||
use crate::fs::file_table::FileDescripter;
|
||||
use crate::fs::fs_resolver::{FsPath, AT_FDCWD};
|
||||
use crate::fs::utils::{Dentry, InodeType};
|
||||
use crate::log_syscall_entry;
|
||||
use crate::prelude::*;
|
||||
use crate::process::posix_thread::name::ThreadName;
|
||||
use crate::process::posix_thread::posix_thread_ext::PosixThreadExt;
|
||||
use crate::process::program_loader::load_program_to_root_vmar;
|
||||
use crate::syscall::{SYS_EXECVE, SYS_EXECVEAT};
|
||||
use crate::util::{read_cstring_from_user, read_val_from_user};
|
||||
use crate::{prelude::*, syscall::SYS_EXECVE};
|
||||
|
||||
pub fn sys_execve(
|
||||
filename_ptr: Vaddr,
|
||||
@ -15,9 +19,78 @@ pub fn sys_execve(
|
||||
context: &mut UserContext,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_EXECVE);
|
||||
let executable_path = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?;
|
||||
let executable_path = executable_path.into_string().unwrap();
|
||||
let executable_path = read_filename(filename_ptr)?;
|
||||
let elf_file = {
|
||||
let current = current!();
|
||||
let fs_resolver = current.fs().read();
|
||||
let fs_path = FsPath::new(AT_FDCWD, &executable_path)?;
|
||||
fs_resolver.lookup(&fs_path)?
|
||||
};
|
||||
do_execve(elf_file, argv_ptr_ptr, envp_ptr_ptr, context)?;
|
||||
Ok(SyscallReturn::NoReturn)
|
||||
}
|
||||
|
||||
pub fn sys_execveat(
|
||||
dfd: FileDescripter,
|
||||
filename_ptr: Vaddr,
|
||||
argv_ptr_ptr: Vaddr,
|
||||
envp_ptr_ptr: Vaddr,
|
||||
flags: u32,
|
||||
context: &mut UserContext,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_EXECVEAT);
|
||||
let flags = OpenFlags::from_bits_truncate(flags);
|
||||
let filename = read_filename(filename_ptr)?;
|
||||
let elf_file = lookup_executable_file(dfd, filename, flags)?;
|
||||
check_file_type_and_permission(&elf_file)?;
|
||||
do_execve(elf_file, argv_ptr_ptr, envp_ptr_ptr, context)?;
|
||||
Ok(SyscallReturn::NoReturn)
|
||||
}
|
||||
|
||||
fn lookup_executable_file(
|
||||
dfd: FileDescripter,
|
||||
filename: String,
|
||||
flags: OpenFlags,
|
||||
) -> Result<Arc<Dentry>> {
|
||||
let current = current!();
|
||||
let fs_resolver = current.fs().read();
|
||||
let dentry = if flags.contains(OpenFlags::AT_EMPTY_PATH) && filename.len() == 0 {
|
||||
fs_resolver.lookup_from_fd(dfd)
|
||||
} else {
|
||||
let fs_path = FsPath::new(dfd, &filename)?;
|
||||
if flags.contains(OpenFlags::AT_SYMLINK_NOFOLLOW) {
|
||||
let dentry = fs_resolver.lookup_no_follow(&fs_path)?;
|
||||
if dentry.inode_type() == InodeType::SymLink {
|
||||
return_errno_with_message!(Errno::ELOOP, "the executable file is a symlink");
|
||||
}
|
||||
Ok(dentry)
|
||||
} else {
|
||||
fs_resolver.lookup(&fs_path)
|
||||
}
|
||||
}?;
|
||||
check_file_type_and_permission(&dentry)?;
|
||||
Ok(dentry)
|
||||
}
|
||||
|
||||
fn check_file_type_and_permission(dentry: &Arc<Dentry>) -> Result<()> {
|
||||
if !dentry.inode_type().is_reguler_file() {
|
||||
return_errno_with_message!(Errno::EACCES, "the dentry is not a regular file");
|
||||
}
|
||||
|
||||
if !dentry.inode_mode().is_executable() {
|
||||
return_errno_with_message!(Errno::EACCES, "the dentry is not executable");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn do_execve(
|
||||
elf_file: Arc<Dentry>,
|
||||
argv_ptr_ptr: Vaddr,
|
||||
envp_ptr_ptr: Vaddr,
|
||||
context: &mut UserContext,
|
||||
) -> Result<()> {
|
||||
let executable_path = elf_file.abs_path();
|
||||
let argv = read_cstring_vec(argv_ptr_ptr, MAX_ARGV_NUMBER, MAX_ARG_LEN)?;
|
||||
let envp = read_cstring_vec(envp_ptr_ptr, MAX_ENVP_NUMBER, MAX_ENV_LEN)?;
|
||||
debug!(
|
||||
@ -27,9 +100,8 @@ pub fn sys_execve(
|
||||
// FIXME: should we set thread name in execve?
|
||||
let current_thread = current_thread!();
|
||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||
let mut thread_name = posix_thread.thread_name().lock();
|
||||
let new_thread_name = ThreadName::new_from_executable_path(&executable_path)?;
|
||||
*thread_name = Some(new_thread_name);
|
||||
*posix_thread.thread_name().lock() =
|
||||
Some(ThreadName::new_from_executable_path(&executable_path)?);
|
||||
// clear ctid
|
||||
// FIXME: should we clear ctid when execve?
|
||||
*posix_thread.clear_child_tid().lock() = 0;
|
||||
@ -42,11 +114,10 @@ pub fn sys_execve(
|
||||
// load elf content to new vm space
|
||||
let fs_resolver = &*current.fs().read();
|
||||
debug!("load program to root vmar");
|
||||
let (new_executable_path, elf_load_info) =
|
||||
load_program_to_root_vmar(root_vmar, executable_path, argv, envp, fs_resolver, 1)?;
|
||||
let elf_load_info = load_program_to_root_vmar(root_vmar, elf_file, argv, envp, fs_resolver, 1)?;
|
||||
debug!("load elf in execve succeeds");
|
||||
// set executable path
|
||||
*current.executable_path().write() = new_executable_path;
|
||||
*current.executable_path().write() = executable_path;
|
||||
// set signal disposition to default
|
||||
current.sig_dispositions().lock().inherit();
|
||||
// set cpu context to default
|
||||
@ -60,7 +131,19 @@ pub fn sys_execve(
|
||||
// set new user stack top
|
||||
context.set_rsp(elf_load_info.user_stack_top() as _);
|
||||
debug!("user stack top: 0x{:x}", elf_load_info.user_stack_top());
|
||||
Ok(SyscallReturn::NoReturn)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
struct OpenFlags: u32 {
|
||||
const AT_EMPTY_PATH = 0x1000;
|
||||
const AT_SYMLINK_NOFOLLOW = 0x100;
|
||||
}
|
||||
}
|
||||
|
||||
fn read_filename(filename_ptr: Vaddr) -> Result<String> {
|
||||
let filename = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?;
|
||||
Ok(filename.into_string().unwrap())
|
||||
}
|
||||
|
||||
fn read_cstring_vec(
|
||||
|
@ -74,6 +74,7 @@ use jinux_frame::cpu::UserContext;
|
||||
use self::accept::sys_accept;
|
||||
use self::bind::sys_bind;
|
||||
use self::connect::sys_connect;
|
||||
use self::execve::sys_execveat;
|
||||
use self::getpeername::sys_getpeername;
|
||||
use self::getrandom::sys_getrandom;
|
||||
use self::getsockname::sys_getsockname;
|
||||
@ -298,7 +299,8 @@ define_syscall_nums!(
|
||||
SYS_EPOLL_CREATE1 = 291,
|
||||
SYS_PIPE2 = 293,
|
||||
SYS_PRLIMIT64 = 302,
|
||||
SYS_GETRANDOM = 318
|
||||
SYS_GETRANDOM = 318,
|
||||
SYS_EXECVEAT = 322
|
||||
);
|
||||
|
||||
pub struct SyscallArgument {
|
||||
@ -457,6 +459,7 @@ pub fn syscall_dispatch(
|
||||
SYS_PIPE2 => syscall_handler!(2, sys_pipe2, args),
|
||||
SYS_PRLIMIT64 => syscall_handler!(4, sys_prlimit64, args),
|
||||
SYS_GETRANDOM => syscall_handler!(3, sys_getrandom, args),
|
||||
SYS_EXECVEAT => syscall_handler!(5, sys_execveat, args, context),
|
||||
_ => {
|
||||
error!("Unimplemented syscall number: {}", syscall_number);
|
||||
return_errno_with_message!(Errno::ENOSYS, "Syscall was unimplemented");
|
||||
|
Loading…
x
Reference in New Issue
Block a user