* Fix bug that caused pid of the child process to be returned instead of 0 or errorno

* Add `same_process` field to not change the address space when `fexec_impl` is called on a different process
This commit is contained in:
R Aadarsh
2026-05-15 16:11:36 +05:30
parent 1bc472e7e1
commit 119f078216
4 changed files with 58 additions and 18 deletions
+10 -4
View File
@@ -63,6 +63,8 @@ pub struct ExtraInfo<'a> {
pub ns_fd: Option<usize>,
/// CWD handle
pub cwd_fd: Option<usize>,
/// If the process for which the image is to be loaded the same as the currently running process
pub same_process: bool,
}
pub fn fexec_impl(
@@ -74,7 +76,7 @@ pub fn fexec_impl(
envs: &[&[u8]],
extrainfo: &ExtraInfo,
interp_override: Option<InterpOverride>,
) -> Result<FexecResult> {
) -> Result<Option<FexecResult>> {
// Here, we do the minimum part of loading an application, which is what the kernel used to do.
// We load the executable into memory (albeit at different offsets in this executable), fix
// some misalignments, and then switch address space.
@@ -235,7 +237,7 @@ pub fn fexec_impl(
}
if let Some(interpreter_path) = interpreter {
return Ok(FexecResult::Interp {
return Ok(Some(FexecResult::Interp {
path: interpreter_path,
interp_override: InterpOverride {
at_entry: base_addr + header.e_entry as usize,
@@ -246,7 +248,7 @@ pub fn fexec_impl(
min_mmap_addr,
grants_fd: grants_fd.take(),
},
});
}));
}
mmap_anon_remote(
@@ -495,7 +497,11 @@ pub fn fexec_impl(
// Dropping this FD will cause the address space switch.
drop(addrspace_selection_fd);
unreachable!();
if extrainfo.same_process {
unreachable!();
} else {
Ok(None)
}
}
fn write_usizes<const N: usize>(fd: &FdGuardUpper, usizes: [usize; N]) -> Result<usize> {
fd.write(unsafe { plain::as_bytes(&usizes) })
+17 -9
View File
@@ -19,13 +19,14 @@ use crate::{
};
fn spawn(
pid: Option<&mut pid_t>,
mut program: &str,
file_actions: Option<&posix_spawn_file_actions_t>,
spawn_attr: Option<&posix_spawnattr_t>,
argv: *const *mut c_char,
envp: *const *mut c_char,
use_path: bool,
) -> Result<pid_t> {
) -> Result<()> {
if use_path {
let path_env = unsafe {
CStr::from_ptr(getenv("PATH".as_ptr() as *const c_char))
@@ -57,12 +58,17 @@ fn spawn(
envp,
use_path,
)
.map(|v| {
if let Some(pid) = pid {
*pid = v;
}
})
}
}
#[unsafe(no_mangle)]
pub extern "C" fn posix_spawn(
pid: *const pid_t,
pid: *mut pid_t,
program: *const c_char,
file_actions: *const posix_spawn_file_actions_t,
spawn_attr: *const posix_spawnattr_t,
@@ -71,7 +77,8 @@ pub extern "C" fn posix_spawn(
) -> c_int {
let program = unsafe { CStr::from_ptr(program).to_str().unwrap() };
match spawn(
if let Err(e) = spawn(
unsafe { pid.as_mut() },
program,
unsafe { file_actions.as_ref() },
unsafe { spawn_attr.as_ref() },
@@ -79,14 +86,14 @@ pub extern "C" fn posix_spawn(
envp,
false,
) {
Ok(v) => v,
Err(e) => e.0,
return e.0;
}
0
}
#[unsafe(no_mangle)]
pub extern "C" fn posix_spawnp(
pid: *const pid_t,
pid: *mut pid_t,
program: *const c_char,
file_actions: *const posix_spawn_file_actions_t,
spawn_attr: *const posix_spawnattr_t,
@@ -95,7 +102,8 @@ pub extern "C" fn posix_spawnp(
) -> c_int {
let program = unsafe { CStr::from_ptr(program).to_str().unwrap() };
match spawn(
if let Err(e) = spawn(
unsafe { pid.as_mut() },
program,
unsafe { file_actions.as_ref() },
unsafe { spawn_attr.as_ref() },
@@ -103,7 +111,7 @@ pub extern "C" fn posix_spawnp(
envp,
true,
) {
Ok(v) => v,
Err(e) => e.0,
return e.0;
}
0
}
+3 -1
View File
@@ -38,7 +38,8 @@ fn fexec_impl(
envs,
extrainfo,
interp_override,
)?;
)?
.unwrap();
// According to elf(5), PT_INTERP requires that the interpreter path be
// null-terminated. Violating this should therefore give the "format error" ENOEXEC.
@@ -238,6 +239,7 @@ pub fn execve(
cwd_fd: super::path::current_dir()
.ok()
.map(|fd| fd.as_ref().unwrap().fd.as_raw_fd()),
same_process: true,
};
fexec_impl(
+28 -4
View File
@@ -61,7 +61,11 @@ use crate::{
free,
sys::timer::{TIMERS, timer_routine, timer_update_wake_time},
},
sync::rwlock::RwLock,
sync::{
self, Mutex,
rwlock::RwLock,
sys::timer::{timer_routine, timer_update_wake_time},
},
};
pub use redox_rt::proc::FdGuard;
@@ -1225,6 +1229,7 @@ impl Pal for Sys {
cwd_fd: path::current_dir()
.ok()
.map(|fd| fd.as_ref().unwrap().fd.as_raw_fd()),
same_process: false,
};
let mut args = Vec::new();
@@ -1244,7 +1249,10 @@ impl Pal for Sys {
envp = unsafe { envp.add(1) };
}
redox_rt::proc::fexec_impl(
if let Some(redox_rt::proc::FexecResult::Interp {
path: interp_path,
interp_override,
}) = redox_rt::proc::fexec_impl(
FdGuard::new(executable.fd as usize).to_upper().unwrap(),
&child.thr_fd,
&proc_fd,
@@ -1253,8 +1261,24 @@ impl Pal for Sys {
envs.as_slice(),
&extra_info,
None,
)
.map_err(|_| syscall::error::Error::new(syscall::error::ENOEXEC))?;
)? {
let interp_path = CStr::from_bytes_with_nul(&interp_path)
.map_err(|_| platform::Errno(syscall::error::ENOEXEC))?;
let interpreter = File::open(interp_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC)
.map_err(|_| platform::Errno(syscall::error::ENOEXEC))?;
redox_rt::proc::fexec_impl(
FdGuard::new(interpreter.fd as usize).to_upper().unwrap(),
&child.thr_fd,
&proc_fd,
program.to_bytes(),
args.as_slice(),
envs.as_slice(),
&extra_info,
Some(interp_override),
)?;
}
Ok(i32::try_from(child.pid).unwrap())
}