2024-01-03 03:22:36 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
2023-12-25 03:12:25 +00:00
|
|
|
use aster_rights::WriteOp;
|
2024-11-28 11:36:09 +00:00
|
|
|
use ostd::{
|
2025-03-05 07:17:32 +00:00
|
|
|
cpu::context::{FpuState, RawGeneralRegs, UserContext},
|
2024-11-28 11:36:09 +00:00
|
|
|
user::UserContextApi,
|
|
|
|
|
};
|
2022-10-26 09:47:38 +00:00
|
|
|
|
2022-11-04 06:22:28 +00:00
|
|
|
use super::{constants::*, SyscallReturn};
|
2024-02-25 14:09:24 +00:00
|
|
|
use crate::{
|
|
|
|
|
fs::{
|
2024-12-26 13:35:56 +00:00
|
|
|
file_table::{get_file_fast, FileDesc},
|
2024-02-25 14:09:24 +00:00
|
|
|
fs_resolver::{FsPath, AT_FDCWD},
|
2024-05-15 07:06:32 +00:00
|
|
|
path::Dentry,
|
2024-02-25 14:09:24 +00:00
|
|
|
},
|
|
|
|
|
prelude::*,
|
|
|
|
|
process::{
|
2025-04-03 06:16:17 +00:00
|
|
|
check_executable_file, posix_thread::ThreadName, renew_vm_and_map, Credentials, Process,
|
|
|
|
|
ProgramToLoad, MAX_ARGV_NUMBER, MAX_ARG_LEN, MAX_ENVP_NUMBER, MAX_ENV_LEN,
|
2024-02-25 14:09:24 +00:00
|
|
|
},
|
|
|
|
|
};
|
2022-10-26 09:47:38 +00:00
|
|
|
|
|
|
|
|
pub fn sys_execve(
|
|
|
|
|
filename_ptr: Vaddr,
|
|
|
|
|
argv_ptr_ptr: Vaddr,
|
|
|
|
|
envp_ptr_ptr: Vaddr,
|
2024-08-04 06:37:50 +00:00
|
|
|
ctx: &Context,
|
2024-08-11 14:42:17 +00:00
|
|
|
user_context: &mut UserContext,
|
2022-11-04 06:22:28 +00:00
|
|
|
) -> Result<SyscallReturn> {
|
2023-06-13 02:13:00 +00:00
|
|
|
let elf_file = {
|
2024-08-11 14:42:17 +00:00
|
|
|
let executable_path = read_filename(filename_ptr, ctx)?;
|
2024-08-11 13:35:27 +00:00
|
|
|
lookup_executable_file(AT_FDCWD, executable_path, OpenFlags::empty(), ctx)?
|
2023-06-13 02:13:00 +00:00
|
|
|
};
|
2023-08-16 09:39:27 +00:00
|
|
|
|
2024-08-11 14:42:17 +00:00
|
|
|
do_execve(elf_file, argv_ptr_ptr, envp_ptr_ptr, ctx, user_context)?;
|
2023-06-13 02:13:00 +00:00
|
|
|
Ok(SyscallReturn::NoReturn)
|
|
|
|
|
}
|
2023-03-30 06:53:39 +00:00
|
|
|
|
2023-06-13 02:13:00 +00:00
|
|
|
pub fn sys_execveat(
|
2024-05-08 12:01:11 +00:00
|
|
|
dfd: FileDesc,
|
2023-06-13 02:13:00 +00:00
|
|
|
filename_ptr: Vaddr,
|
|
|
|
|
argv_ptr_ptr: Vaddr,
|
|
|
|
|
envp_ptr_ptr: Vaddr,
|
|
|
|
|
flags: u32,
|
2024-08-04 06:37:50 +00:00
|
|
|
ctx: &Context,
|
2024-08-11 14:42:17 +00:00
|
|
|
user_context: &mut UserContext,
|
2023-06-13 02:13:00 +00:00
|
|
|
) -> Result<SyscallReturn> {
|
2023-08-16 09:39:27 +00:00
|
|
|
let elf_file = {
|
|
|
|
|
let flags = OpenFlags::from_bits_truncate(flags);
|
2024-08-11 14:42:17 +00:00
|
|
|
let filename = read_filename(filename_ptr, ctx)?;
|
2024-08-11 13:35:27 +00:00
|
|
|
lookup_executable_file(dfd, filename, flags, ctx)?
|
2023-08-16 09:39:27 +00:00
|
|
|
};
|
|
|
|
|
|
2024-08-11 14:42:17 +00:00
|
|
|
do_execve(elf_file, argv_ptr_ptr, envp_ptr_ptr, ctx, user_context)?;
|
2023-06-13 02:13:00 +00:00
|
|
|
Ok(SyscallReturn::NoReturn)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn lookup_executable_file(
|
2024-05-08 12:01:11 +00:00
|
|
|
dfd: FileDesc,
|
2023-06-13 02:13:00 +00:00
|
|
|
filename: String,
|
|
|
|
|
flags: OpenFlags,
|
2024-08-11 13:35:27 +00:00
|
|
|
ctx: &Context,
|
2024-10-10 12:51:26 +00:00
|
|
|
) -> Result<Dentry> {
|
2024-05-15 07:06:32 +00:00
|
|
|
let dentry = if flags.contains(OpenFlags::AT_EMPTY_PATH) && filename.is_empty() {
|
2024-12-26 13:35:56 +00:00
|
|
|
let mut file_table = ctx.thread_local.file_table().borrow_mut();
|
|
|
|
|
let file = get_file_fast!(&mut file_table, dfd);
|
|
|
|
|
file.as_inode_or_err()?.dentry().clone()
|
2023-06-13 02:13:00 +00:00
|
|
|
} else {
|
2024-12-26 13:35:56 +00:00
|
|
|
let fs_resolver = ctx.posix_thread.fs().resolver().read();
|
2023-06-13 02:13:00 +00:00
|
|
|
let fs_path = FsPath::new(dfd, &filename)?;
|
|
|
|
|
if flags.contains(OpenFlags::AT_SYMLINK_NOFOLLOW) {
|
2024-12-26 13:35:56 +00:00
|
|
|
fs_resolver.lookup_no_follow(&fs_path)?
|
2023-06-13 02:13:00 +00:00
|
|
|
} else {
|
2024-12-26 13:35:56 +00:00
|
|
|
fs_resolver.lookup(&fs_path)?
|
2023-06-13 02:13:00 +00:00
|
|
|
}
|
2024-12-26 13:35:56 +00:00
|
|
|
};
|
|
|
|
|
|
2024-05-15 07:06:32 +00:00
|
|
|
check_executable_file(&dentry)?;
|
2024-12-26 13:35:56 +00:00
|
|
|
|
2024-05-15 07:06:32 +00:00
|
|
|
Ok(dentry)
|
2023-06-13 02:13:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn do_execve(
|
2024-10-10 12:51:26 +00:00
|
|
|
elf_file: Dentry,
|
2023-06-13 02:13:00 +00:00
|
|
|
argv_ptr_ptr: Vaddr,
|
|
|
|
|
envp_ptr_ptr: Vaddr,
|
2024-08-04 06:37:50 +00:00
|
|
|
ctx: &Context,
|
2024-08-11 14:42:17 +00:00
|
|
|
user_context: &mut UserContext,
|
2023-06-13 02:13:00 +00:00
|
|
|
) -> Result<()> {
|
2024-08-04 06:37:50 +00:00
|
|
|
let Context {
|
|
|
|
|
process,
|
2024-12-01 01:19:03 +00:00
|
|
|
thread_local,
|
2024-08-04 06:37:50 +00:00
|
|
|
posix_thread,
|
2024-12-01 01:19:03 +00:00
|
|
|
..
|
2024-08-04 06:37:50 +00:00
|
|
|
} = ctx;
|
|
|
|
|
|
2023-06-13 02:13:00 +00:00
|
|
|
let executable_path = elf_file.abs_path();
|
2024-08-11 14:42:17 +00:00
|
|
|
let argv = read_cstring_vec(argv_ptr_ptr, MAX_ARGV_NUMBER, MAX_ARG_LEN, ctx)?;
|
|
|
|
|
let envp = read_cstring_vec(envp_ptr_ptr, MAX_ENVP_NUMBER, MAX_ENV_LEN, ctx)?;
|
2022-11-09 07:14:12 +00:00
|
|
|
debug!(
|
|
|
|
|
"filename: {:?}, argv = {:?}, envp = {:?}",
|
2023-03-07 09:13:35 +00:00
|
|
|
executable_path, argv, envp
|
2022-11-09 07:14:12 +00:00
|
|
|
);
|
2022-12-20 06:12:22 +00:00
|
|
|
// FIXME: should we set thread name in execve?
|
2023-06-13 02:13:00 +00:00
|
|
|
*posix_thread.thread_name().lock() =
|
|
|
|
|
Some(ThreadName::new_from_executable_path(&executable_path)?);
|
2023-03-13 07:59:01 +00:00
|
|
|
// clear ctid
|
|
|
|
|
// FIXME: should we clear ctid when execve?
|
2024-12-01 01:19:03 +00:00
|
|
|
thread_local.clear_child_tid().set(0);
|
2022-11-09 07:14:12 +00:00
|
|
|
|
2023-12-13 03:29:03 +00:00
|
|
|
// Ensure that the file descriptors with the close-on-exec flag are closed.
|
2024-12-01 03:41:23 +00:00
|
|
|
// FIXME: This is just wrong if the file table is shared with other processes.
|
2024-12-26 13:35:56 +00:00
|
|
|
let closed_files = thread_local
|
|
|
|
|
.file_table()
|
|
|
|
|
.borrow()
|
|
|
|
|
.write()
|
|
|
|
|
.close_files_on_exec();
|
2024-07-23 11:21:03 +00:00
|
|
|
drop(closed_files);
|
2023-12-13 03:29:03 +00:00
|
|
|
|
2023-03-30 06:53:39 +00:00
|
|
|
debug!("load program to root vmar");
|
2025-04-03 06:16:17 +00:00
|
|
|
let fs_resolver = &*posix_thread.fs().resolver().read();
|
|
|
|
|
let program_to_load =
|
|
|
|
|
ProgramToLoad::build_from_file(elf_file.clone(), fs_resolver, argv, envp, 1)?;
|
|
|
|
|
|
|
|
|
|
let process_vm = process.vm();
|
|
|
|
|
if process.status().is_vfork_child() {
|
|
|
|
|
renew_vm_and_map(ctx);
|
|
|
|
|
|
|
|
|
|
// Resumes the parent process.
|
|
|
|
|
process.status().set_vfork_child(false);
|
|
|
|
|
let parent = process.parent().lock().process().upgrade().unwrap();
|
|
|
|
|
parent.children_wait_queue().wake_all();
|
|
|
|
|
} else {
|
|
|
|
|
// FIXME: Currently, the efficiency of replacing the VMAR is lower than that
|
|
|
|
|
// of directly clearing the VMAR. Therefore, if not in vfork case we will only
|
|
|
|
|
// clear the VMAR.
|
|
|
|
|
process_vm.clear_and_map();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let (new_executable_path, elf_load_info) =
|
|
|
|
|
program_to_load.load_to_vm(process_vm, fs_resolver)?;
|
2024-05-30 12:09:54 +00:00
|
|
|
|
|
|
|
|
// After the program has been successfully loaded, the virtual memory of the current process
|
|
|
|
|
// is initialized. Hence, it is necessary to clear the previously recorded robust list.
|
2024-12-01 01:19:03 +00:00
|
|
|
*thread_local.robust_list().borrow_mut() = None;
|
2022-10-26 09:47:38 +00:00
|
|
|
debug!("load elf in execve succeeds");
|
2023-11-29 11:42:53 +00:00
|
|
|
|
2024-12-01 01:19:03 +00:00
|
|
|
let credentials = posix_thread.credentials_mut();
|
2024-08-04 06:37:50 +00:00
|
|
|
set_uid_from_elf(process, &credentials, &elf_file)?;
|
|
|
|
|
set_gid_from_elf(process, &credentials, &elf_file)?;
|
2024-12-05 07:49:43 +00:00
|
|
|
credentials.set_keep_capabilities(false);
|
2023-11-29 11:42:53 +00:00
|
|
|
|
2023-03-30 06:53:39 +00:00
|
|
|
// set executable path
|
2024-08-04 06:37:50 +00:00
|
|
|
process.set_executable_path(new_executable_path);
|
2022-10-31 08:14:41 +00:00
|
|
|
// set signal disposition to default
|
2024-08-04 06:37:50 +00:00
|
|
|
process.sig_dispositions().lock().inherit();
|
2024-08-11 14:42:17 +00:00
|
|
|
// set cpu context to default
|
2024-11-28 11:36:09 +00:00
|
|
|
*user_context.general_regs_mut() = RawGeneralRegs::default();
|
|
|
|
|
user_context.set_tls_pointer(0);
|
|
|
|
|
*user_context.fpu_state_mut() = FpuState::default();
|
|
|
|
|
// FIXME: how to reset the FPU state correctly? Before returning to the user space,
|
|
|
|
|
// the kernel will call `handle_pending_signal`, which may update the CPU states so that
|
|
|
|
|
// when the kernel switches to the user mode, the control of the CPU will be handed over
|
|
|
|
|
// to the user-registered signal handlers.
|
|
|
|
|
user_context.fpu_state().restore();
|
2022-10-26 09:47:38 +00:00
|
|
|
// set new entry point
|
2024-08-11 14:42:17 +00:00
|
|
|
user_context.set_instruction_pointer(elf_load_info.entry_point() as _);
|
2022-10-26 09:47:38 +00:00
|
|
|
debug!("entry_point: 0x{:x}", elf_load_info.entry_point());
|
|
|
|
|
// set new user stack top
|
2024-08-11 14:42:17 +00:00
|
|
|
user_context.set_stack_pointer(elf_load_info.user_stack_top() as _);
|
2022-10-26 09:47:38 +00:00
|
|
|
debug!("user stack top: 0x{:x}", elf_load_info.user_stack_top());
|
2023-06-13 02:13:00 +00:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bitflags::bitflags! {
|
|
|
|
|
struct OpenFlags: u32 {
|
|
|
|
|
const AT_EMPTY_PATH = 0x1000;
|
|
|
|
|
const AT_SYMLINK_NOFOLLOW = 0x100;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-11 14:42:17 +00:00
|
|
|
fn read_filename(filename_ptr: Vaddr, ctx: &Context) -> Result<String> {
|
|
|
|
|
let filename = ctx
|
2024-11-13 15:39:10 +00:00
|
|
|
.user_space()
|
2024-08-11 14:42:17 +00:00
|
|
|
.read_cstring(filename_ptr, MAX_FILENAME_LEN)?;
|
2023-06-13 02:13:00 +00:00
|
|
|
Ok(filename.into_string().unwrap())
|
2022-10-26 09:47:38 +00:00
|
|
|
}
|
2022-11-09 07:14:12 +00:00
|
|
|
|
|
|
|
|
fn read_cstring_vec(
|
|
|
|
|
array_ptr: Vaddr,
|
|
|
|
|
max_string_number: usize,
|
|
|
|
|
max_string_len: usize,
|
2024-08-11 14:42:17 +00:00
|
|
|
ctx: &Context,
|
2022-11-09 07:14:12 +00:00
|
|
|
) -> Result<Vec<CString>> {
|
|
|
|
|
let mut res = Vec::new();
|
2024-07-31 07:36:35 +00:00
|
|
|
// On Linux, argv pointer and envp pointer can be specified as NULL.
|
|
|
|
|
if array_ptr == 0 {
|
|
|
|
|
return Ok(res);
|
|
|
|
|
}
|
2022-11-09 07:14:12 +00:00
|
|
|
let mut read_addr = array_ptr;
|
|
|
|
|
let mut find_null = false;
|
2024-11-13 15:39:10 +00:00
|
|
|
let user_space = ctx.user_space();
|
2022-11-09 07:14:12 +00:00
|
|
|
for _ in 0..max_string_number {
|
2024-08-09 08:11:43 +00:00
|
|
|
let cstring_ptr = user_space.read_val::<usize>(read_addr)?;
|
2022-11-09 07:14:12 +00:00
|
|
|
read_addr += 8;
|
|
|
|
|
// read a null pointer
|
|
|
|
|
if cstring_ptr == 0 {
|
|
|
|
|
find_null = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-08-09 08:11:43 +00:00
|
|
|
let cstring = user_space.read_cstring(cstring_ptr, max_string_len)?;
|
2022-11-09 07:14:12 +00:00
|
|
|
res.push(cstring);
|
|
|
|
|
}
|
|
|
|
|
if !find_null {
|
2022-12-07 11:22:37 +00:00
|
|
|
return_errno_with_message!(Errno::E2BIG, "Cannot find null pointer in vector");
|
2022-11-09 07:14:12 +00:00
|
|
|
}
|
|
|
|
|
Ok(res)
|
|
|
|
|
}
|
2023-11-29 11:42:53 +00:00
|
|
|
|
|
|
|
|
/// Sets uid for credentials as the same of uid of elf file if elf file has `set_uid` bit.
|
2024-01-08 03:36:16 +00:00
|
|
|
fn set_uid_from_elf(
|
2024-08-04 06:37:50 +00:00
|
|
|
current: &Process,
|
2024-01-08 03:36:16 +00:00
|
|
|
credentials: &Credentials<WriteOp>,
|
2024-10-10 12:51:26 +00:00
|
|
|
elf_file: &Dentry,
|
2024-01-08 03:36:16 +00:00
|
|
|
) -> Result<()> {
|
2024-01-04 09:52:27 +00:00
|
|
|
if elf_file.mode()?.has_set_uid() {
|
|
|
|
|
let uid = elf_file.owner()?;
|
2023-11-29 11:42:53 +00:00
|
|
|
credentials.set_euid(uid);
|
2024-01-08 03:36:16 +00:00
|
|
|
|
|
|
|
|
current.clear_parent_death_signal();
|
2023-11-29 11:42:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No matter whether the elf_file has `set_uid` bit, suid should be reset.
|
|
|
|
|
credentials.reset_suid();
|
2024-01-04 09:52:27 +00:00
|
|
|
Ok(())
|
2023-11-29 11:42:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets gid for credentials as the same of gid of elf file if elf file has `set_gid` bit.
|
2024-01-08 03:36:16 +00:00
|
|
|
fn set_gid_from_elf(
|
2024-08-04 06:37:50 +00:00
|
|
|
current: &Process,
|
2024-01-08 03:36:16 +00:00
|
|
|
credentials: &Credentials<WriteOp>,
|
2024-10-10 12:51:26 +00:00
|
|
|
elf_file: &Dentry,
|
2024-01-08 03:36:16 +00:00
|
|
|
) -> Result<()> {
|
2024-01-04 09:52:27 +00:00
|
|
|
if elf_file.mode()?.has_set_gid() {
|
|
|
|
|
let gid = elf_file.group()?;
|
2023-11-29 11:42:53 +00:00
|
|
|
credentials.set_egid(gid);
|
2024-01-08 03:36:16 +00:00
|
|
|
|
|
|
|
|
current.clear_parent_death_signal();
|
2023-11-29 11:42:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No matter whether the the elf file has `set_gid` bit, sgid should be reset.
|
|
|
|
|
credentials.reset_sgid();
|
2024-01-04 09:52:27 +00:00
|
|
|
Ok(())
|
2023-11-29 11:42:53 +00:00
|
|
|
}
|