diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 9aa0d90b360766655fb5ff32106203c36f87aad1..106fadc264738dc804a7cc1276f9b8d9408e8f9a 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -143,6 +143,7 @@ pub fn initialize_freestanding() { page.tcb_ptr = page; page.tcb_len = syscall::PAGE_SIZE; page.tls_end = (page as *mut Tcb).cast(); + *page.os_specific.thr_fd.get_mut() = None; #[cfg(not(target_arch = "aarch64"))] unsafe { diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index edd90eb1c6f3b30bc9ec1dae279001e33481f4ad..360c18a14b73e6f33550a859a2e21ab1fba20ef7 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -45,6 +45,8 @@ pub struct InterpOverride { pub struct ExtraInfo<'a> { pub cwd: Option<&'a [u8]>, + // Default scheme for the process + pub default_scheme: Option<&'a [u8]>, // POSIX states that while sigactions are reset, ignored sigactions will remain ignored. pub sigignmask: u64, // POSIX also states that the sigprocmask must be preserved across execs. @@ -351,8 +353,9 @@ where )?; push(AT_PHENT)?; - let total_args_envs_auxvpointee_size = - total_args_envs_size + extrainfo.cwd.map_or(0, |s| s.len() + 1); + let total_args_envs_auxvpointee_size = total_args_envs_size + + extrainfo.cwd.map_or(0, |s| s.len() + 1) + + extrainfo.default_scheme.map_or(0, |s| s.len() + 1); let args_envs_size_aligned = total_args_envs_auxvpointee_size.next_multiple_of(PAGE_SIZE); let target_args_env_address = find_free_target_addr(&tree, args_envs_size_aligned).ok_or(Error::new(ENOMEM))?; @@ -392,10 +395,18 @@ where if let Some(cwd) = extrainfo.cwd { push(append(cwd)?)?; - push(AT_REDOX_INITIALCWD_PTR)?; + push(AT_REDOX_INITIAL_CWD_PTR)?; push(cwd.len())?; - push(AT_REDOX_INITIALCWD_LEN)?; + push(AT_REDOX_INITIAL_CWD_LEN)?; } + + if let Some(default_scheme) = extrainfo.default_scheme { + push(append(default_scheme)?)?; + push(AT_REDOX_INITIAL_DEFAULT_SCHEME_PTR)?; + push(default_scheme.len())?; + push(AT_REDOX_INITIAL_DEFAULT_SCHEME_LEN)?; + } + #[cfg(target_pointer_width = "32")] { push((extrainfo.sigignmask >> 32) as usize)?; diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index 0abbcdad18fe989ee52fe7e54472c5805c5db380..981fea243aa2d79cdba5b2c4665d2ef6a1d0c003 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -102,13 +102,21 @@ pub unsafe extern "C" fn chdir(path: *const c_char) -> c_int { } #[no_mangle] -pub extern "C" fn chroot(path: *const c_char) -> c_int { +pub unsafe extern "C" fn chroot(path: *const c_char) -> c_int { // TODO: Implement platform::ERRNO.set(crate::header::errno::EPERM); -1 } +#[no_mangle] +pub unsafe extern "C" fn set_default_scheme(scheme: *const c_char) -> c_int { + let scheme = CStr::from_ptr(scheme); + Sys::set_default_scheme(scheme) + .map(|_| 0) + .or_minus_one_errno() +} + #[no_mangle] pub unsafe extern "C" fn chown(path: *const c_char, owner: uid_t, group: gid_t) -> c_int { let path = CStr::from_ptr(path); diff --git a/src/platform/auxv_defs.rs b/src/platform/auxv_defs.rs index d26d3e55f66fe19899fd274a049083d4108e593c..814eab24994935e3fb0e928eb54d670c3143c870 100644 --- a/src/platform/auxv_defs.rs +++ b/src/platform/auxv_defs.rs @@ -28,9 +28,9 @@ pub const AT_EXECFN: usize = 31; /* Filename of executable. */ #[cfg(target_os = "redox")] // XXX: The name AT_CWD is already used in openat... for a completely different purpose. -pub const AT_REDOX_INITIALCWD_PTR: usize = 32; +pub const AT_REDOX_INITIAL_CWD_PTR: usize = 32; #[cfg(target_os = "redox")] -pub const AT_REDOX_INITIALCWD_LEN: usize = 33; +pub const AT_REDOX_INITIAL_CWD_LEN: usize = 33; #[cfg(target_os = "redox")] pub const AT_REDOX_INHERITED_SIGIGNMASK: usize = 34; @@ -40,3 +40,8 @@ pub const AT_REDOX_INHERITED_SIGIGNMASK_HI: usize = 35; pub const AT_REDOX_INHERITED_SIGPROCMASK: usize = 36; #[cfg(all(target_os = "redox", target_pointer_width = "32"))] pub const AT_REDOX_INHERITED_SIGPROCMASK_HI: usize = 37; + +#[cfg(target_os = "redox")] +pub const AT_REDOX_INITIAL_DEFAULT_SCHEME_PTR: usize = 38; +#[cfg(target_os = "redox")] +pub const AT_REDOX_INITIAL_DEFAULT_SCHEME_LEN: usize = 39; diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index c2f1d4b8afc820e07c6c18d6839c1042995a49e6..0646f1b78c434719313ee00336de7b091c3fb41f 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -1,5 +1,5 @@ -use crate::io::Write; -use core::{arch::asm, mem::offset_of, ptr}; +use crate::{header::errno::EOPNOTSUPP, io::Write}; +use core::{arch::asm, ptr}; use super::{types::*, Pal, ERRNO}; use crate::{ @@ -100,6 +100,10 @@ impl Pal for Sys { e(unsafe { syscall!(CHDIR, path.as_ptr()) }) as c_int } + fn set_default_scheme(scheme: CStr) -> Result<(), Errno> { + Err(Errno(EOPNOTSUPP)) + } + fn chmod(path: CStr, mode: mode_t) -> c_int { e(unsafe { syscall!(FCHMODAT, AT_FDCWD, path.as_ptr(), mode, 0) }) as c_int } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 0ce9a4c07454aed335c821e7dc9702f24126cd6e..2b4071dd84dad5af1c241849e24428aa87aa9aae 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -287,13 +287,24 @@ pub fn init(auxvs: Box<[[usize; 2]]>) { use self::auxv_defs::*; if let (Some(cwd_ptr), Some(cwd_len)) = ( - get_auxv(&auxvs, AT_REDOX_INITIALCWD_PTR), - get_auxv(&auxvs, AT_REDOX_INITIALCWD_LEN), + get_auxv(&auxvs, AT_REDOX_INITIAL_CWD_PTR), + get_auxv(&auxvs, AT_REDOX_INITIAL_CWD_LEN), ) { let cwd_bytes: &'static [u8] = unsafe { core::slice::from_raw_parts(cwd_ptr as *const u8, cwd_len) }; if let Ok(cwd) = core::str::from_utf8(cwd_bytes) { - self::sys::path::setcwd_manual(cwd.into()); + self::sys::path::set_cwd_manual(cwd.into()); + } + } + + if let (Some(scheme_ptr), Some(scheme_len)) = ( + get_auxv(&auxvs, AT_REDOX_INITIAL_DEFAULT_SCHEME_PTR), + get_auxv(&auxvs, AT_REDOX_INITIAL_DEFAULT_SCHEME_LEN), + ) { + let scheme_bytes: &'static [u8] = + unsafe { core::slice::from_raw_parts(scheme_ptr as *const u8, scheme_len) }; + if let Ok(scheme) = core::str::from_utf8(scheme_bytes) { + self::sys::path::set_default_scheme_manual(scheme.into()); } } diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index 500a0f5de90df25e0d1f21a7761ddbbbb020ca33..3a234dfec37848f242580f44584bd386fc56cd08 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -3,7 +3,6 @@ use crate::{ c_str::CStr, error::Errno, header::{ - dirent::dirent, sys_resource::{rlimit, rusage}, sys_stat::stat, sys_statvfs::statvfs, @@ -33,6 +32,8 @@ pub trait Pal { fn chdir(path: CStr) -> c_int; + fn set_default_scheme(scheme: CStr) -> Result<(), Errno>; + fn chmod(path: CStr, mode: mode_t) -> c_int; fn chown(path: CStr, owner: uid_t, group: gid_t) -> c_int; @@ -191,10 +192,10 @@ pub trait Pal { fn pipe2(fildes: &mut [c_int], flags: c_int) -> c_int; - unsafe fn rlct_clone(stack: *mut usize) -> Result<crate::pthread::OsTid, Errno>; - unsafe fn rlct_kill(os_tid: crate::pthread::OsTid, signal: usize) -> Result<(), Errno>; + unsafe fn rlct_clone(stack: *mut usize) -> Result<pthread::OsTid, Errno>; + unsafe fn rlct_kill(os_tid: pthread::OsTid, signal: usize) -> Result<(), Errno>; - fn current_os_tid() -> crate::pthread::OsTid; + fn current_os_tid() -> pthread::OsTid; fn read(fildes: c_int, buf: &mut [u8]) -> Result<ssize_t, Errno>; fn pread(fildes: c_int, buf: &mut [u8], offset: off_t) -> Result<ssize_t, Errno>; diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index edc7304d37045e1eb0119f624cfaaf5d8bedb465..6b8c3856c72f5b6d5da8f72f34ecc3b448022638 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -131,6 +131,9 @@ pub fn execve( let wants_setugid = stat.st_mode & ((S_ISUID | S_ISGID) as u16) != 0; let cwd: Box<[u8]> = super::path::clone_cwd().unwrap_or_default().into(); + let default_scheme: Box<[u8]> = super::path::clone_default_scheme() + .unwrap_or_else(|| Box::from("file")) + .into(); // Count arguments let mut len = 0; @@ -295,6 +298,7 @@ pub fn execve( let _ = syscall::write(*escalate_fd, &flatten_with_nul(args))?; let _ = syscall::write(*escalate_fd, &flatten_with_nul(envs))?; let _ = syscall::write(*escalate_fd, &cwd)?; + let _ = syscall::write(*escalate_fd, &default_scheme)?; // Closing will notify the scheme, and from that point we will no longer have control // over this process (unless it fails). We do this manually since drop cannot handle @@ -310,6 +314,7 @@ pub fn execve( let extrainfo = ExtraInfo { cwd: Some(&cwd), + default_scheme: Some(&default_scheme), sigignmask: 0, sigprocmask, }; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 534bb98272438b490fae473b441a0898a705bd5b..95c7b89847d340da8413ac7fe3fe11001aed79e7 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -175,6 +175,11 @@ impl Pal for Sys { e(path::chdir(path).map(|()| 0)) as c_int } + fn set_default_scheme(path: CStr) -> Result<(), Errno> { + let path = path.to_str().map_err(|_| Errno(EINVAL))?; + Ok(path::set_default_scheme(path)?) + } + fn chmod(path: CStr, mode: mode_t) -> c_int { match File::open(path, fcntl::O_PATH | fcntl::O_CLOEXEC) { Ok(file) => Self::fchmod(*file, mode), diff --git a/src/platform/redox/path.rs b/src/platform/redox/path.rs index 01c075748bad8c5e92fb1a51cb2aaa04e892a2e0..414056a63c3be99758ee56ebf35f4ce58d055bfc 100644 --- a/src/platform/redox/path.rs +++ b/src/platform/redox/path.rs @@ -23,28 +23,21 @@ pub fn chdir(path: &str) -> Result<()> { let _siglock = tmp_disable_signals(); let mut cwd_guard = CWD.lock(); - let canonicalized = - canonicalize_using_cwd(cwd_guard.as_deref(), path).ok_or(Error::new(ENOENT))?; + let canon = canonicalize_using_cwd(cwd_guard.as_deref(), path).ok_or(Error::new(ENOENT))?; + let canon_with_scheme = canonicalize_with_cwd_internal(cwd_guard.as_deref(), path)?; - let fd = syscall::open(&canonicalized, O_STAT | O_CLOEXEC)?; + let fd = syscall::open(&canon_with_scheme, O_STAT | O_CLOEXEC)?; let mut stat = Stat::default(); if syscall::fstat(fd, &mut stat).is_err() || (stat.st_mode & MODE_TYPE) != MODE_DIR { return Err(Error::new(ENOTDIR)); } let _ = syscall::close(fd); - *cwd_guard = Some(canonicalized.into_boxed_str()); - - // TODO: Check that the dir exists and is a directory. + *cwd_guard = Some(canon.into_boxed_str()); Ok(()) } -pub fn clone_cwd() -> Option<Box<str>> { - let _siglock = tmp_disable_signals(); - CWD.lock().clone() -} - // TODO: MaybeUninit pub fn getcwd(buf: &mut [u8]) -> Option<usize> { let _siglock = tmp_disable_signals(); @@ -62,20 +55,81 @@ pub fn getcwd(buf: &mut [u8]) -> Option<usize> { Some(cwd.len()) } +/// Sets the default scheme +/// +/// By default absolute paths resolve to /scheme/file, calling this function +/// allows a different scheme to be used as the root. This property is inherited +/// by child processes. +/// +/// Resets CWD to /. +pub fn set_default_scheme(scheme: &str) -> Result<()> { + let _siglock = tmp_disable_signals(); + let mut cwd_guard = CWD.lock(); + let mut default_scheme_guard = DEFAULT_SCHEME.lock(); + + *cwd_guard = None; + *default_scheme_guard = Some(scheme.into()); + + Ok(()) +} + +// TODO: How much of this logic should be in redox-path? +fn canonicalize_with_cwd_internal(cwd: Option<&str>, path: &str) -> Result<String> { + let path = canonicalize_using_cwd(cwd, path).ok_or(Error::new(ENOENT))?; + + let standard_scheme = path == "/scheme" || path.starts_with("/scheme/"); + let legacy_scheme = path + .split("/") + .next() + .map(|c| c.contains(":")) + .unwrap_or(false); + + Ok(if standard_scheme || legacy_scheme { + path + } else { + let mut default_scheme_guard = DEFAULT_SCHEME.lock(); + let default_scheme = default_scheme_guard.get_or_insert_with(|| Box::from("file")); + let mut result = format!("/scheme/{}{}", default_scheme, path); + + // Trim trailing / to keep path canonical. + if result.as_bytes().last() == Some(&b'/') { + result.pop(); + } + + result + }) +} + pub fn canonicalize(path: &str) -> Result<String> { let _siglock = tmp_disable_signals(); - let cwd = CWD.lock(); - canonicalize_using_cwd(cwd.as_deref(), path).ok_or(Error::new(ENOENT)) + let cwd_guard = CWD.lock(); + canonicalize_with_cwd_internal(cwd_guard.as_deref(), path) } // TODO: arraystring? static CWD: Mutex<Option<Box<str>>> = Mutex::new(None); +static DEFAULT_SCHEME: Mutex<Option<Box<str>>> = Mutex::new(None); -pub fn setcwd_manual(cwd: Box<str>) { +pub fn set_cwd_manual(cwd: Box<str>) { let _siglock = tmp_disable_signals(); *CWD.lock() = Some(cwd); } +pub fn set_default_scheme_manual(scheme: Box<str>) { + let _siglock = tmp_disable_signals(); + *DEFAULT_SCHEME.lock() = Some(scheme) +} + +pub fn clone_cwd() -> Option<Box<str>> { + let _siglock = tmp_disable_signals(); + CWD.lock().clone() +} + +pub fn clone_default_scheme() -> Option<Box<str>> { + let _siglock = tmp_disable_signals(); + DEFAULT_SCHEME.lock().clone() +} + pub fn open(path: &str, flags: usize) -> Result<usize> { // TODO: SYMLOOP_MAX const MAX_LEVEL: usize = 64; @@ -84,7 +138,7 @@ pub fn open(path: &str, flags: usize) -> Result<usize> { let mut path = path; for _ in 0..MAX_LEVEL { - let canon = canonicalize(path)?; + let canon = canonicalize_with_cwd_internal(CWD.lock().as_deref(), path)?; let open_res = if canon.starts_with(libcscheme::LIBC_SCHEME) { libcscheme::open(&canon, flags)