From 71632a51b573dbc4a5175e8216854e4b1624ce6c Mon Sep 17 00:00:00 2001 From: Wang Siyuan Date: Wed, 22 Oct 2025 16:21:14 +0000 Subject: [PATCH] `ProgramToLoad` only needs a `elf_inode: Arc` instead of a `Path` --- kernel/src/process/execve.rs | 46 +++++++++---------- kernel/src/process/mod.rs | 2 +- kernel/src/process/process/init_proc.rs | 2 +- .../process/program_loader/elf/elf_file.rs | 9 ++-- .../process/program_loader/elf/load_elf.rs | 32 +++++++------ kernel/src/process/program_loader/mod.rs | 44 ++++++++---------- kernel/src/syscall/execve.rs | 4 +- 7 files changed, 69 insertions(+), 70 deletions(-) diff --git a/kernel/src/process/execve.rs b/kernel/src/process/execve.rs index 1cbb94eea..9d2e4a91e 100644 --- a/kernel/src/process/execve.rs +++ b/kernel/src/process/execve.rs @@ -8,7 +8,7 @@ use ostd::{ }; use crate::{ - fs::{fs_resolver::FsResolver, path::Path}, + fs::{fs_resolver::FsResolver, path::Path, utils::Inode}, prelude::*, process::{ posix_thread::{sigkill_other_threads, thread_table, PosixThread, ThreadLocal, ThreadName}, @@ -46,8 +46,8 @@ pub fn do_execve( let fs_ref = ctx.thread_local.borrow_fs(); let fs_resolver = fs_ref.resolver().read(); - let program_to_load = - ProgramToLoad::build_from_file(elf_file.clone(), &fs_resolver, argv, envp, 1)?; + let elf_inode = elf_file.inode(); + let program_to_load = ProgramToLoad::build_from_inode(elf_inode, &fs_resolver, argv, envp, 1)?; // Ensure no other thread is concurrently performing exit_group or execve. // If such an operation is in progress, return EAGAIN. @@ -152,7 +152,7 @@ fn do_execve_no_return( set_cpu_context(thread_local, user_context, &elf_load_info); // Apply file-capability changes. - apply_caps_from_exec(process, posix_thread, elf_file)?; + apply_caps_from_exec(process, posix_thread, elf_file.inode())?; // If this was a vfork child, reset vfork-specific state. reset_vfork_child(process); @@ -230,62 +230,62 @@ fn set_cpu_context( debug!("user stack top: 0x{:x}", elf_load_info.user_stack_top); } -/// Sets the UID and GID in the credentials according to the ELF file. +/// Sets the UID and GID in the credentials according to the ELF inode. /// /// The capabilities will be updated accordingly. fn apply_caps_from_exec( process: &Process, posix_thread: &PosixThread, - elf_file: &Path, + elf_inode: &Arc, ) -> Result<()> { - // FIXME: We need to recalculate the capabilities during execve even the executable file + // FIXME: We need to recalculate the capabilities during execve even the executable inode // does not have setuid/setgid bit. let credentials = posix_thread.credentials_mut(); - set_uid_from_elf(process, &credentials, elf_file)?; - set_gid_from_elf(process, &credentials, elf_file)?; + set_uid_from_elf(process, &credentials, elf_inode)?; + set_gid_from_elf(process, &credentials, elf_inode)?; credentials.set_keep_capabilities(false)?; Ok(()) } -/// Sets the UID in the credentials according to the ELF file. +/// Sets the UID in the credentials according to the ELF inode. /// -/// If the ELF file has the `set_uid` bit, the effective UID is set to the same value as the ELF -/// file's UID. +/// If the ELF inode has the `set_uid` bit, the effective UID is set to the same value as the ELF +/// inode's UID. fn set_uid_from_elf( current: &Process, credentials: &Credentials, - elf_file: &Path, + elf_inode: &Arc, ) -> Result<()> { - if elf_file.mode()?.has_set_uid() { - let uid = elf_file.owner()?; + if elf_inode.mode()?.has_set_uid() { + let uid = elf_inode.owner()?; credentials.set_euid(uid); current.clear_parent_death_signal(); } - // No matter whether the ELF file has `set_uid` bit, SUID should be reset. + // No matter whether the ELF inode has `set_uid` bit, SUID should be reset. credentials.reset_suid(); Ok(()) } -/// Sets the GID in the credentials according to the ELF file. +/// Sets the GID in the credentials according to the ELF inode. /// -/// If the ELF file has the `set_gid` bit, the effective GID is set to the same value as the ELF -/// file's GID. +/// If the ELF inode has the `set_gid` bit, the effective GID is set to the same value as the ELF +/// inode's GID. fn set_gid_from_elf( current: &Process, credentials: &Credentials, - elf_file: &Path, + elf_inode: &Arc, ) -> Result<()> { - if elf_file.mode()?.has_set_gid() { - let gid = elf_file.group()?; + if elf_inode.mode()?.has_set_gid() { + let gid = elf_inode.group()?; credentials.set_egid(gid); current.clear_parent_death_signal(); } - // No matter whether the ELF file has `set_gid` bit, SGID should be reset. + // No matter whether the ELF inode has `set_gid` bit, SGID should be reset. credentials.reset_sgid(); Ok(()) } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 2d204b0ee..4ee8f76c8 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -39,7 +39,7 @@ pub use process::{ }; pub use process_filter::ProcessFilter; pub use process_vm::ProcessVm; -pub use program_loader::{check_executable_file, ProgramToLoad}; +pub use program_loader::{check_executable_inode, ProgramToLoad}; pub use rlimit::ResourceType; pub use stats::collect_process_creation_count; pub use term_status::TermStatus; diff --git a/kernel/src/process/process/init_proc.rs b/kernel/src/process/process/init_proc.rs index 6fb9bdf07..064f58c58 100644 --- a/kernel/src/process/process/init_proc.rs +++ b/kernel/src/process/process/init_proc.rs @@ -103,7 +103,7 @@ fn create_init_task( let fs_path = FsPath::try_from(executable_path)?; let elf_file = fs.resolver().read().lookup(&fs_path)?; let program_to_load = - ProgramToLoad::build_from_file(elf_file, &fs_resolver, argv, envp, 1)?; + ProgramToLoad::build_from_inode(elf_file.inode(), &fs_resolver, argv, envp, 1)?; let vmar = process.lock_vmar(); program_to_load.load_to_vmar(vmar.unwrap(), &fs_resolver)? }; diff --git a/kernel/src/process/program_loader/elf/elf_file.rs b/kernel/src/process/program_loader/elf/elf_file.rs index 903726bc9..742a96ad1 100644 --- a/kernel/src/process/program_loader/elf/elf_file.rs +++ b/kernel/src/process/program_loader/elf/elf_file.rs @@ -7,7 +7,7 @@ use xmas_elf::{ }; use crate::{ - fs::{path::Path, utils::PATH_MAX}, + fs::utils::{Inode, PATH_MAX}, prelude::*, }; pub struct ElfHeaders { @@ -92,8 +92,8 @@ impl ElfHeaders { self.elf_header.pt2.type_.as_type() == header::Type::SharedObject } - /// Reads the LDSO path from the ELF file. - pub fn read_ldso_path(&self, elf_file: &Path) -> Result> { + /// Reads the LDSO path from the ELF inode. + pub fn read_ldso_path(&self, elf_inode: &Arc) -> Result> { for program_header in &self.program_headers { let type_ = program_header.get_type().map_err(|_| { Error::with_message(Errno::ENOEXEC, "parse program header type fails") @@ -109,9 +109,8 @@ impl ElfHeaders { ); } - let inode = elf_file.inode(); let mut buffer = vec![0; file_size]; - inode.read_bytes_at(file_offset, &mut buffer)?; + elf_inode.read_bytes_at(file_offset, &mut buffer)?; let ldso_path = CString::from_vec_with_nul(buffer).map_err(|_| { Error::with_message( diff --git a/kernel/src/process/program_loader/elf/load_elf.rs b/kernel/src/process/program_loader/elf/load_elf.rs index db347b517..54a367b0f 100644 --- a/kernel/src/process/program_loader/elf/load_elf.rs +++ b/kernel/src/process/program_loader/elf/load_elf.rs @@ -17,6 +17,7 @@ use crate::{ fs::{ fs_resolver::{FsPath, FsResolver}, path::Path, + utils::Inode, }, prelude::*, process::process_vm::{AuxKey, AuxVec}, @@ -29,20 +30,20 @@ use crate::{ /// initialize process init stack. pub fn load_elf_to_vmar( vmar: &Vmar, - elf_file: Path, + elf_inode: &Arc, fs_resolver: &FsResolver, elf_headers: ElfHeaders, argv: Vec, envp: Vec, ) -> Result { - let ldso = lookup_and_parse_ldso(&elf_headers, &elf_file, fs_resolver)?; + let ldso = lookup_and_parse_ldso(&elf_headers, elf_inode, fs_resolver)?; #[cfg_attr( not(any(target_arch = "x86_64", target_arch = "riscv64")), expect(unused_mut) )] let (_range, entry_point, mut aux_vec) = - init_and_map_vmos(vmar, ldso, &elf_headers, &elf_file)?; + init_and_map_vmos(vmar, ldso, &elf_headers, elf_inode)?; // Map the vDSO and set the entry. // Since the vDSO does not require being mapped to any specific address, @@ -69,11 +70,11 @@ pub fn load_elf_to_vmar( fn lookup_and_parse_ldso( headers: &ElfHeaders, - elf_file: &Path, + elf_inode: &Arc, fs_resolver: &FsResolver, ) -> Result> { let ldso_file = { - let Some(ldso_path) = headers.read_ldso_path(elf_file)? else { + let Some(ldso_path) = headers.read_ldso_path(elf_inode)? else { return Ok(None); }; // Our FS requires the path to be valid UTF-8. This may be too restrictive. @@ -96,7 +97,7 @@ fn lookup_and_parse_ldso( } fn load_ldso(vmar: &Vmar, ldso_file: &Path, ldso_elf: &ElfHeaders) -> Result { - let range = map_segment_vmos(ldso_elf, vmar, ldso_file)?; + let range = map_segment_vmos(ldso_elf, vmar, ldso_file.inode())?; Ok(LdsoLoadInfo { entry_point: range .relocated_addr_of(ldso_elf.entry_point()) @@ -116,7 +117,7 @@ fn init_and_map_vmos( vmar: &Vmar, ldso: Option<(Path, ElfHeaders)>, parsed_elf: &ElfHeaders, - elf_file: &Path, + elf_inode: &Arc, ) -> Result<(RelocatedRange, Vaddr, AuxVec)> { // After we clear process vm, if any error happens, we must call exit_group instead of return to user space. let ldso_load_info = if let Some((ldso_file, ldso_elf)) = ldso { @@ -125,7 +126,7 @@ fn init_and_map_vmos( None }; - let elf_map_range = map_segment_vmos(parsed_elf, vmar, elf_file)?; + let elf_map_range = map_segment_vmos(parsed_elf, vmar, elf_inode)?; let mut aux_vec = { let ldso_base = ldso_load_info @@ -135,7 +136,7 @@ fn init_and_map_vmos( }; // Set AT_SECURE based on setuid/setgid bits of the executable file. - let mode = elf_file.inode().mode()?; + let mode = elf_inode.mode()?; let secure = if mode.has_set_uid() || mode.has_set_gid() { 1 } else { @@ -183,7 +184,11 @@ pub struct ElfLoadInfo { /// boundaries may not be page-aligned. /// /// [`Vmo`]: crate::vm::vmo::Vmo -pub fn map_segment_vmos(elf: &ElfHeaders, vmar: &Vmar, elf_file: &Path) -> Result { +pub fn map_segment_vmos( + elf: &ElfHeaders, + vmar: &Vmar, + elf_inode: &Arc, +) -> Result { let elf_va_range = get_range_for_all_segments(elf)?; let map_range = if elf.is_shared_object() { @@ -225,7 +230,7 @@ pub fn map_segment_vmos(elf: &ElfHeaders, vmar: &Vmar, elf_file: &Path) -> Resul .relocated_addr_of(program_header.virtual_addr as Vaddr) .expect("Address not covered by `get_range_for_all_segments`"); - map_segment_vmo(program_header, elf_file, vmar, map_at)?; + map_segment_vmo(program_header, elf_inode, vmar, map_at)?; } } @@ -297,7 +302,7 @@ fn get_range_for_all_segments(elf: &ElfHeaders) -> Result> { /// If needed, create additional anonymous mapping to represents .bss segment. fn map_segment_vmo( program_header: &ProgramHeader64, - elf_file: &Path, + elf_inode: &Arc, vmar: &Vmar, map_at: Vaddr, ) -> Result<()> { @@ -318,8 +323,7 @@ fn map_segment_vmo( let virtual_addr = program_header.virtual_addr as usize; debug_assert!(file_offset % PAGE_SIZE == virtual_addr % PAGE_SIZE); let segment_vmo = { - let inode = elf_file.inode(); - inode.page_cache().ok_or(Error::with_message( + elf_inode.page_cache().ok_or(Error::with_message( Errno::ENOENT, "executable has no page cache", ))? diff --git a/kernel/src/process/program_loader/mod.rs b/kernel/src/process/program_loader/mod.rs index d51557392..8e35ea753 100644 --- a/kernel/src/process/program_loader/mod.rs +++ b/kernel/src/process/program_loader/mod.rs @@ -10,8 +10,7 @@ use self::{ use crate::{ fs::{ fs_resolver::{FsPath, FsResolver}, - path::Path, - utils::{InodeType, Permission}, + utils::{Inode, InodeType, Permission}, }, prelude::*, vm::vmar::Vmar, @@ -22,7 +21,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 { - elf_file: Path, + elf_inode: Arc, file_first_page: Box<[u8; PAGE_SIZE]>, argv: Vec, envp: Vec, @@ -36,18 +35,17 @@ impl ProgramToLoad { /// 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_file( - elf_file: Path, + pub fn build_from_inode( + elf_inode: &Arc, fs_resolver: &FsResolver, argv: Vec, envp: Vec, recursion_limit: usize, ) -> Result { - let inode = elf_file.inode(); 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]); - inode.read_bytes_at(0, &mut *buffer)?; + elf_inode.read_bytes_at(0, &mut *buffer)?; buffer }; if let Some(mut new_argv) = parse_shebang_line(&*file_first_page)? { @@ -60,9 +58,9 @@ impl ProgramToLoad { let fs_path = FsPath::try_from(filename.as_str())?; fs_resolver.lookup(&fs_path)? }; - check_executable_file(&interpreter)?; - return Self::build_from_file( - interpreter, + check_executable_inode(interpreter.inode())?; + return Self::build_from_inode( + interpreter.inode(), fs_resolver, new_argv, envp, @@ -71,7 +69,7 @@ impl ProgramToLoad { } Ok(Self { - elf_file, + elf_inode: elf_inode.clone(), file_first_page, argv, envp, @@ -80,14 +78,12 @@ impl ProgramToLoad { /// Loads the executable into the specified virtual memory space. /// - /// Returns a tuple containing: - /// 1. The absolute path of the loaded executable. - /// 2. Information about the ELF loading process. + /// Returns the information about the ELF loading process. pub fn load_to_vmar(self, vmar: &Vmar, fs_resolver: &FsResolver) -> Result { let elf_headers = ElfHeaders::parse_elf(&*self.file_first_page)?; let elf_load_info = load_elf_to_vmar( vmar, - self.elf_file, + &self.elf_inode, fs_resolver, elf_headers, self.argv, @@ -98,21 +94,21 @@ impl ProgramToLoad { } } -pub fn check_executable_file(path: &Path) -> Result<()> { - if path.type_().is_directory() { - return_errno_with_message!(Errno::EISDIR, "the file is a directory"); +pub fn check_executable_inode(inode: &Arc) -> Result<()> { + if inode.type_().is_directory() { + return_errno_with_message!(Errno::EISDIR, "the inode is a directory"); } - if path.type_() == InodeType::SymLink { - return_errno_with_message!(Errno::ELOOP, "the file is a symbolic link"); + if inode.type_() == InodeType::SymLink { + return_errno_with_message!(Errno::ELOOP, "the inode is a symbolic link"); } - if !path.type_().is_regular_file() { - return_errno_with_message!(Errno::EACCES, "the path is not a regular file"); + if !inode.type_().is_regular_file() { + return_errno_with_message!(Errno::EACCES, "the inode is not a regular file"); } - if path.inode().check_permission(Permission::MAY_EXEC).is_err() { - return_errno_with_message!(Errno::EACCES, "the path is not executable"); + if inode.check_permission(Permission::MAY_EXEC).is_err() { + return_errno_with_message!(Errno::EACCES, "the inode is not executable"); } Ok(()) diff --git a/kernel/src/syscall/execve.rs b/kernel/src/syscall/execve.rs index b1d239019..4ee2928a8 100644 --- a/kernel/src/syscall/execve.rs +++ b/kernel/src/syscall/execve.rs @@ -10,7 +10,7 @@ use crate::{ path::Path, }, prelude::*, - process::{check_executable_file, do_execve}, + process::{check_executable_inode, do_execve}, }; pub fn sys_execve( @@ -75,7 +75,7 @@ fn lookup_executable_file( } }; - check_executable_file(&path)?; + check_executable_inode(path.inode())?; Ok(path) }