Add syscall execveat

This commit is contained in:
Jianfeng Jiang 2023-06-13 10:13:00 +08:00 committed by Tate, Hongliang Tian
parent 5815f248fc
commit dcfbeb270d
5 changed files with 117 additions and 35 deletions

View File

@ -41,6 +41,10 @@ impl InodeType {
_ => false,
}
}
pub fn is_reguler_file(&self) -> bool {
*self == InodeType::File
}
}
impl From<DeviceType> for InodeType {

View File

@ -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();

View File

@ -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)
}

View File

@ -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(

View File

@ -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");