Remove execve, replace with fexec
This commit is contained in:
@@ -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(
|
||||
d as *const [usize; 2],
|
||||
e
|
||||
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(
|
||||
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) -> ! {
|
||||
|
||||
2
syscall
2
syscall
Submodule syscall updated: 0ab552da9a...66e34aea2e
Reference in New Issue
Block a user