* Make posix_spawnp consider the program argument as a path if it contains a slash

* Remove existence and file type check

* Make envp optional

* Ensure that the CWD of the calling process is same before and after spawning
This commit is contained in:
R Aadarsh
2026-05-28 17:17:57 +05:30
parent 38af072426
commit 2df7484e6c
6 changed files with 67 additions and 63 deletions
+20 -13
View File
@@ -19,6 +19,7 @@ use crate::{
},
platform::{
self, Pal,
sys::path,
types::{c_char, c_int, pid_t},
},
};
@@ -29,9 +30,11 @@ fn spawn(
file_actions: Option<&posix_spawn_file_actions_t>,
spawn_attr: Option<&posix_spawnattr_t>,
argv: *const *mut c_char,
envp: *const *mut c_char,
envp: Option<*const *mut c_char>,
use_path: bool,
) -> Result<()> {
let original_cwd = path::clone_cwd().unwrap().to_string();
if use_path {
let path = unsafe { getenv(c"PATH".as_ptr()) };
let path_env = unsafe { CStr::from_nullable_ptr(path).unwrap().to_str().unwrap() };
@@ -79,6 +82,10 @@ fn spawn(
if let Some(pid) = pid {
*pid = v;
}
})
.map_err(|e| {
path::chdir(original_cwd.as_str()).unwrap();
e
})?;
}
@@ -88,21 +95,21 @@ fn spawn(
#[unsafe(no_mangle)]
pub extern "C" fn posix_spawn(
pid: *mut pid_t,
program: *const c_char,
path: *const c_char,
file_actions: *const posix_spawn_file_actions_t,
spawn_attr: *const posix_spawnattr_t,
attrp: *const posix_spawnattr_t,
argv: *const *mut c_char,
envp: *const *mut c_char,
) -> c_int {
let program = unsafe { CStr::from_ptr(program).to_str().unwrap().to_string() };
let program = unsafe { CStr::from_ptr(path).to_str().unwrap().to_string() };
if let Err(e) = spawn(
unsafe { pid.as_mut() },
program,
unsafe { file_actions.as_ref() },
unsafe { spawn_attr.as_ref() },
unsafe { attrp.as_ref() },
argv,
envp,
if envp.is_null() { None } else { Some(envp) },
false,
) {
return e.0;
@@ -113,22 +120,22 @@ pub extern "C" fn posix_spawn(
#[unsafe(no_mangle)]
pub extern "C" fn posix_spawnp(
pid: *mut pid_t,
program: *const c_char,
path: *const c_char,
file_actions: *const posix_spawn_file_actions_t,
spawn_attr: *const posix_spawnattr_t,
attrp: *const posix_spawnattr_t,
argv: *const *mut c_char,
envp: *const *mut c_char,
) -> c_int {
let program = unsafe { CStr::from_ptr(program).to_str().unwrap().to_string() };
let program = unsafe { CStr::from_ptr(path).to_str().unwrap().to_string() };
if let Err(e) = spawn(
unsafe { pid.as_mut() },
program,
program.clone(),
unsafe { file_actions.as_ref() },
unsafe { spawn_attr.as_ref() },
unsafe { attrp.as_ref() },
argv,
envp,
true,
if envp.is_null() { None } else { Some(envp) },
if program.contains('/') { false } else { true },
) {
return e.0;
}
+1 -1
View File
@@ -438,7 +438,7 @@ pub trait Pal {
fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>,
fat: Option<&crate::header::spawn::posix_spawnattr_t>,
argv: *const *mut c_char,
envp: *const *mut c_char,
envp: Option<*const *mut c_char>,
use_path: bool,
) -> Result<pid_t>;
+28 -22
View File
@@ -1,3 +1,4 @@
use alloc::string::String;
use core::{
convert::TryFrom,
mem::{self, size_of},
@@ -29,13 +30,13 @@ use crate::{
header::{
errno::{
EBADF, EBADFD, EEXIST, EFAULT, EFBIG, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT,
ENOEXEC, ENOMEM, ENOSYS, ENOTDIR, EOPNOTSUPP, EPERM,
ENOEXEC, ENOMEM, ENOSYS, EOPNOTSUPP, EPERM,
},
fcntl::{
self, AT_EACCESS, AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_FOLLOW, F_GETLK,
F_OFD_GETLK, F_OFD_SETLK, F_RDLCK, F_SETLK, F_SETLKW, F_UNLCK, F_WRLCK, flock,
},
limits::{self, NAME_MAX},
limits::{self},
pthread::{pthread_cancel, pthread_create},
signal::{NSIG, SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD, SIGRTMIN, sigevent},
stdio::RENAME_NOREPLACE,
@@ -46,7 +47,7 @@ use crate::{
sys_random,
sys_resource::{RLIM_INFINITY, rlimit, rusage},
sys_select::timeval,
sys_stat::{self, S_ISVTX, stat},
sys_stat::{S_ISVTX, stat},
sys_statvfs::statvfs,
sys_time::timezone,
sys_utsname::{UTSLENGTH, utsname},
@@ -1205,7 +1206,7 @@ impl Pal for Sys {
fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>,
fat: Option<&crate::header::spawn::posix_spawnattr_t>,
mut argv: *const *mut c_char,
mut envp: *const *mut c_char,
envp: Option<*const *mut c_char>,
use_path: bool,
) -> Result<pid_t> {
use crate::header::spawn::Flags;
@@ -1214,7 +1215,6 @@ impl Pal for Sys {
let executable = File::open(program, fcntl::O_RDONLY)?;
let original_cwd = path::clone_cwd().unwrap().to_string();
let mut cwd = original_cwd.clone();
cwd.reserve_exact(NAME_MAX - cwd.len());
let proc_fd = child.proc_fd.unwrap();
let curr_proc_fd = redox_rt::current_proc_fd();
let file_table = RtTcb::current()
@@ -1230,6 +1230,15 @@ impl Pal for Sys {
let mut args = Vec::new();
let mut envs = Vec::new();
let len = unsafe { strlen(*argv) };
let program_name =
str::from_utf8(unsafe { slice::from_raw_parts(*argv as *const u8, len) }).unwrap();
let program_name: String =
redox_path::canonicalize_using_cwd(Some(original_cwd.as_str()), program_name)
.ok_or(Errno(ENOENT))?;
argv = unsafe { argv.add(1) };
args.push(program_name.as_bytes());
while unsafe { !(*argv).is_null() } {
let arg = unsafe { *argv };
let len = unsafe { strlen(arg) };
@@ -1237,11 +1246,13 @@ impl Pal for Sys {
argv = unsafe { argv.add(1) };
}
while unsafe { !(*envp).is_null() } {
let env = unsafe { *envp };
let len = unsafe { strlen(env) };
envs.push(unsafe { slice::from_raw_parts(env as *const u8, len) });
envp = unsafe { envp.add(1) };
if let Some(mut envp) = envp {
while unsafe { !(*envp).is_null() } {
let env = unsafe { *envp };
let len = unsafe { strlen(env) };
envs.push(unsafe { slice::from_raw_parts(env as *const u8, len) });
envp = unsafe { envp.add(1) };
}
}
let new_file_table = child.thr_fd.dup(b"filetable")?;
@@ -1273,13 +1284,8 @@ impl Pal for Sys {
}
crate::header::spawn::Operation::Chdir(path) => {
let path = unsafe { CStr::from_ptr(path) };
let mut stat = sys_stat::stat::default();
let fd = Sys::stat(path, Out::from_mut(&mut stat))?;
if sys_stat::S_IFDIR & sys_stat::S_IFMT != sys_stat::S_IFDIR {
return Err(Errno(ENOTDIR));
}
cwd = path.to_str().unwrap().to_string();
path::chdir(cwd.as_str())?;
}
crate::header::spawn::Operation::FChdir(fd) => {
@@ -1299,14 +1305,14 @@ impl Pal for Sys {
}
}
}
new_file_table.call_wo(
&[],
syscall::CallFlags::empty(),
&[syscall::flag::FileTableVerb::CloseCloExec as u64],
)?;
}
new_file_table.call_wo(
&[],
syscall::CallFlags::empty(),
&[syscall::flag::FileTableVerb::CloseCloExec as u64],
)?;
let mut extra_info = redox_rt::proc::ExtraInfo {
cwd: Some(cwd.as_bytes()),
sigignmask: redox_rt::signal::get_sigignmask_to_inherit(),