Commit c7b3765d authored by Jeremy Soller's avatar Jeremy Soller

Remove execve, replace with fexec

parent a198cb22
......@@ -143,7 +143,8 @@ pub extern fn userspace_init() {
assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));
syscall::exec(b"/bin/init", &[]).expect("failed to execute init");
let fd = syscall::open(b"/bin/init", syscall::flag::O_RDONLY).expect("failed to open init");
syscall::fexec(fd, &[], &[]).expect("failed to execute init");
panic!("init returned");
}
......
......@@ -191,13 +191,26 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
"clone({})",
b
),
SYS_EXIT => format!(
"exit({})",
b
),
//TODO: Cleanup, do not allocate
SYS_EXECVE => format!(
"execve({:?}, {:?})",
validate_slice(b as *const u8, c).map(ByteStr),
SYS_FEXEC => format!(
"fexec({}, {:?}, {:?})",
b,
validate_slice(
c as *const [usize; 2],
d
).map(|slice| {
slice.iter().map(|a|
validate_slice(a[0] as *const u8, a[1]).ok()
.and_then(|s| ::core::str::from_utf8(s).ok())
).collect::<Vec<Option<&str>>>()
}),
validate_slice(
d as *const [usize; 2],
e
e as *const [usize; 2],
f
).map(|slice| {
slice.iter().map(|a|
validate_slice(a[0] as *const u8, a[1]).ok()
......@@ -205,10 +218,6 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
).collect::<Vec<Option<&str>>>()
})
),
SYS_EXIT => format!(
"exit({})",
b
),
SYS_FUTEX => format!(
"futex({:#X} [{:?}], {}, {}, {}, {})",
b,
......
......@@ -64,6 +64,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u
SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
SYS_FCNTL => fcntl(fd, c, d),
SYS_FEVENT => fevent(fd, c),
SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?),
SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?),
SYS_FUNMAP => funmap(b),
_ => file_op(a, fd, c, d)
......@@ -98,7 +99,6 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u
SYS_KILL => kill(ContextId::from(b), c),
SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into),
SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?),
SYS_IOPL => iopl(b, stack),
SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
SYS_GETEGID => getegid(),
......
......@@ -2,7 +2,7 @@ use alloc::arc::Arc;
use alloc::boxed::Box;
use alloc::{BTreeMap, Vec};
use core::alloc::{Alloc, GlobalAlloc, Layout};
use core::{intrinsics, mem, str};
use core::{intrinsics, mem};
use core::ops::DerefMut;
use spin::Mutex;
......@@ -541,11 +541,11 @@ impl Drop for ExecFile {
}
fn exec_noreturn(
canonical: Box<[u8]>,
setuid: Option<u32>,
setgid: Option<u32>,
data: Box<[u8]>,
args: Box<[Box<[u8]>]>
args: Box<[Box<[u8]>]>,
vars: Box<[Box<[u8]>]>
) -> ! {
let entry;
let mut sp = ::USER_STACK_OFFSET + ::USER_STACK_SIZE - 256;
......@@ -557,7 +557,9 @@ fn exec_noreturn(
let mut context = context_lock.write();
// Set name
context.name = Arc::new(Mutex::new(canonical));
if let Some(name) = args.get(0) {
context.name = Arc::new(Mutex::new(name.clone()));
}
empty(&mut context, false);
......@@ -776,7 +778,7 @@ fn exec_noreturn(
unsafe { usermode(entry, sp, 0); }
}
pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
pub fn fexec(mut fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -> Result<usize> {
let mut args = Vec::new();
for arg_ptr in arg_ptrs {
let arg = validate_slice(arg_ptr[0] as *const u8, arg_ptr[1])?;
......@@ -784,17 +786,25 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
args.push(arg.to_vec().into_boxed_slice());
}
let (uid, gid, mut canonical) = {
let mut vars = Vec::new();
for var_ptr in var_ptrs {
let var = validate_slice(var_ptr[0] as *const u8, var_ptr[1])?;
// Argument must be moved into kernel space before exec unmaps all memory
vars.push(var.to_vec().into_boxed_slice());
}
let (uid, gid) = {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
(context.euid, context.egid, context.canonicalize(path))
(context.euid, context.egid)
};
let mut stat: Stat;
let mut data: Vec<u8>;
loop {
let file = ExecFile(syscall::open(&canonical, syscall::flag::O_RDONLY)?);
//loop
{
let file = ExecFile(fd);
stat = Stat::default();
syscall::file_op_mut_slice(syscall::number::SYS_FSTAT, file.0, &mut stat)?;
......@@ -819,34 +829,37 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
syscall::file_op_mut_slice(syscall::number::SYS_READ, file.0, &mut data)?;
drop(file);
if data.starts_with(b"#!") {
if let Some(line) = data[2..].split(|&b| b == b'\n').next() {
// Strip whitespace
let line = &line[line.iter().position(|&b| b != b' ')
.unwrap_or(0)..];
let executable = line.split(|x| *x == b' ').next().unwrap_or(b"");
let mut parts = line.split(|x| *x == b' ')
.map(|x| x.iter().cloned().collect::<Vec<_>>().into_boxed_slice())
.collect::<Vec<_>>();
if ! args.is_empty() {
args.remove(0);
}
parts.push(path.to_vec().into_boxed_slice());
parts.extend(args.iter().cloned());
args = parts;
canonical = {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
context.canonicalize(executable)
};
} else {
println!("invalid script {}", unsafe { str::from_utf8_unchecked(path) });
return Err(Error::new(ENOEXEC));
}
} else {
break;
}
// TODO: Move to userspace
// if data.starts_with(b"#!") {
// if let Some(line) = data[2..].split(|&b| b == b'\n').next() {
// // Strip whitespace
// let line = &line[line.iter().position(|&b| b != b' ')
// .unwrap_or(0)..];
// let executable = line.split(|x| *x == b' ').next().unwrap_or(b"");
// let mut parts = line.split(|x| *x == b' ')
// .map(|x| x.iter().cloned().collect::<Vec<_>>().into_boxed_slice())
// .collect::<Vec<_>>();
// if ! args.is_empty() {
// args.remove(0);
// }
// parts.push(path.to_vec().into_boxed_slice());
// parts.extend(args.iter().cloned());
// args = parts;
// let canonical = {
// let contexts = context::contexts();
// let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
// let context = context_lock.read();
// context.canonicalize(executable)
// };
//
// fd = syscall::open(&canonical, syscall::flag::O_RDONLY)?;
// } else {
// println!("invalid script {}", unsafe { str::from_utf8_unchecked(path) });
// return Err(Error::new(ENOEXEC));
// }
// } else {
// break;
// }
}
// Set UID and GID are determined after resolving any hashbangs
......@@ -871,7 +884,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
// argument pointer array and potential padding
//
// A limit of 4095 would mean a stack of (4095 + 1) * 8 * 2 = 65536, or 64KB
if args.len() > 4095 {
if (args.len() + vars.len()) > 4095 {
return Err(Error::new(E2BIG));
}
......@@ -894,19 +907,19 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
}
},
Err(err) => {
println!("exec: failed to execute {}: {}", unsafe { str::from_utf8_unchecked(path) }, err);
println!("fexec: failed to execute {}: {}", fd.into(), err);
return Err(Error::new(ENOEXEC));
}
}
// Drop so that usage is not allowed after unmapping context
drop(path);
drop(arg_ptrs);
drop(var_ptrs);
// This is the point of no return, quite literaly. Any checks for validity need
// to be done before, and appropriate errors returned. Otherwise, we have nothing
// to return to.
exec_noreturn(canonical.into_boxed_slice(), setuid, setgid, data.into_boxed_slice(), args.into_boxed_slice());
exec_noreturn(setuid, setgid, data.into_boxed_slice(), args.into_boxed_slice(), vars.into_boxed_slice());
}
pub fn exit(status: usize) -> ! {
......
Subproject commit 0ab552da9a9587b360b5d9991ed9921300e5667b
Subproject commit 66e34aea2ee48e55a023861595064df26f8573b9
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment