Make code safer by disallowing NULL argv, empty argv and NULL values for pointer arguments to functions
This commit is contained in:
@@ -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<Self::Item> {
|
||||
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::<Action>::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;
|
||||
}
|
||||
|
||||
+39
-6
@@ -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<NulTerminated<*mut c_char>>,
|
||||
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 },
|
||||
)
|
||||
} {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<NulTerminated<*mut c_char>>,
|
||||
use_path: bool,
|
||||
) -> Result<pid_t>;
|
||||
|
||||
|
||||
+19
-26
@@ -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<NulTerminated<*mut c_char>>,
|
||||
use_path: bool,
|
||||
) -> Result<pid_t> {
|
||||
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)?;
|
||||
|
||||
Reference in New Issue
Block a user