diff --git a/src/ld_so/access.rs b/src/ld_so/access.rs index 15bbd074e7dc32ee1049de3f0ebda867a7be97df..c29f7f3417fe902a033ab7f8f4c68099ce0df0e2 100644 --- a/src/ld_so/access.rs +++ b/src/ld_so/access.rs @@ -29,7 +29,7 @@ unsafe fn access(path: *const c_char, mode: c_int) -> c_int { Ok(ok) => ok, Err(_) => return -1, }; - let fd = match syscall::open(path, syscall::O_CLOEXEC) { + let fd = match crate::platform::sys::path::open(path, syscall::O_CLOEXEC) { Ok(fd) => fd, _ => return -1, }; @@ -40,6 +40,7 @@ unsafe fn access(path: *const c_char, mode: c_int) -> c_int { if syscall::fstat(fd, &mut stat).is_err() { return -1; } + let _ = syscall::close(fd); let uid = match syscall::getuid() { Ok(uid) => uid, Err(_) => return -1, diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs index e07afac109b77d444f46ef02e680e79a4f1f8c7e..4a395ffec4377e14c217b935259d44362552f224 100644 --- a/src/ld_so/start.rs +++ b/src/ld_so/start.rs @@ -11,7 +11,7 @@ use alloc::{ use crate::{ c_str::CStr, header::{sys_auxv::AT_NULL, unistd}, - platform::{new_mspace, types::c_char}, + platform::{get_auxvs, get_auxv, new_mspace, types::c_char}, start::Stack, sync::mutex::Mutex, ALLOCATOR, @@ -57,19 +57,6 @@ unsafe fn get_env(mut ptr: *const usize) -> (BTreeMap<String, String>, *const us return (envs, ptr); } -unsafe fn get_auxv(mut ptr: *const usize) -> BTreeMap<usize, usize> { - //traverse the stack and collect argument environment variables - let mut auxv = BTreeMap::new(); - while *ptr != AT_NULL { - let kind = *ptr; - ptr = ptr.add(1); - let value = *ptr; - ptr = ptr.add(1); - auxv.insert(kind, value); - } - return auxv; -} - unsafe fn adjust_stack(sp: &'static mut Stack) { let mut argv = sp.argv() as *mut usize; @@ -163,7 +150,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> let argv_start = sp.argv() as *mut usize; let (argv, argv_end) = get_argv(argv_start); let (envs, envs_end) = get_env(argv_end.add(1)); - let auxv = get_auxv(envs_end.add(1)); + let auxv = get_auxvs(envs_end.add(1)); (argv, envs, auxv) }; @@ -183,8 +170,8 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> crate::platform::environ = crate::platform::OUR_ENVIRON.as_mut_ptr(); } - let is_manual = if let Some(img_entry) = auxv.get(&AT_ENTRY) { - *img_entry == ld_entry + let is_manual = if let Some(img_entry) = get_auxv(&auxv, AT_ENTRY) { + img_entry == ld_entry } else { true }; @@ -194,6 +181,9 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> _r_debug.r_ldbase = ld_entry; } + // TODO: Fix memory leak, although minimal. + crate::platform::init(auxv.clone()); + // Some variables that will be overridden by environment and auxiliary vectors let ld_library_path = envs.get("LD_LIBRARY_PATH").map(|s| s.to_owned()); @@ -229,7 +219,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> let base_addr = { let mut base = None; if !is_manual && cfg!(not(target_os = "redox")) { - let phdr = *auxv.get(&AT_PHDR).unwrap(); + let phdr = get_auxv(&auxv, AT_PHDR).unwrap(); if phdr != 0 { base = Some(phdr - SIZEOF_EHDR); } diff --git a/src/platform/auxv_defs.rs b/src/platform/auxv_defs.rs index 30a59962bb691f85b04a0eddef66ba813e2ea685..f88052e0a4b9ec31cd9d115ae0aaf8d716808ad1 100644 --- a/src/platform/auxv_defs.rs +++ b/src/platform/auxv_defs.rs @@ -25,3 +25,9 @@ pub const AT_BASE_PLATFORM: usize = 24; /* String identifying real platforms.*/ pub const AT_RANDOM: usize = 25; /* Address of 16 random bytes. */ pub const AT_HWCAP2: usize = 26; /* More machine-dependent hints about*/ 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; +#[cfg(target_os = "redox")] +pub const AT_REDOX_INITIALCWD_LEN: usize = 33; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 6169a3b5919a57c8704c842994f02f0910cf1a25..09d4e7986b65d5aeee918a357aa6eeb81bd80c5a 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -1,4 +1,5 @@ use crate::io::{self, Read, Write}; +use alloc::boxed::Box; use alloc::vec::Vec; use core::{fmt, ptr}; @@ -20,11 +21,11 @@ pub use self::sys::{e, Sys}; #[cfg(all(not(feature = "no_std"), target_os = "linux"))] #[path = "linux/mod.rs"] -mod sys; +pub(crate) mod sys; #[cfg(all(not(feature = "no_std"), target_os = "redox"))] #[path = "redox/mod.rs"] -mod sys; +pub(crate) mod sys; #[cfg(test)] mod test; @@ -261,3 +262,41 @@ impl<T: Write> Write for CountingWriter<T> { self.inner.flush() } } + +// TODO: Set a global variable once get_auxvs is called, and then implement getauxval based on +// get_auxv. + +#[cold] +pub unsafe fn get_auxvs(mut ptr: *const usize) -> Box<[[usize; 2]]> { + //traverse the stack and collect argument environment variables + let mut auxvs = Vec::new(); + + while *ptr != self::auxv_defs::AT_NULL { + let kind = ptr.read(); + ptr = ptr.add(1); + let value = ptr.read(); + ptr = ptr.add(1); + auxvs.push([kind, value]); + } + + auxvs.sort_unstable_by_key(|[kind, _]| *kind); + auxvs.into_boxed_slice() +} +pub fn get_auxv(auxvs: &[[usize; 2]], key: usize) -> Option<usize> { + auxvs.binary_search_by_key(&key, |[entry_key, _]| *entry_key).ok().map(|idx| auxvs[idx][1]) +} + +#[cold] +#[cfg(target_os = "redox")] +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)) { + 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()); + } + } +} +#[cfg(not(target_os = "redox"))] +pub fn init(auxvs: Box<[[usize; 2]]>) {} diff --git a/src/platform/redox/clone.rs b/src/platform/redox/clone.rs index da8619f2725522b9b9302839da42a19799841d2c..ba079e1f239528f2119666effcadcd321ef7f585 100644 --- a/src/platform/redox/clone.rs +++ b/src/platform/redox/clone.rs @@ -31,7 +31,6 @@ pub unsafe fn pte_clone_impl(stack: *mut usize) -> Result<usize> { } copy_str(*cur_pid_fd, *new_pid_fd, "name")?; - copy_str(*cur_pid_fd, *new_pid_fd, "cwd")?; // Reuse existing address space { diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index 99b561c68410ece5226d72536c2e27256690ccad..3ddd9a34d711a0b50cfa7c362b41510fdcfa6748 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -7,9 +7,9 @@ use crate::platform::{sys::{S_ISUID, S_ISGID}, types::*}; use syscall::data::Stat; use syscall::flag::*; use syscall::error::*; -use redox_exec::{FdGuard, FexecResult}; +use redox_exec::{FdGuard, ExtraInfo, FexecResult}; -fn fexec_impl(file: File, path: &[u8], args: &[&[u8]], envs: &[&[u8]], total_args_envs_size: usize, interp_override: Option<redox_exec::InterpOverride>) -> Result<usize> { +fn fexec_impl(file: File, path: &[u8], args: &[&[u8]], envs: &[&[u8]], total_args_envs_size: usize, extrainfo: &ExtraInfo, interp_override: Option<redox_exec::InterpOverride>) -> Result<usize> { let fd = *file; core::mem::forget(file); let image_file = FdGuard::new(fd as usize); @@ -17,7 +17,7 @@ fn fexec_impl(file: File, path: &[u8], args: &[&[u8]], envs: &[&[u8]], total_arg let open_via_dup = FdGuard::new(syscall::open("thisproc:current/open_via_dup", 0)?); let memory = FdGuard::new(syscall::open("memory:", 0)?); - let addrspace_selection_fd = match redox_exec::fexec_impl(image_file, open_via_dup, &memory, path, args.iter().rev(), envs.iter().rev(), total_args_envs_size, interp_override)? { + let addrspace_selection_fd = match redox_exec::fexec_impl(image_file, open_via_dup, &memory, path, args.iter().rev(), envs.iter().rev(), total_args_envs_size, extrainfo, interp_override)? { FexecResult::Normal { addrspace_handle } => addrspace_handle, FexecResult::Interp { image_file, open_via_dup, path, interp_override: new_interp_override } => { drop(image_file); @@ -75,6 +75,8 @@ pub fn execve(path: &CStr, arg_env: ArgEnv, interp_override: Option<redox_exec:: } 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(); + // Count arguments let mut len = 0; @@ -103,12 +105,11 @@ pub fn execve(path: &CStr, arg_env: ArgEnv, interp_override: Option<redox_exec:: } shebang == *b"#!" }; - // Since the fexec implementation is almost fully done in userspace, the kernel can no - // longer set UID/GID accordingly, and this code checking for them before using - // hypothetical interfaces to upgrade UID/GID, can not be trusted. So we ask the - // `escalate:` scheme for help. Note that `escalate:` can be deliberately excluded from the - // scheme namespace to deny privilege escalation (such as su/sudo/doas) for untrusted - // processes. + // Since the fexec implementation is almost fully done in userspace, the kernel can no longer + // set UID/GID accordingly, and this code checking for them before using interfaces to upgrade + // UID/GID, can not be trusted. So we ask the `escalate:` scheme for help. Note that + // `escalate:` can be deliberately excluded from the scheme namespace to deny privilege + // escalation (such as su/sudo/doas) for untrusted processes. // // According to execve(2), Linux and most other UNIXes ignore setuid/setgid for interpreted // executables and thereby simply keep the privileges as is. For compatibility we do that @@ -224,6 +225,7 @@ pub fn execve(path: &CStr, arg_env: ArgEnv, interp_override: Option<redox_exec:: // individual items. This can be copied directly into the new executable's memory. let _ = syscall::write(*escalate_fd, &flatten_with_nul(args))?; let _ = syscall::write(*escalate_fd, &flatten_with_nul(envs))?; + let _ = syscall::write(*escalate_fd, &cwd)?; // 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 @@ -235,7 +237,8 @@ pub fn execve(path: &CStr, arg_env: ArgEnv, interp_override: Option<redox_exec:: unreachable!() } else { - fexec_impl(image_file, path.to_bytes(), &args, &envs, total_args_envs_size, interp_override) + let extrainfo = ExtraInfo { cwd: Some(&cwd) }; + fexec_impl(image_file, path.to_bytes(), &args, &envs, total_args_envs_size, &extrainfo, interp_override) } } fn flatten_with_nul<T>(iter: impl IntoIterator<Item = T>) -> Box<[u8]> where T: AsRef<[u8]> { diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 4f41c6d76e3faf6db7ab355ebc2d311516645d18..8b74849463ecc1f6cdfa84e031bf6313c16a1bf3 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1,10 +1,11 @@ use core::{mem, ptr, result::Result as CoreResult, slice, str}; +use core::convert::TryFrom; use core::arch::asm; use syscall::{ self, data::{Map, Stat as redox_stat, StatVfs as redox_statvfs, TimeSpec as redox_timespec}, - PtraceEvent, Result, + PtraceEvent, Result, Error, EMFILE, }; use crate::{ @@ -29,6 +30,8 @@ use crate::{ io::{self, prelude::*, BufReader, SeekFrom}, }; +pub use redox_exec::FdGuard; + use super::{errno, types::*, Pal, Read}; static mut BRK_CUR: *mut c_void = ptr::null_mut(); @@ -43,6 +46,7 @@ mod clone; mod epoll; mod exec; mod extra; +pub(crate) mod path; mod ptrace; mod signal; mod socket; @@ -61,6 +65,8 @@ macro_rules! path_from_c_str { }}; } +use self::path::canonicalize; + pub fn e(sys: Result<usize>) -> usize { match sys { Ok(ok) => ok, @@ -163,7 +169,7 @@ impl Pal for Sys { fn chdir(path: &CStr) -> c_int { let path = path_from_c_str!(path); - e(syscall::chdir(path)) as c_int + e(path::chdir(path).map(|()| 0)) as c_int } fn chmod(path: &CStr, mode: mode_t) -> c_int { @@ -354,29 +360,20 @@ impl Pal for Sys { } fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char { + // TODO: Not using MaybeUninit seems a little unsafe + let buf_slice = unsafe { slice::from_raw_parts_mut(buf as *mut u8, size as usize) }; - if !buf_slice.is_empty() { - let nonnull_size = buf_slice.len() - 1; - let read = e(syscall::getcwd(&mut buf_slice[..nonnull_size])); - if read == !0 { - ptr::null_mut() - } else if read == nonnull_size { - unsafe { - errno = ERANGE; - } - ptr::null_mut() - } else { - for b in &mut buf_slice[read..] { - *b = 0; - } - buf - } - } else { - unsafe { - errno = EINVAL; - } - ptr::null_mut() + if buf_slice.is_empty() { + unsafe { errno = EINVAL; } + return ptr::null_mut(); + } + + if path::getcwd(buf_slice).is_none() { + unsafe { errno = ERANGE; } + return ptr::null_mut() } + + buf } fn getdents(fd: c_int, mut dirents: *mut dirent, max_bytes: usize) -> c_int { @@ -708,10 +705,19 @@ impl Pal for Sys { fn open(path: &CStr, oflag: c_int, mode: mode_t) -> c_int { let path = path_from_c_str!(path); - e(syscall::open( - path, - ((oflag as usize) & 0xFFFF_0000) | ((mode as usize) & 0xFFFF), - )) as c_int + + match path::open(path, ((oflag as usize) & 0xFFFF_0000) | ((mode as usize) & 0xFFFF)) { + Ok(fd) => { + match c_int::try_from(fd) { + Ok(c_fd) => c_fd, + Err(_) => { + let _ = syscall::close(fd); + e(Err(Error::new(EMFILE))) as c_int + } + } + } + Err(error) => e(Err(error)) as c_int, + } } fn pipe2(fds: &mut [c_int], flags: c_int) -> c_int { @@ -764,7 +770,7 @@ impl Pal for Sys { fn rmdir(path: &CStr) -> c_int { let path = path_from_c_str!(path); - e(syscall::rmdir(path)) as c_int + e(canonicalize(path).and_then(|path| syscall::rmdir(&path))) as c_int } fn sched_yield() -> c_int { @@ -891,7 +897,7 @@ impl Pal for Sys { fn unlink(path: &CStr) -> c_int { let path = path_from_c_str!(path); - e(syscall::unlink(path)) as c_int + e(canonicalize(path).and_then(|path| syscall::unlink(&path))) as c_int } fn waitpid(mut pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t { diff --git a/src/platform/redox/path.rs b/src/platform/redox/path.rs new file mode 100644 index 0000000000000000000000000000000000000000..45e3e7bbaaab0ebd45113b909b81c957a8c5462f --- /dev/null +++ b/src/platform/redox/path.rs @@ -0,0 +1,185 @@ +use syscall::error::*; +use syscall::flag::*; + +use alloc::borrow::{Cow, ToOwned}; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; + +use super::FdGuard; +use crate::sync::Mutex; + +// TODO: Define in syscall +const PATH_MAX: usize = 4096; + +/// Make a relative path absolute. +/// +/// Given a cwd of "scheme:/path", this his function will turn "foo" into "scheme:/path/foo". +/// "/foo" will turn into "scheme:/foo". "bar:/foo" will be used directly, as it is already +/// absolute +pub fn canonicalize_using_cwd<'a>(cwd_opt: Option<&str>, path: &'a str) -> Option<String> { + let mut canon = if path.find(':').is_none() { + let cwd = cwd_opt?; + let path_start = cwd.find(':')? + 1; + + let mut canon = if !path.starts_with('/') { + let mut c = cwd.to_owned(); + if ! c.ends_with('/') { + c.push('/'); + } + c + } else { + cwd[..path_start].to_owned() + }; + + canon.push_str(&path); + canon + } else { + path.to_owned() + }; + + // NOTE: assumes the scheme does not include anything like "../" or "./" + let mut result = { + let parts = canon.split('/') + .rev() + .scan(0, |nskip, part| { + if part == "." { + Some(None) + } else if part == ".." { + *nskip += 1; + Some(None) + } else if *nskip > 0 { + *nskip -= 1; + Some(None) + } else { + Some(Some(part)) + } + }) + .filter_map(|x| x) + .filter(|x| !x.is_empty()) + .collect::<Vec<_>>(); + parts + .iter() + .rev() + .fold(String::new(), |mut string, &part| { + string.push_str(part); + string.push('/'); + string + }) + }; + result.pop(); // remove extra '/' + + // replace with the root of the scheme if it's empty + Some(if result.is_empty() { + let pos = canon.find(':') + .map_or(canon.len(), |p| p + 1); + canon.truncate(pos); + canon + } else { + result + }) +} + +// XXX: chdir is not marked thread-safe (MT-safe) by POSIX. But on Linux it is simply run as a +// syscall and is therefore atomic, which is presumably why Rust's libstd doesn't synchronize +// access to this. +// +// https://internals.rust-lang.org/t/synchronized-ffi-access-to-posix-environment-variable-functions/15475 +// +// chdir is however signal-safe, forbidding the use of locks. We therefore call sigprocmask before +// and after acquiring the locks. (TODO: ArcSwap? That will need to be ported to no_std first, +// though). +pub fn chdir(path: &str) -> Result<()> { + let _siglock = SignalMask::lock(); + let mut cwd_guard = CWD.lock(); + + let canonicalized = canonicalize_using_cwd(cwd_guard.as_deref(), path).ok_or(Error::new(ENOENT))?; + + *cwd_guard = Some(canonicalized.into_boxed_str()); + + // TODO: Check that the dir exists and is a directory. + + Ok(()) +} + +pub fn clone_cwd() -> Option<Box<str>> { + let _siglock = SignalMask::lock(); + CWD.lock().clone() +} + +// TODO: MaybeUninit +pub fn getcwd(buf: &mut [u8]) -> Option<usize> { + let _siglock = SignalMask::lock(); + let cwd_guard = CWD.lock(); + let cwd = cwd_guard.as_deref().unwrap_or("").as_bytes(); + + // But is already checked not to be empty. + if buf.len() - 1 < cwd.len() { return None; } + + buf[..cwd.len()].copy_from_slice(&cwd); + buf[cwd.len()..].fill(0_u8); + + Some(cwd.len()) +} + +// TODO: Move cwd from kernel to libc. It is passed via auxiliary vectors. +pub fn canonicalize(path: &str) -> Result<String> { + let _siglock = SignalMask::lock(); + let cwd = CWD.lock(); + canonicalize_using_cwd(cwd.as_deref(), path).ok_or(Error::new(ENOENT)) +} + +// TODO: arraystring? +static CWD: Mutex<Option<Box<str>>> = Mutex::new(None); + +pub fn setcwd_manual(cwd: Box<str>) { + let _siglock = SignalMask::lock(); + *CWD.lock() = Some(cwd); +} + +/// RAII guard able to magically fix signal unsafety, by disabling signals during a critical +/// section. +pub struct SignalMask { + oldset: [u64; 2], +} +impl SignalMask { + pub fn lock() -> Self { + let mut oldset = [0; 2]; + syscall::sigprocmask(syscall::SIG_SETMASK, Some(&[!0, !0]), Some(&mut oldset)).expect("failed to run sigprocmask"); + Self { oldset } + } +} +impl Drop for SignalMask { + fn drop(&mut self) { + let _ = syscall::sigprocmask(syscall::SIG_SETMASK, Some(&self.oldset), None); + } +} + +pub fn open(path: &str, flags: usize) -> Result<usize> { + // TODO: SYMLOOP_MAX + const MAX_LEVEL: usize = 64; + + let mut resolve_buf = [0_u8; 4096]; + let mut path = path; + + for _ in 0..MAX_LEVEL { + let canon = canonicalize(path)?; + match syscall::open(&*canon, flags) { + Ok(fd) => return Ok(fd), + Err(error) if error == Error::new(EXDEV) => { + let resolve_flags = O_CLOEXEC | O_SYMLINK | O_RDONLY; + let resolve_fd = FdGuard::new(syscall::open(&*canon, resolve_flags)?); + + let bytes_read = syscall::read(*resolve_fd, &mut resolve_buf)?; + // TODO: make resolve_buf PATH_MAX + 1 bytes? + if bytes_read == resolve_buf.len() { return Err(Error::new(ENAMETOOLONG)); } + + // If the symbolic link path is non-UTF8, it cannot be opened, and is thus + // considered a "dangling symbolic link". + path = core::str::from_utf8(&resolve_buf[..bytes_read]).map_err(|_| Error::new(ENOENT))?; + } + Err(other_error) => return Err(other_error), + } + } + Err(Error::new(ELOOP)) +} diff --git a/src/platform/redox/redox-exec/src/lib.rs b/src/platform/redox/redox-exec/src/lib.rs index 99f08f5e8e4bb7a149c552dba718a8bdb1cb766d..7d90ddcd0b8d7c5a170cb1e35ecdb930859499f3 100644 --- a/src/platform/redox/redox-exec/src/lib.rs +++ b/src/platform/redox/redox-exec/src/lib.rs @@ -34,7 +34,11 @@ pub struct InterpOverride { tree: BTreeMap<usize, usize>, } -pub fn fexec_impl<A, E>(image_file: FdGuard, open_via_dup: FdGuard, memory_scheme_fd: &FdGuard, path: &[u8], args: A, envs: E, total_args_envs_size: usize, mut interp_override: Option<InterpOverride>) -> Result<FexecResult> +pub struct ExtraInfo<'a> { + pub cwd: Option<&'a [u8]>, +} + +pub fn fexec_impl<A, E>(image_file: FdGuard, open_via_dup: FdGuard, memory_scheme_fd: &FdGuard, path: &[u8], args: A, envs: E, total_args_envs_size: usize, extrainfo: &ExtraInfo, mut interp_override: Option<InterpOverride>) -> Result<FexecResult> where A: IntoIterator, E: IntoIterator, @@ -178,7 +182,8 @@ where push(interp_override.as_ref().map_or(header.e_phentsize as usize, |o| o.at_phent))?; push(AT_PHENT)?; - let args_envs_size_aligned = (total_args_envs_size+PAGE_SIZE-1)/PAGE_SIZE*PAGE_SIZE; + let total_args_envs_auxvpointee_size = total_args_envs_size + extrainfo.cwd.map_or(0, |s| s.len() + 1); + let args_envs_size_aligned = (total_args_envs_auxvpointee_size+PAGE_SIZE-1)/PAGE_SIZE*PAGE_SIZE; let target_args_env_address = find_free_target_addr(&tree, args_envs_size_aligned).ok_or(Error::new(ENOMEM))?; allocate_remote(&grants_fd, memory_scheme_fd, target_args_env_address, args_envs_size_aligned, MapFlags::PROT_READ | MapFlags::PROT_WRITE)?; tree.insert(target_args_env_address, args_envs_size_aligned); @@ -195,6 +200,13 @@ where Ok(address) }; + if let Some(cwd) = extrainfo.cwd { + push(append(cwd)?)?; + push(AT_REDOX_INITIALCWD_PTR)?; + push(cwd.len())?; + push(AT_REDOX_INITIALCWD_LEN)?; + } + push(0)?; for env in envs { @@ -424,7 +436,6 @@ fn fork_inner(initial_rsp: *mut usize) -> Result<usize> { } copy_str(*cur_pid_fd, *new_pid_fd, "name")?; - copy_str(*cur_pid_fd, *new_pid_fd, "cwd")?; { let cur_sigaction_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"sigactions")?); diff --git a/src/start.rs b/src/start.rs index 0b9c13a68bf182eb08382775b380a01493d3a387..3c297a831f5f43f41bec8276177b7c966c3fb12f 100644 --- a/src/start.rs +++ b/src/start.rs @@ -4,7 +4,7 @@ use core::{intrinsics, ptr}; use crate::{ header::{libgen, stdio, stdlib}, ld_so, - platform::{self, new_mspace, types::*, Pal, Sys}, + platform::{self, get_auxvs, new_mspace, types::*, Pal, Sys}, ALLOCATOR, }; @@ -185,6 +185,8 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { platform::OUR_ENVIRON = copy_string_array(envp, len); platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); } + let auxvs = get_auxvs(sp.auxv().cast()); + crate::platform::init(auxvs); // Setup signal stack, otherwise we cannot handle any signals besides SIG_IGN/SIG_DFL behavior. #[cfg(target_os = "redox")] diff --git a/src/sync/reentrant_mutex.rs b/src/sync/reentrant_mutex.rs new file mode 100644 index 0000000000000000000000000000000000000000..43e60772d0d2910983937da1b5f6cfbd49c4b7e7 --- /dev/null +++ b/src/sync/reentrant_mutex.rs @@ -0,0 +1,27 @@ +use super::{AtomicLock, AttemptStatus}; + +const WAITING_BIT: u32 = 1 << 31; +const UNLOCKED: u32 = 0; +// We now have 2^32 - 1 possible thread ID values + +pub struct ReentrantMutex<T> { + lock: AtomicLock, + content: UnsafeCell<T>, +} +unsafe impl<T: Send> Send for ReentrantMutex {} +unsafe impl<T: Send> Sync for ReentrantMutex {} + +impl<T> ReentrantMutex<T> { + pub const fn new(context: T) -> Self { + Self { + lock: AtomicLock::new(UNLOCKED), + content: UnsafeCell::new(content), + } + } +} +pub struct ReentrantMutexGuard<'a, T: 'a> { + mutex: &'a ReentrantMutex<T>, + content: &'a T, +} +impl<'a, T> Deref for MutexGuard { +}