diff --git a/src/header/spawn/file_actions.rs b/src/header/spawn/file_actions.rs index a501086b83..fcf4cde770 100644 --- a/src/header/spawn/file_actions.rs +++ b/src/header/spawn/file_actions.rs @@ -1,4 +1,4 @@ -use core::{mem::ManuallyDrop, ptr::null_mut}; +use core::{mem::ManuallyDrop, slice}; use alloc::{ffi::CString, vec::Vec}; @@ -13,7 +13,6 @@ const CHDIR: c_char = 3; const FCHDIR: c_char = 4; const DUP2: c_char = 5; -#[repr(C)] #[derive(Debug, Clone)] pub enum Action { Open { @@ -31,15 +30,19 @@ pub enum Action { #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct posix_spawn_file_actions_t { - file_actions: *mut Action, + file_actions: usize, length: usize, capacity: usize, } impl posix_spawn_file_actions_t { pub fn add_action(&mut self, action: Action) { - let v = unsafe { &mut Vec::from_raw_parts(self.file_actions, self.length, self.capacity) }; + let mut v = unsafe { + Vec::from_raw_parts(self.file_actions as *mut Action, self.length, self.capacity) + }; v.push(action); + let raw = v.into_raw_parts(); + (self.file_actions, self.length, self.capacity) = (raw.0.addr(), raw.1, raw.2); } } @@ -53,10 +56,9 @@ impl Iterator for FileActionsIter { fn next(&mut self) -> Option { let actions = unsafe { - &Vec::from_raw_parts( - self.actions.file_actions, + slice::from_raw_parts( + self.actions.file_actions as *const Action, self.actions.length, - self.actions.capacity, ) }; let e = actions.get(self.curr)?; @@ -80,10 +82,11 @@ impl<'a> IntoIterator for &'a posix_spawn_file_actions_t { #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_init( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, ) -> c_int { - let mut v = ManuallyDrop::new(Vec::new()); - file_actions.file_actions = v.as_mut_ptr(); + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; + let mut v = ManuallyDrop::new(Vec::::new()); + file_actions.file_actions = v.as_mut_ptr().addr(); file_actions.capacity = v.capacity(); file_actions.length = 0; 0 @@ -91,30 +94,35 @@ pub unsafe extern "C" fn posix_spawn_file_actions_init( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_destroy( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; let v = unsafe { - &Vec::from_raw_parts( - file_actions.file_actions, + Vec::from_raw_parts( + file_actions.file_actions as *mut Action, file_actions.length, file_actions.capacity, ) }; file_actions.capacity = 0; file_actions.length = 0; - file_actions.file_actions = null_mut(); + file_actions.file_actions = 0; 0 } #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addopen( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, fd: c_int, path: *const c_char, oflag: c_int, mode: mode_t, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; + if path.is_null() { + panic!("path cannot be NULL"); + } if fd < 0 { return EBADF; } @@ -133,9 +141,10 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addopen( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addclose( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, fd: c_int, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; if fd < 0 { return EBADF; } @@ -145,9 +154,13 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addclose( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, path: *const c_char, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; + if path.is_null() { + panic!("path cannot be NULL"); + } file_actions.add_action(Action::Chdir(unsafe { if path.is_null() { CString::new("").unwrap() @@ -160,9 +173,10 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addchdir( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, fd: c_int, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; if fd < 0 { return EBADF; } @@ -172,10 +186,11 @@ pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_spawn_file_actions_adddup2( - file_actions: &mut posix_spawn_file_actions_t, + file_actions: *mut posix_spawn_file_actions_t, fd: c_int, new: c_int, ) -> c_int { + let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") }; if fd < 0 || new < 0 { return EBADF; } diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index 83d6674efb..79c4e305dc 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -17,6 +17,7 @@ use crate::{ errno::ENOENT, stdlib::getenv, }, + iter::NulTerminated, platform::{ self, Pal, sys::path, @@ -29,8 +30,8 @@ unsafe fn spawn( mut program: String, file_actions: Option<&posix_spawn_file_actions_t>, spawn_attr: Option<&posix_spawnattr_t>, - argv: *const *mut c_char, - envp: Option<*const *mut c_char>, + argv: NulTerminated<*mut c_char>, + envp: Option>, use_path: bool, ) -> Result<()> { let original_cwd = path::clone_cwd().unwrap().to_string(); @@ -101,7 +102,23 @@ pub unsafe extern "C" fn posix_spawn( argv: *const *mut c_char, envp: *const *mut c_char, ) -> c_int { - let program = unsafe { CStr::from_ptr(path).to_str().unwrap().to_string() }; + let argv = { + if argv.is_null() { + panic!("argv cannot be NULL") + } else { + if unsafe { (*argv).is_null() } { + panic!("argv must contain the program name"); + } + unsafe { NulTerminated::new(argv).unwrap() } + } + }; + let envp = unsafe { NulTerminated::new(envp) }; + let program = unsafe { + CStr::from_ptr(path) + .to_str() + .expect("path cannot be NULL") + .to_string() + }; if let Err(e) = unsafe { spawn( @@ -110,7 +127,7 @@ pub unsafe extern "C" fn posix_spawn( file_actions.as_ref(), attrp.as_ref(), argv, - if envp.is_null() { None } else { Some(envp) }, + envp, false, ) } { @@ -128,7 +145,23 @@ pub unsafe extern "C" fn posix_spawnp( argv: *const *mut c_char, envp: *const *mut c_char, ) -> c_int { - let program = unsafe { CStr::from_ptr(path).to_str().unwrap().to_string() }; + let argv = { + if argv.is_null() { + panic!("argv cannot be NULL") + } else { + if unsafe { (*argv).is_null() } { + panic!("argv must contain the program name"); + } + unsafe { NulTerminated::new(argv).unwrap() } + } + }; + let envp = unsafe { NulTerminated::new(envp) }; + let program = unsafe { + CStr::from_ptr(path) + .to_str() + .expect("path cannot be NULL") + .to_string() + }; if let Err(e) = unsafe { spawn( @@ -137,7 +170,7 @@ pub unsafe extern "C" fn posix_spawnp( file_actions.as_ref(), attrp.as_ref(), argv, - if envp.is_null() { None } else { Some(envp) }, + envp, if program.contains('/') { false } else { true }, ) } { diff --git a/src/iter.rs b/src/iter.rs index 369d2dadc8..4b3cc6c872 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -30,6 +30,12 @@ unsafe impl Zero for wchar_t { } } +unsafe impl Zero for *mut c_char { + fn is_zero(&self) -> bool { + self.is_null() + } +} + /// An iterator over a nul-terminated buffer. /// /// This is intended to allow safe, ergonomic iteration over C-style byte and diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index 83e380610e..194535eb17 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -15,6 +15,7 @@ use crate::{ sys_utsname::utsname, time::{itimerspec, timespec}, }, + iter::NulTerminated, ld_so::tcb::OsSpecific, out::Out, pthread, @@ -437,8 +438,8 @@ pub trait Pal { program: CStr, fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>, fat: Option<&crate::header::spawn::posix_spawnattr_t>, - argv: *const *mut c_char, - envp: Option<*const *mut c_char>, + argv: NulTerminated<*mut c_char>, + envp: Option>, use_path: bool, ) -> Result; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 9672ec6141..50346fce4c 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -41,7 +41,6 @@ use crate::{ signal::{NSIG, SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD, SIGRTMIN, sigevent}, stdio::RENAME_NOREPLACE, stdlib::posix_memalign, - string::strlen, sys_file, sys_mman::{MAP_ANONYMOUS, PROT_READ, PROT_WRITE}, sys_random, @@ -57,6 +56,7 @@ use crate::{ unistd::{F_OK, R_OK, SEEK_CUR, SEEK_SET, W_OK, X_OK}, }, io::{self, BufReader, prelude::*}, + iter::NulTerminated, ld_so::tcb::OsSpecific, out::Out, platform::{ @@ -1205,8 +1205,8 @@ impl Pal for Sys { program: CStr, fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>, fat: Option<&crate::header::spawn::posix_spawnattr_t>, - mut argv: *const *mut c_char, - envp: Option<*const *mut c_char>, + argv: NulTerminated<*mut c_char>, + envp: Option>, use_path: bool, ) -> Result { use crate::header::spawn::Flags; @@ -1230,31 +1230,25 @@ 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) }; - args.push(unsafe { slice::from_raw_parts(arg as *const u8, len) }); - argv = unsafe { argv.add(1) }; + for arg in argv { + args.push(unsafe { CStr::from_ptr(*arg).to_chars() }); } - 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) }; + if let Some(envp) = envp { + for env in envp { + envs.push(unsafe { CStr::from_ptr(*env).to_chars() }); } } + let mut program_name = String::new(); + + program_name = redox_path::canonicalize_using_cwd( + Some(original_cwd.as_str()), + str::from_utf8(args[0]).unwrap(), + ) + .ok_or(Errno(ENOENT))?; + args[0] = program_name.as_bytes(); + let new_file_table = child.thr_fd.dup(b"filetable")?; if let Some(fac) = fac { @@ -1286,10 +1280,9 @@ impl Pal for Sys { )?; } crate::header::spawn::Action::Chdir(path) => { - let path = path.to_str().unwrap(); - cwd = path.to_string(); + cwd = path.to_str().unwrap().to_string(); - path::chdir(path)?; + path::chdir(path.to_str().unwrap())?; } crate::header::spawn::Action::FChdir(fd) => { path::fchdir(fd)?;