diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index 17aad17f45f6e3729af9ed6eb73007f227a310c8..73c8102e4cbfddb265d24e3a3b9e161f5a365388 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -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? diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index 9c1cb8fc132dee1e886f26b63961a8706f6895ee..1b99048652fb54fe2e4c6c80b421d45f18827519 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -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!(); diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 907de338f5fa1b3e952e6cc961e78dfc5c9c4ce2..266ffec1068b2a1c8c64932f1331c0c61b1dd65e 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -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 } }