Merge branch 'kek/chroot3' into 'master'
Add capability to set the default scheme See merge request redox-os/relibc!510
This commit is contained in:
@@ -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 {
|
||||
|
||||
+15
-4
@@ -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)?;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+14
-3
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
|
||||
+69
-15
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user