Browse Source

feat: add execveat syscall (#1240)

Signed-off-by: Godones <chenlinfeng25@outlook.com>
linfeng 1 day ago
parent
commit
cd10e69927

+ 4 - 2
kernel/src/init/initial_kthread.rs

@@ -2,7 +2,7 @@
 
 
 use core::sync::atomic::{compiler_fence, Ordering};
 use core::sync::atomic::{compiler_fence, Ordering};
 
 
-use alloc::{ffi::CString, string::ToString};
+use alloc::ffi::CString;
 use log::{debug, error};
 use log::{debug, error};
 use system_error::SystemError;
 use system_error::SystemError;
 
 
@@ -161,8 +161,10 @@ fn run_init_process(
     compiler_fence(Ordering::SeqCst);
     compiler_fence(Ordering::SeqCst);
     let path = proc_init_info.proc_name.to_str().unwrap();
     let path = proc_init_info.proc_name.to_str().unwrap();
 
 
+    let pwd = ProcessManager::current_pcb().pwd_inode();
+    let inode = pwd.lookup(path)?;
     do_execve(
     do_execve(
-        path.to_string(),
+        inode,
         proc_init_info.args.clone(),
         proc_init_info.args.clone(),
         proc_init_info.envs.clone(),
         proc_init_info.envs.clone(),
         trap_frame,
         trap_frame,

+ 9 - 5
kernel/src/libs/elf.rs

@@ -787,13 +787,17 @@ impl BinaryLoader for ElfLoader {
                     e
                     e
                 ))
                 ))
             })?;
             })?;
+            let pwd = ProcessManager::current_pcb().pwd_inode();
+            let inode = pwd.lookup(interpreter_path).map_err(|_| {
+                log::error!("Failed to find interpreter path: {}", interpreter_path);
+                return ExecError::InvalidParemeter;
+            })?;
             // log::debug!("opening interpreter at :{}", interpreter_path);
             // log::debug!("opening interpreter at :{}", interpreter_path);
             interpreter = Some(
             interpreter = Some(
-                ExecParam::new(interpreter_path, param.vm().clone(), ExecParamFlags::EXEC)
-                    .map_err(|e| {
-                        log::error!("Failed to load interpreter {interpreter_path}: {:?}", e);
-                        return ExecError::NotSupported;
-                    })?,
+                ExecParam::new(inode, param.vm().clone(), ExecParamFlags::EXEC).map_err(|e| {
+                    log::error!("Failed to load interpreter {interpreter_path}: {:?}", e);
+                    return ExecError::NotSupported;
+                })?,
             );
             );
         }
         }
         //TODO 缺少一部分逻辑 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#931
         //TODO 缺少一部分逻辑 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/binfmt_elf.c#931

+ 6 - 6
kernel/src/process/exec.rs

@@ -5,7 +5,10 @@ use system_error::SystemError;
 
 
 use crate::{
 use crate::{
     driver::base::block::SeekFrom,
     driver::base::block::SeekFrom,
-    filesystem::vfs::file::{File, FileMode},
+    filesystem::vfs::{
+        file::{File, FileMode},
+        IndexNode,
+    },
     libs::elf::ELF_LOADER,
     libs::elf::ELF_LOADER,
     mm::{
     mm::{
         ucontext::{AddressSpace, UserStack},
         ucontext::{AddressSpace, UserStack},
@@ -111,15 +114,12 @@ pub enum ExecLoadMode {
 #[allow(dead_code)]
 #[allow(dead_code)]
 impl ExecParam {
 impl ExecParam {
     pub fn new(
     pub fn new(
-        file_path: &str,
+        file_inode: Arc<dyn IndexNode>,
         vm: Arc<AddressSpace>,
         vm: Arc<AddressSpace>,
         flags: ExecParamFlags,
         flags: ExecParamFlags,
     ) -> Result<Self, SystemError> {
     ) -> Result<Self, SystemError> {
-        let pwd = ProcessManager::current_pcb().pwd_inode();
-        let inode = pwd.lookup(file_path)?;
-
         // 读取文件头部,用于判断文件类型
         // 读取文件头部,用于判断文件类型
-        let file = File::new(inode, FileMode::O_RDONLY)?;
+        let file = File::new(file_inode, FileMode::O_RDONLY)?;
 
 
         Ok(Self {
         Ok(Self {
             file,
             file,

+ 4 - 3
kernel/src/process/execve.rs

@@ -1,5 +1,6 @@
 use crate::arch::CurrentIrqArch;
 use crate::arch::CurrentIrqArch;
 use crate::exception::InterruptArch;
 use crate::exception::InterruptArch;
+use crate::filesystem::vfs::IndexNode;
 use crate::ipc::signal_types::SignalStruct;
 use crate::ipc::signal_types::SignalStruct;
 use crate::process::exec::{load_binary_file, ExecParam, ExecParamFlags};
 use crate::process::exec::{load_binary_file, ExecParam, ExecParamFlags};
 use crate::process::ProcessManager;
 use crate::process::ProcessManager;
@@ -7,18 +8,18 @@ use crate::syscall::Syscall;
 use crate::{libs::rand::rand_bytes, mm::ucontext::AddressSpace};
 use crate::{libs::rand::rand_bytes, mm::ucontext::AddressSpace};
 
 
 use crate::arch::interrupt::TrapFrame;
 use crate::arch::interrupt::TrapFrame;
-use alloc::{ffi::CString, string::String, sync::Arc, vec::Vec};
+use alloc::{ffi::CString, sync::Arc, vec::Vec};
 use system_error::SystemError;
 use system_error::SystemError;
 
 
 pub fn do_execve(
 pub fn do_execve(
-    path: String,
+    file_inode: Arc<dyn IndexNode>,
     argv: Vec<CString>,
     argv: Vec<CString>,
     envp: Vec<CString>,
     envp: Vec<CString>,
     regs: &mut TrapFrame,
     regs: &mut TrapFrame,
 ) -> Result<(), SystemError> {
 ) -> Result<(), SystemError> {
     let address_space = AddressSpace::new(true).expect("Failed to create new address space");
     let address_space = AddressSpace::new(true).expect("Failed to create new address space");
     // debug!("to load binary file");
     // debug!("to load binary file");
-    let mut param = ExecParam::new(path.as_str(), address_space.clone(), ExecParamFlags::EXEC)?;
+    let mut param = ExecParam::new(file_inode, address_space.clone(), ExecParamFlags::EXEC)?;
     let old_vm = do_execve_switch_user_vm(address_space.clone());
     let old_vm = do_execve_switch_user_vm(address_space.clone());
 
 
     // 加载可执行文件
     // 加载可执行文件

+ 1 - 0
kernel/src/process/syscall/mod.rs

@@ -1,5 +1,6 @@
 mod sys_clone;
 mod sys_clone;
 mod sys_execve;
 mod sys_execve;
+mod sys_execveat;
 mod sys_exit;
 mod sys_exit;
 mod sys_exit_group;
 mod sys_exit_group;
 mod sys_get_rusage;
 mod sys_get_rusage;

+ 78 - 47
kernel/src/process/syscall/sys_execve.rs

@@ -1,8 +1,9 @@
-use log::error;
+use alloc::string::String;
+use alloc::sync::Arc;
 
 
 use crate::arch::interrupt::TrapFrame;
 use crate::arch::interrupt::TrapFrame;
 use crate::arch::syscall::nr::SYS_EXECVE;
 use crate::arch::syscall::nr::SYS_EXECVE;
-use crate::filesystem::vfs::MAX_PATHLEN;
+use crate::filesystem::vfs::{IndexNode, MAX_PATHLEN};
 use crate::mm::page::PAGE_4K_SIZE;
 use crate::mm::page::PAGE_4K_SIZE;
 use crate::mm::{verify_area, VirtAddr};
 use crate::mm::{verify_area, VirtAddr};
 use crate::process::execve::do_execve;
 use crate::process::execve::do_execve;
@@ -10,6 +11,7 @@ use crate::process::{ProcessControlBlock, ProcessManager};
 use crate::syscall::table::{FormattedSyscallParam, Syscall};
 use crate::syscall::table::{FormattedSyscallParam, Syscall};
 use crate::syscall::user_access::{check_and_clone_cstr, check_and_clone_cstr_array};
 use crate::syscall::user_access::{check_and_clone_cstr, check_and_clone_cstr_array};
 use alloc::{ffi::CString, vec::Vec};
 use alloc::{ffi::CString, vec::Vec};
+use log::error;
 use system_error::SystemError;
 use system_error::SystemError;
 
 
 pub struct SysExecve;
 pub struct SysExecve;
@@ -26,6 +28,63 @@ impl SysExecve {
     fn env_ptr(args: &[usize]) -> usize {
     fn env_ptr(args: &[usize]) -> usize {
         args[2]
         args[2]
     }
     }
+
+    pub fn check_args(
+        frame: &mut TrapFrame,
+        path_ptr: usize,
+        argv_ptr: usize,
+        env_ptr: usize,
+    ) -> Result<(), SystemError> {
+        if path_ptr == 0 {
+            return Err(SystemError::EINVAL);
+        }
+        let virt_path_ptr = VirtAddr::new(path_ptr);
+        let virt_argv_ptr = VirtAddr::new(argv_ptr);
+        let virt_env_ptr = VirtAddr::new(env_ptr);
+
+        // 权限校验
+        if frame.is_from_user()
+            && (verify_area(virt_path_ptr, MAX_PATHLEN).is_err()
+                || verify_area(virt_argv_ptr, PAGE_4K_SIZE).is_err())
+            || verify_area(virt_env_ptr, PAGE_4K_SIZE).is_err()
+        {
+            return Err(SystemError::EFAULT);
+        }
+        Ok(())
+    }
+
+    pub fn basic_args(
+        path: *const u8,
+        argv: *const *const u8,
+        envp: *const *const u8,
+    ) -> Result<(CString, Vec<CString>, Vec<CString>), SystemError> {
+        let path: CString = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
+        let argv: Vec<CString> = check_and_clone_cstr_array(argv)?;
+        let envp: Vec<CString> = check_and_clone_cstr_array(envp)?;
+        Ok((path, argv, envp))
+    }
+
+    pub fn execve(
+        inode: Arc<dyn IndexNode>,
+        path: String,
+        argv: Vec<CString>,
+        envp: Vec<CString>,
+        frame: &mut TrapFrame,
+    ) -> Result<(), SystemError> {
+        ProcessManager::current_pcb()
+            .basic_mut()
+            .set_name(ProcessControlBlock::generate_name(&path, &argv));
+
+        do_execve(inode, argv, envp, frame)?;
+
+        let pcb = ProcessManager::current_pcb();
+        // 关闭设置了O_CLOEXEC的文件描述符
+        let fd_table = pcb.fd_table();
+        fd_table.write().close_on_exec();
+
+        pcb.set_execute_path(path);
+        Ok(())
+    }
 }
 }
 
 
 impl Syscall for SysExecve {
 impl Syscall for SysExecve {
@@ -38,52 +97,24 @@ impl Syscall for SysExecve {
         let argv_ptr = Self::argv_ptr(args);
         let argv_ptr = Self::argv_ptr(args);
         let env_ptr = Self::env_ptr(args);
         let env_ptr = Self::env_ptr(args);
 
 
-        let virt_path_ptr = VirtAddr::new(path_ptr);
-        let virt_argv_ptr = VirtAddr::new(argv_ptr);
-        let virt_env_ptr = VirtAddr::new(env_ptr);
+        Self::check_args(frame, path_ptr, argv_ptr, env_ptr)?;
 
 
-        // 权限校验
-        if frame.is_from_user()
-            && (verify_area(virt_path_ptr, MAX_PATHLEN).is_err()
-                || verify_area(virt_argv_ptr, PAGE_4K_SIZE).is_err())
-            || verify_area(virt_env_ptr, PAGE_4K_SIZE).is_err()
-        {
-            Err(SystemError::EFAULT)
-        } else {
-            let path = path_ptr as *const u8;
-            let argv = argv_ptr as *const *const u8;
-            let envp = env_ptr as *const *const u8;
-
-            if path.is_null() {
-                return Err(SystemError::EINVAL);
-            }
-
-            let x = || {
-                let path: CString = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
-                let argv: Vec<CString> = check_and_clone_cstr_array(argv)?;
-                let envp: Vec<CString> = check_and_clone_cstr_array(envp)?;
-                Ok((path, argv, envp))
-            };
-            let (path, argv, envp) = x().inspect_err(|e: &SystemError| {
-                error!("Failed to execve: {:?}", e);
-            })?;
-
-            let path = path.into_string().map_err(|_| SystemError::EINVAL)?;
-            ProcessManager::current_pcb()
-                .basic_mut()
-                .set_name(ProcessControlBlock::generate_name(&path, &argv));
-
-            do_execve(path.clone(), argv, envp, frame)?;
-
-            let pcb = ProcessManager::current_pcb();
-            // 关闭设置了O_CLOEXEC的文件描述符
-            let fd_table = pcb.fd_table();
-            fd_table.write().close_on_exec();
-
-            pcb.set_execute_path(path);
-
-            return Ok(0);
-        }
+        let (path, argv, envp) = Self::basic_args(
+            path_ptr as *const u8,
+            argv_ptr as *const *const u8,
+            env_ptr as *const *const u8,
+        )
+        .inspect_err(|e: &SystemError| {
+            error!("Failed to execve: {:?}", e);
+        })?;
+
+        let path = path.into_string().map_err(|_| SystemError::EINVAL)?;
+
+        let pwd = ProcessManager::current_pcb().pwd_inode();
+        let inode = pwd.lookup(&path)?;
+
+        Self::execve(inode, path, argv, envp, frame)?;
+        return Ok(0);
     }
     }
 
 
     fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
     fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {

+ 84 - 0
kernel/src/process/syscall/sys_execveat.rs

@@ -0,0 +1,84 @@
+use alloc::vec::Vec;
+use system_error::SystemError;
+
+use crate::{
+    arch::{interrupt::TrapFrame, syscall::nr::SYS_EXECVEAT},
+    filesystem::vfs::{utils::user_path_at, VFS_MAX_FOLLOW_SYMLINK_TIMES},
+    process::{syscall::sys_execve::SysExecve, ProcessManager},
+    syscall::table::{FormattedSyscallParam, Syscall},
+};
+
+bitflags::bitflags! {
+    struct OpenFlags: u32 {
+        const AT_EMPTY_PATH = 0x1000;
+        const AT_SYMLINK_NOFOLLOW = 0x100;
+    }
+}
+
+/// See https://man7.org/linux/man-pages/man2/execveat.2.html
+pub struct SysExecveAt;
+
+impl Syscall for SysExecveAt {
+    fn num_args(&self) -> usize {
+        5
+    }
+
+    fn handle(&self, args: &[usize], frame: &mut TrapFrame) -> Result<usize, SystemError> {
+        let dirfd = args[0];
+        let path_ptr = args[1];
+        let argv_ptr = args[2];
+        let env_ptr = args[3];
+        let flags = OpenFlags::from_bits(args[4] as u32).ok_or(SystemError::EINVAL)?;
+
+        // 权限校验
+        SysExecve::check_args(frame, path_ptr, argv_ptr, env_ptr)?;
+
+        let (path, argv, envp) = SysExecve::basic_args(
+            path_ptr as *const u8,
+            argv_ptr as *const *const u8,
+            env_ptr as *const *const u8,
+        )
+        .inspect_err(|e: &SystemError| {
+            log::error!("Failed to execve: {:?}", e);
+        })?;
+        let path = path.into_string().map_err(|_| SystemError::EINVAL)?;
+
+        let inode = if flags.contains(OpenFlags::AT_EMPTY_PATH) && path.is_empty() {
+            let binding = ProcessManager::current_pcb().fd_table();
+            let fd_table_guard = binding.read();
+
+            let file = fd_table_guard
+                .get_file_by_fd(dirfd as _)
+                .ok_or(SystemError::EBADF)?;
+            file.inode()
+        } else {
+            let (inode_begin, path) =
+                user_path_at(&ProcessManager::current_pcb(), dirfd as _, &path)?;
+            let inode = inode_begin.lookup_follow_symlink(
+                &path,
+                if flags.contains(OpenFlags::AT_SYMLINK_NOFOLLOW) {
+                    VFS_MAX_FOLLOW_SYMLINK_TIMES
+                } else {
+                    0
+                },
+            )?;
+            inode
+        };
+
+        SysExecve::execve(inode, path, argv, envp, frame)?;
+
+        Ok(0)
+    }
+
+    fn entry_format(&self, args: &[usize]) -> Vec<crate::syscall::table::FormattedSyscallParam> {
+        vec![
+            FormattedSyscallParam::new("dirfd", format!("{:#x}", args[0])),
+            FormattedSyscallParam::new("path", format!("{:#x}", args[1])),
+            FormattedSyscallParam::new("argv", format!("{:#x}", args[2])),
+            FormattedSyscallParam::new("envp", format!("{:#x}", args[3])),
+            FormattedSyscallParam::new("flags", format!("{:#x}", args[4])),
+        ]
+    }
+}
+
+syscall_table_macros::declare_syscall!(SYS_EXECVEAT, SysExecveAt);