From 999c21dd573dc16da882ead9cffa8cd436306692 Mon Sep 17 00:00:00 2001 From: Niv Kaminer Date: Thu, 28 Oct 2021 21:15:29 +0300 Subject: [PATCH 1/3] add execv --- src/imp/linux_raw/syscalls.rs | 50 +++++++++++++++++++++++++---------- src/runtime.rs | 14 ++++++++++ 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/imp/linux_raw/syscalls.rs b/src/imp/linux_raw/syscalls.rs index 7e87f8bea..24536b718 100644 --- a/src/imp/linux_raw/syscalls.rs +++ b/src/imp/linux_raw/syscalls.rs @@ -83,19 +83,20 @@ use linux_raw_sys::general::{ use linux_raw_sys::general::{__NR_arch_prctl, ARCH_SET_FS}; use linux_raw_sys::general::{ __NR_chdir, __NR_clock_getres, __NR_clock_nanosleep, __NR_close, __NR_dup, __NR_dup3, - __NR_epoll_create1, __NR_epoll_ctl, __NR_exit, __NR_exit_group, __NR_faccessat, __NR_fallocate, - __NR_fchdir, __NR_fchmod, __NR_fchmodat, __NR_fdatasync, __NR_flock, __NR_fsync, __NR_futex, - __NR_getcwd, __NR_getdents64, __NR_getpid, __NR_getppid, __NR_getpriority, __NR_gettid, - __NR_ioctl, __NR_linkat, __NR_madvise, __NR_mkdirat, __NR_mknodat, __NR_mlock, __NR_mprotect, - __NR_munlock, __NR_munmap, __NR_nanosleep, __NR_openat, __NR_pipe2, __NR_prctl, __NR_pread64, - __NR_preadv, __NR_pwrite64, __NR_pwritev, __NR_read, __NR_readlinkat, __NR_readv, - __NR_sched_getaffinity, __NR_sched_setaffinity, __NR_sched_yield, __NR_set_tid_address, - __NR_setpriority, __NR_symlinkat, __NR_uname, __NR_unlinkat, __NR_utimensat, __NR_wait4, - __NR_write, __NR_writev, __kernel_gid_t, __kernel_pid_t, __kernel_timespec, __kernel_uid_t, - epoll_event, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_un, socklen_t, AT_FDCWD, - AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW, EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD, FIONBIO, - FIONREAD, F_DUPFD, F_DUPFD_CLOEXEC, F_GETFD, F_GETFL, F_GETLEASE, F_GETOWN, F_GETSIG, F_SETFD, - F_SETFL, PR_SET_NAME, SIGCHLD, TCGETS, TIMER_ABSTIME, TIOCEXCL, TIOCGWINSZ, TIOCNXCL, + __NR_epoll_create1, __NR_epoll_ctl, __NR_execve, __NR_exit, __NR_exit_group, __NR_faccessat, + __NR_fallocate, __NR_fchdir, __NR_fchmod, __NR_fchmodat, __NR_fdatasync, __NR_flock, + __NR_fsync, __NR_futex, __NR_getcwd, __NR_getdents64, __NR_getpid, __NR_getppid, + __NR_getpriority, __NR_gettid, __NR_ioctl, __NR_linkat, __NR_madvise, __NR_mkdirat, + __NR_mknodat, __NR_mlock, __NR_mprotect, __NR_munlock, __NR_munmap, __NR_nanosleep, + __NR_openat, __NR_pipe2, __NR_prctl, __NR_pread64, __NR_preadv, __NR_pwrite64, __NR_pwritev, + __NR_read, __NR_readlinkat, __NR_readv, __NR_sched_getaffinity, __NR_sched_setaffinity, + __NR_sched_yield, __NR_set_tid_address, __NR_setpriority, __NR_symlinkat, __NR_uname, + __NR_unlinkat, __NR_utimensat, __NR_wait4, __NR_write, __NR_writev, __kernel_gid_t, + __kernel_pid_t, __kernel_timespec, __kernel_uid_t, epoll_event, sockaddr, sockaddr_in, + sockaddr_in6, sockaddr_un, socklen_t, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW, + EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD, FIONBIO, FIONREAD, F_DUPFD, F_DUPFD_CLOEXEC, + F_GETFD, F_GETFL, F_GETLEASE, F_GETOWN, F_GETSIG, F_SETFD, F_SETFL, PR_SET_NAME, SIGCHLD, + TCGETS, TIMER_ABSTIME, TIOCEXCL, TIOCGWINSZ, TIOCNXCL, }; #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] use linux_raw_sys::general::{__NR_dup2, __NR_open, __NR_pipe, __NR_poll}; @@ -123,7 +124,7 @@ use std::ffi::CStr; use std::io::{IoSlice, IoSliceMut, SeekFrom}; use std::mem::{size_of_val, MaybeUninit}; use std::net::{SocketAddrV4, SocketAddrV6}; -use std::os::raw::{c_int, c_uint, c_void}; +use std::os::raw::{c_char, c_int, c_uint, c_void}; #[cfg(target_arch = "x86")] use { super::conv::x86_sys, @@ -3590,6 +3591,27 @@ pub(crate) unsafe fn fork() -> io::Result { Ok(Pid::from_raw(pid)) } +pub fn execv>(path: &CStr, args: &[S]) -> io::Result<()> { + let mut argv: Vec<_> = args + .into_iter() + .map(AsRef::as_ref) + .map(CStr::as_ptr) + .collect(); + argv.push(std::ptr::null()); + _execv(path, &argv) +} + +fn _execv(path: &CStr, args: &[*const c_char]) -> io::Result<()> { + unsafe { + ret(syscall3_readonly( + nr(__NR_execve), + c_str(path), + slice_just_addr(args), + slice_just_addr(&[std::ptr::null::()]), + )) + } +} + #[inline] pub fn waitpid(pid: RawPid, waitopts: WaitOptions) -> io::Result> { unsafe { diff --git a/src/runtime.rs b/src/runtime.rs index 0c7dec250..d3fa2d211 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -17,8 +17,10 @@ #![allow(unsafe_code)] +use crate::path::Arg; use crate::process::Pid; use crate::{imp, io}; +use std::borrow::Cow; use std::ffi::{c_void, CStr}; #[cfg(target_arch = "x86")] @@ -117,3 +119,15 @@ pub use imp::thread::tls::StartupTlsInfo; pub unsafe fn fork() -> io::Result { imp::syscalls::fork() } + +/// Executes the program pointed to by `path`, with the arguments `args`. +/// +/// The first argument, by convention, +/// should be the filename associated with the file being executed. +pub fn execv(path: P, args: &[P]) -> io::Result<()> { + let arg_vec: Vec> = args + .into_iter() + .map(Arg::as_cow_c_str) + .collect::>()?; + path.into_with_c_str(|path_cstr| imp::syscalls::execv(path_cstr, &arg_vec)) +} From 50cce3f70b73a6df2420256ee47d1335dc9ece89 Mon Sep 17 00:00:00 2001 From: Niv Kaminer Date: Fri, 29 Oct 2021 00:13:10 +0300 Subject: [PATCH 2/3] use concrete type for syscalls::execv --- src/imp/linux_raw/syscalls.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/imp/linux_raw/syscalls.rs b/src/imp/linux_raw/syscalls.rs index 24536b718..03152fd19 100644 --- a/src/imp/linux_raw/syscalls.rs +++ b/src/imp/linux_raw/syscalls.rs @@ -119,6 +119,7 @@ use linux_raw_sys::v5_4::general::{ __NR_memfd_create, __NR_mlock2, __NR_preadv2, __NR_prlimit64, __NR_pwritev2, __NR_renameat2, __NR_statx, __NR_userfaultfd, statx, F_GETPIPE_SZ, F_GET_SEALS, F_SETPIPE_SZ, }; +use std::borrow::Cow; use std::convert::TryInto; use std::ffi::CStr; use std::io::{IoSlice, IoSliceMut, SeekFrom}; @@ -3591,22 +3592,14 @@ pub(crate) unsafe fn fork() -> io::Result { Ok(Pid::from_raw(pid)) } -pub fn execv>(path: &CStr, args: &[S]) -> io::Result<()> { - let mut argv: Vec<_> = args - .into_iter() - .map(AsRef::as_ref) - .map(CStr::as_ptr) - .collect(); +pub fn execv(path: &CStr, args: &[Cow<'_, CStr>]) -> io::Result<()> { + let mut argv: Vec<_> = args.into_iter().map(|cstr| CStr::as_ptr(cstr)).collect(); argv.push(std::ptr::null()); - _execv(path, &argv) -} - -fn _execv(path: &CStr, args: &[*const c_char]) -> io::Result<()> { unsafe { ret(syscall3_readonly( nr(__NR_execve), c_str(path), - slice_just_addr(args), + slice_just_addr(&args), slice_just_addr(&[std::ptr::null::()]), )) } From 248375acf5aabc3c431649f323517a8e10a52165 Mon Sep 17 00:00:00 2001 From: Niv Kaminer Date: Fri, 29 Oct 2021 00:32:38 +0300 Subject: [PATCH 3/3] allow setting environment variables in exec with execve --- src/imp/linux_raw/syscalls.rs | 13 +++++++++---- src/runtime.rs | 11 ++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/imp/linux_raw/syscalls.rs b/src/imp/linux_raw/syscalls.rs index 03152fd19..2da00e948 100644 --- a/src/imp/linux_raw/syscalls.rs +++ b/src/imp/linux_raw/syscalls.rs @@ -125,7 +125,7 @@ use std::ffi::CStr; use std::io::{IoSlice, IoSliceMut, SeekFrom}; use std::mem::{size_of_val, MaybeUninit}; use std::net::{SocketAddrV4, SocketAddrV6}; -use std::os::raw::{c_char, c_int, c_uint, c_void}; +use std::os::raw::{c_int, c_uint, c_void}; #[cfg(target_arch = "x86")] use { super::conv::x86_sys, @@ -3592,15 +3592,20 @@ pub(crate) unsafe fn fork() -> io::Result { Ok(Pid::from_raw(pid)) } -pub fn execv(path: &CStr, args: &[Cow<'_, CStr>]) -> io::Result<()> { +pub fn execve(path: &CStr, args: &[Cow<'_, CStr>], env_vars: &[Cow<'_, CStr>]) -> io::Result<()> { let mut argv: Vec<_> = args.into_iter().map(|cstr| CStr::as_ptr(cstr)).collect(); + let mut envs: Vec<_> = env_vars + .into_iter() + .map(|cstr| CStr::as_ptr(cstr)) + .collect(); argv.push(std::ptr::null()); + envs.push(std::ptr::null()); unsafe { ret(syscall3_readonly( nr(__NR_execve), c_str(path), - slice_just_addr(&args), - slice_just_addr(&[std::ptr::null::()]), + slice_just_addr(&argv), + slice_just_addr(&envs), )) } } diff --git a/src/runtime.rs b/src/runtime.rs index d3fa2d211..d2e3c926e 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -120,14 +120,19 @@ pub unsafe fn fork() -> io::Result { imp::syscalls::fork() } -/// Executes the program pointed to by `path`, with the arguments `args`. +/// Executes the program pointed to by `path`, with the arguments `args`, +/// and the environment variables `env_vars`. /// /// The first argument, by convention, /// should be the filename associated with the file being executed. -pub fn execv(path: P, args: &[P]) -> io::Result<()> { +pub fn execve(path: P, args: &[P], env_vars: &[P]) -> io::Result<()> { let arg_vec: Vec> = args .into_iter() .map(Arg::as_cow_c_str) .collect::>()?; - path.into_with_c_str(|path_cstr| imp::syscalls::execv(path_cstr, &arg_vec)) + let env_vec: Vec> = env_vars + .into_iter() + .map(Arg::as_cow_c_str) + .collect::>()?; + path.into_with_c_str(|path_cstr| imp::syscalls::execve(path_cstr, &arg_vec, &env_vec)) }