Clean up `ProgramToLoad`
This commit is contained in:
parent
2b8ccbf3d2
commit
e2f7b0eb73
|
|
@ -15,10 +15,10 @@ use crate::{
|
|||
},
|
||||
prelude::*,
|
||||
process::{
|
||||
ContextUnshareAdminApi, Credentials, Process, ProgramToLoad,
|
||||
ContextUnshareAdminApi, Credentials, Process,
|
||||
posix_thread::{PosixThread, ThreadLocal, ThreadName, sigkill_other_threads, thread_table},
|
||||
process_vm::{MAX_LEN_STRING_ARG, MAX_NR_STRING_ARGS, unshare_and_renew_vmar},
|
||||
program_loader::elf::ElfLoadInfo,
|
||||
program_loader::{ProgramToLoad, elf::ElfLoadInfo},
|
||||
signal::{
|
||||
HandlePendingSignal, PauseReason, SigStack,
|
||||
constants::{SIGCHLD, SIGKILL},
|
||||
|
|
@ -50,8 +50,10 @@ pub fn do_execve(
|
|||
|
||||
let fs_ref = ctx.thread_local.borrow_fs();
|
||||
let fs_resolver = fs_ref.resolver().read();
|
||||
|
||||
let elf_inode = elf_file.inode();
|
||||
let program_to_load = ProgramToLoad::build_from_inode(elf_inode, &fs_resolver, argv, envp, 1)?;
|
||||
let program_to_load =
|
||||
ProgramToLoad::build_from_inode(elf_inode.clone(), &fs_resolver, argv, envp)?;
|
||||
|
||||
// Ensure no other thread is concurrently performing exit_group or execve.
|
||||
// If such an operation is in progress, return EAGAIN.
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ pub use process::{
|
|||
};
|
||||
pub use process_filter::ProcessFilter;
|
||||
pub use process_vm::ProcessVm;
|
||||
pub use program_loader::{ProgramToLoad, check_executable_inode};
|
||||
pub use rlimit::ResourceType;
|
||||
pub use stats::collect_process_creation_count;
|
||||
pub use term_status::TermStatus;
|
||||
|
|
|
|||
|
|
@ -13,10 +13,11 @@ use crate::{
|
|||
},
|
||||
prelude::*,
|
||||
process::{
|
||||
Credentials, ProgramToLoad, UserNamespace,
|
||||
Credentials, UserNamespace,
|
||||
posix_thread::{PosixThreadBuilder, ThreadName, allocate_posix_tid},
|
||||
process_table,
|
||||
process_vm::new_vmar_and_map,
|
||||
program_loader::ProgramToLoad,
|
||||
rlimit::new_resource_limits_for_init,
|
||||
signal::sig_disposition::SigDispositions,
|
||||
},
|
||||
|
|
@ -109,7 +110,7 @@ fn create_init_task(
|
|||
let elf_load_info = {
|
||||
let fs_resolver = fs.resolver().read();
|
||||
let program_to_load =
|
||||
ProgramToLoad::build_from_inode(elf_path.inode(), &fs_resolver, argv, envp, 1)?;
|
||||
ProgramToLoad::build_from_inode(elf_path.inode().clone(), &fs_resolver, argv, envp)?;
|
||||
let vmar = process.lock_vmar();
|
||||
program_to_load.load_to_vmar(vmar.unwrap(), &fs_resolver)?
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ use crate::{
|
|||
},
|
||||
prelude::*,
|
||||
process::{
|
||||
check_executable_inode,
|
||||
process_vm::{AuxKey, AuxVec},
|
||||
program_loader::check_executable_inode,
|
||||
},
|
||||
vm::{
|
||||
perms::VmPerms,
|
||||
|
|
@ -102,7 +102,7 @@ fn lookup_and_parse_ldso(
|
|||
|
||||
let ldso_elf = {
|
||||
let inode = ldso_file.inode();
|
||||
check_executable_inode(inode)?;
|
||||
check_executable_inode(inode.as_ref())?;
|
||||
|
||||
let mut buf = Box::new([0u8; PAGE_SIZE]);
|
||||
let len = inode.read_bytes_at(0, &mut *buf)?;
|
||||
|
|
|
|||
|
|
@ -4,5 +4,6 @@ mod elf_file;
|
|||
mod load_elf;
|
||||
mod relocate;
|
||||
|
||||
pub use elf_file::ElfHeaders;
|
||||
pub use load_elf::{ElfLoadInfo, load_elf_to_vmar};
|
||||
pub(super) use elf_file::ElfHeaders;
|
||||
pub(in crate::process) use load_elf::ElfLoadInfo;
|
||||
pub(super) use load_elf::load_elf_to_vmar;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
pub mod elf;
|
||||
pub(super) mod elf;
|
||||
mod shebang;
|
||||
|
||||
use self::{
|
||||
|
|
@ -20,7 +20,7 @@ use crate::{
|
|||
///
|
||||
/// This struct encapsulates the ELF file to be executed along with its header data,
|
||||
/// the `argv` and the `envp` which is required for the program execution.
|
||||
pub struct ProgramToLoad {
|
||||
pub(super) struct ProgramToLoad {
|
||||
elf_inode: Arc<dyn Inode>,
|
||||
elf_headers: ElfHeaders,
|
||||
argv: Vec<CString>,
|
||||
|
|
@ -28,50 +28,56 @@ pub struct ProgramToLoad {
|
|||
}
|
||||
|
||||
impl ProgramToLoad {
|
||||
/// Constructs a new `ProgramToLoad` from a file, handling shebang interpretation if needed.
|
||||
///
|
||||
/// About `recursion_limit`: recursion limit is used to limit th recursion depth of shebang executables.
|
||||
/// If the interpreter(the program behind #!) of shebang executable is also a shebang,
|
||||
/// then it will trigger recursion. We will try to setup VMAR for the interpreter.
|
||||
/// I guess for most cases, setting the `recursion_limit` as 1 should be enough.
|
||||
/// because the interpreter is usually an elf binary(e.g., /bin/bash)
|
||||
pub fn build_from_inode(
|
||||
elf_inode: &Arc<dyn Inode>,
|
||||
/// Constructs a new `ProgramToLoad` from an inode and handles shebang interpretation if
|
||||
/// necessary.
|
||||
pub(super) fn build_from_inode(
|
||||
mut elf_inode: Arc<dyn Inode>,
|
||||
fs_resolver: &FsResolver,
|
||||
argv: Vec<CString>,
|
||||
mut argv: Vec<CString>,
|
||||
envp: Vec<CString>,
|
||||
recursion_limit: usize,
|
||||
) -> Result<Self> {
|
||||
let file_first_page = {
|
||||
// Read the first page of file header, which must contain the ELF header.
|
||||
let mut buffer = Box::new([0u8; PAGE_SIZE]);
|
||||
elf_inode.read_bytes_at(0, &mut *buffer)?;
|
||||
buffer
|
||||
};
|
||||
if let Some(mut new_argv) = parse_shebang_line(&*file_first_page)? {
|
||||
if recursion_limit == 0 {
|
||||
check_executable_inode(elf_inode.as_ref())?;
|
||||
|
||||
// A limit to the recursion depth of shebang executables.
|
||||
//
|
||||
// If the interpreter is a shebang, then recursion will be triggered. If it loops, we
|
||||
// should fail. We follow the same limit as Linux.
|
||||
let mut recursive_limit = 5;
|
||||
|
||||
let (file_first_page, len) = loop {
|
||||
// Read the first page of the file, which should contain a shebang or an ELF header.
|
||||
let (file_first_page, len) = {
|
||||
let mut buffer = Box::new([0u8; PAGE_SIZE]);
|
||||
let len = elf_inode.read_bytes_at(0, &mut *buffer)?;
|
||||
(buffer, len)
|
||||
};
|
||||
|
||||
let Some(mut new_argv) = parse_shebang_line(&file_first_page[..len])? else {
|
||||
break (file_first_page, len);
|
||||
};
|
||||
|
||||
if recursive_limit == 0 {
|
||||
return_errno_with_message!(Errno::ELOOP, "the recursieve limit is reached");
|
||||
}
|
||||
new_argv.extend_from_slice(&argv);
|
||||
recursive_limit -= 1;
|
||||
|
||||
let interpreter = {
|
||||
let filename = new_argv[0].to_str()?.to_string();
|
||||
let fs_path = FsPath::try_from(filename.as_str())?;
|
||||
fs_resolver.lookup_inode(&fs_path)?
|
||||
};
|
||||
check_executable_inode(interpreter.inode())?;
|
||||
return Self::build_from_inode(
|
||||
interpreter.inode(),
|
||||
fs_resolver,
|
||||
new_argv,
|
||||
envp,
|
||||
recursion_limit - 1,
|
||||
);
|
||||
}
|
||||
check_executable_inode(interpreter.inode().as_ref())?;
|
||||
|
||||
let elf_headers = ElfHeaders::parse(&*file_first_page)?;
|
||||
// Update the argument list and the executable inode. Then, try again.
|
||||
new_argv.extend(argv);
|
||||
argv = new_argv;
|
||||
elf_inode = interpreter.inode().clone();
|
||||
};
|
||||
|
||||
let elf_headers = ElfHeaders::parse(&file_first_page[..len])?;
|
||||
|
||||
Ok(Self {
|
||||
elf_inode: elf_inode.clone(),
|
||||
elf_inode,
|
||||
elf_headers,
|
||||
argv,
|
||||
envp,
|
||||
|
|
@ -81,7 +87,7 @@ impl ProgramToLoad {
|
|||
/// Loads the executable into the specified virtual memory space.
|
||||
///
|
||||
/// Returns the information about the ELF loading process.
|
||||
pub fn load_to_vmar(self, vmar: &Vmar, fs_resolver: &FsResolver) -> Result<ElfLoadInfo> {
|
||||
pub(super) fn load_to_vmar(self, vmar: &Vmar, fs_resolver: &FsResolver) -> Result<ElfLoadInfo> {
|
||||
let elf_load_info = load_elf_to_vmar(
|
||||
vmar,
|
||||
&self.elf_inode,
|
||||
|
|
@ -95,7 +101,7 @@ impl ProgramToLoad {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_executable_inode(inode: &Arc<dyn Inode>) -> Result<()> {
|
||||
fn check_executable_inode(inode: &dyn Inode) -> Result<()> {
|
||||
if inode.type_().is_directory() {
|
||||
return_errno_with_message!(Errno::EISDIR, "the inode is a directory");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
fs_resolver::{AT_FDCWD, FsPath, PathOrInode},
|
||||
},
|
||||
prelude::*,
|
||||
process::{check_executable_inode, do_execve},
|
||||
process::do_execve,
|
||||
};
|
||||
|
||||
pub fn sys_execve(
|
||||
|
|
@ -74,9 +74,6 @@ fn lookup_executable_file(
|
|||
}
|
||||
};
|
||||
|
||||
let inode = path_or_inode.inode();
|
||||
check_executable_inode(inode)?;
|
||||
|
||||
Ok(path_or_inode)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue