WIP: Support setuid/setgid
This commit is contained in:
@@ -124,6 +124,7 @@ pub fn static_init(sp: &'static Stack) {
|
||||
tcb.masters_len = mem::size_of::<Master>();
|
||||
tcb.copy_masters().expect_notls("failed to copy TLS master data");
|
||||
tcb.activate();
|
||||
|
||||
}
|
||||
|
||||
//TODO: Warning on multiple TLS sections?
|
||||
|
||||
@@ -11,6 +11,8 @@ use syscall::{
|
||||
flag::{AT_ENTRY, AT_NULL, AT_PHDR, AT_PHENT, AT_PHNUM, MapFlags},
|
||||
};
|
||||
|
||||
use crate::fs::File;
|
||||
|
||||
fn read_all(fd: usize, offset: u64, buf: &mut [u8]) -> Result<()> {
|
||||
syscall::lseek(fd, offset as isize, syscall::SEEK_SET).unwrap();
|
||||
|
||||
@@ -63,7 +65,8 @@ const PAGE_SIZE: usize = 4096;
|
||||
|
||||
const FD_ANONYMOUS: usize = !0;
|
||||
|
||||
pub fn fexec_impl(fd: usize, path: &[u8], args: &[&[u8]], envs: &[&[u8]], args_envs_size_without_nul: usize) -> Result<usize> {
|
||||
pub fn fexec_impl(file: File, path: &[u8], args: &[&[u8]], envs: &[&[u8]], args_envs_size_without_nul: usize) -> Result<usize> {
|
||||
let fd = *file as usize;
|
||||
let total_args_envs_size = args_envs_size_without_nul + args.len() + envs.len();
|
||||
|
||||
// Here, we do the minimum part of loading an application, which is what the kernel used to do.
|
||||
@@ -261,10 +264,11 @@ pub fn fexec_impl(fd: usize, path: &[u8], args: &[&[u8]], envs: &[&[u8]], args_e
|
||||
unsafe { crate::ld_so::tcb::Tcb::deactivate(); }
|
||||
|
||||
// TODO: Restore old name if exec failed?
|
||||
if let Ok(fd) = syscall::open("thisproc:current/name", syscall::O_WRONLY) {
|
||||
let _ = syscall::write(fd, path);
|
||||
let _ = syscall::close(fd);
|
||||
if let Ok(name_fd) = syscall::open("thisproc:current/name", syscall::O_WRONLY) {
|
||||
let _ = syscall::write(name_fd, path);
|
||||
let _ = syscall::close(name_fd);
|
||||
}
|
||||
drop(file);
|
||||
|
||||
syscall::exec(&memranges, instruction_ptr, sp)?;
|
||||
unreachable!();
|
||||
|
||||
@@ -218,7 +218,9 @@ impl Pal for Sys {
|
||||
mut argv: *const *mut c_char,
|
||||
mut envp: *const *mut c_char,
|
||||
) -> c_int {
|
||||
let mut file = match File::open(path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) {
|
||||
// NOTE: We must omit O_CLOEXEC and close manually, otherwise it will be closed before we
|
||||
// have even read it!
|
||||
let mut file = match File::open(path, fcntl::O_RDONLY) {
|
||||
Ok(file) => file,
|
||||
Err(_) => return -1,
|
||||
};
|
||||
@@ -309,7 +311,7 @@ impl Pal for Sys {
|
||||
Ok(cstring) => cstring,
|
||||
Err(_) => return -1,
|
||||
};
|
||||
file = match File::open(&cstring, fcntl::O_RDONLY | fcntl::O_CLOEXEC) {
|
||||
file = match File::open(&cstring, fcntl::O_RDONLY) {
|
||||
Ok(file) => file,
|
||||
Err(_) => return -1,
|
||||
};
|
||||
@@ -351,6 +353,32 @@ impl Pal for Sys {
|
||||
envp = envp.add(1);
|
||||
}
|
||||
|
||||
// Close all O_CLOEXEC file descriptors. TODO: close_range?
|
||||
{
|
||||
let name = CStr::from_bytes_with_nul(b"thisproc:current/files\0").expect("string should be valid");
|
||||
let files_fd = match File::open(name, fcntl::O_RDONLY) {
|
||||
Ok(f) => f,
|
||||
Err(_) => return -1,
|
||||
};
|
||||
for line in BufReader::new(files_fd).lines() {
|
||||
let line = match line {
|
||||
Ok(l) => l,
|
||||
Err(_) => break,
|
||||
};
|
||||
let fd = match line.parse::<usize>() {
|
||||
Ok(f) => f,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let flags = Self::fcntl(fd as c_int, fcntl::F_GETFD, 0);
|
||||
if flags != -1 {
|
||||
if flags & fcntl::O_CLOEXEC == fcntl::O_CLOEXEC {
|
||||
let _ = Self::close(fd as c_int);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !is_interpreted && wants_setugid {
|
||||
let name = CStr::from_bytes_with_nul(b"escalate:\0").expect("string should be valid");
|
||||
// We are now going to invoke `escalate:` rather than loading the program ourselves.
|
||||
@@ -368,7 +396,7 @@ impl Pal for Sys {
|
||||
// descriptor and not a path will allow escalated to run in a limited namespace.
|
||||
//
|
||||
// TODO: Plus, at this point fexecve is not implemented (but specified in
|
||||
// POSIX.1-2008), and to avoid bad syscalls such as fpath passing a file descriptor
|
||||
// POSIX.1-2008), and to avoid bad syscalls such as fpath, passing a file descriptor
|
||||
// would be better.
|
||||
escalate_fd.write_all(path.to_bytes());
|
||||
|
||||
@@ -382,13 +410,14 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
// escalated will take care of the rest when responding to SYS_CLOSE.
|
||||
// FIXME: close escalate_fd
|
||||
if escalate_fd.write(&[]).is_err() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
unreachable!()
|
||||
} else {
|
||||
e(self::exec::fexec_impl(*file as usize, path.to_bytes(), &args, &envs, args_envs_size_without_nul)) as c_int
|
||||
e(self::exec::fexec_impl(file, path.to_bytes(), &args, &envs, args_envs_size_without_nul)) as c_int
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user