diff --git a/Cargo.lock b/Cargo.lock index c6b092310f..83d70890c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -432,9 +432,9 @@ dependencies = [ [[package]] name = "redox-path" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7" +checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717" [[package]] name = "redox-rt" diff --git a/Cargo.toml b/Cargo.toml index 29a8b1d49b..239f8f16f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ sc = "0.2.3" [target.'cfg(target_os = "redox")'.dependencies] redox_syscall = "0.5.13" redox-rt = { path = "redox-rt" } -redox-path = "0.2" +redox-path = "0.3" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git", default-features = false, features = [ "redox_syscall", ] } diff --git a/redox-rt/src/protocol.rs b/redox-rt/src/protocol.rs index 823b68c98f..4e6ced18d1 100644 --- a/redox-rt/src/protocol.rs +++ b/redox-rt/src/protocol.rs @@ -52,6 +52,7 @@ pub enum ThreadCall { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(usize)] +#[non_exhaustive] pub enum SocketCall { Bind = 0, Connect = 1, @@ -59,6 +60,15 @@ pub enum SocketCall { GetSockOpt = 3, SendMsg = 4, RecvMsg = 5, + Unbind = 6, + GetToken = 7, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(usize)] +#[non_exhaustive] +pub enum FsCall { + Connect = 0, } impl ProcCall { @@ -103,6 +113,17 @@ impl SocketCall { 3 => Self::GetSockOpt, 4 => Self::SendMsg, 5 => Self::RecvMsg, + 6 => Self::Unbind, + 7 => Self::GetToken, + _ => return None, + }) + } +} + +impl FsCall { + pub fn try_from_raw(raw: usize) -> Option { + Some(match raw { + 0 => Self::Connect, _ => return None, }) } diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs index ada4c18646..0d060262b9 100644 --- a/redox-rt/src/sys.rs +++ b/redox-rt/src/sys.rs @@ -296,11 +296,12 @@ pub fn posix_getresugid() -> Resugid { sgid, } } -pub fn get_proc_credentials(target_pid: usize, buf: &mut [u8]) -> Result { +pub fn get_proc_credentials(cap_fd: usize, target_pid: usize, buf: &mut [u8]) -> Result { if buf.len() < size_of::() { return Err(Error::new(EINVAL)); } - this_proc_call( + proc_call( + cap_fd, buf, CallFlags::empty(), &[ProcCall::GetProcCredentials as u64, target_pid as u64], diff --git a/src/platform/redox/libredox.rs b/src/platform/redox/libredox.rs index 64afa91cb3..58fcf679be 100644 --- a/src/platform/redox/libredox.rs +++ b/src/platform/redox/libredox.rs @@ -242,11 +242,12 @@ pub unsafe extern "C" fn redox_get_rgid_v1() -> RawResult { redox_rt::sys::posix_getresugid().rgid as _ } #[no_mangle] -pub unsafe extern "C" fn redox_get_proc_credentials_v0( +pub unsafe extern "C" fn redox_get_proc_credentials_v1( + cap_fd: usize, target_pid: usize, buf: &mut [u8], ) -> RawResult { - Error::mux(redox_rt::sys::get_proc_credentials(target_pid, buf)) + Error::mux(redox_rt::sys::get_proc_credentials(cap_fd, target_pid, buf)) } #[no_mangle] diff --git a/src/platform/redox/path.rs b/src/platform/redox/path.rs index 9d6739a463..9eb20eaec1 100644 --- a/src/platform/redox/path.rs +++ b/src/platform/redox/path.rs @@ -1,11 +1,16 @@ -use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec}; +use alloc::{ + borrow::ToOwned, + boxed::Box, + string::{String, ToString}, + vec::Vec, +}; use redox_rt::signal::tmp_disable_signals; use syscall::{data::Stat, error::*, flag::*}; use super::{libcscheme, FdGuard}; use crate::sync::Mutex; -pub use redox_path::canonicalize_using_cwd; +pub use redox_path::{canonicalize_using_cwd, RedoxPath}; // TODO: Define in syscall const PATH_MAX: usize = 4096; @@ -169,3 +174,40 @@ pub fn open(path: &str, flags: usize) -> Result { } Err(Error::new(ELOOP)) } + +pub fn dir_path_and_fd_path(socket_path: &str) -> Result<(String, String)> { + let _siglock = tmp_disable_signals(); + let cwd_guard = CWD.lock(); + + let full_path = canonicalize_with_cwd_internal(cwd_guard.as_deref(), socket_path)?; + + let redox_path = RedoxPath::from_absolute(&full_path).ok_or(Error::new(EINVAL))?; + let (_, mut ref_path) = redox_path.as_parts().ok_or(Error::new(EINVAL))?; + if ref_path.as_ref().is_empty() { + return Err(Error::new(EINVAL)); + } + if redox_path.is_default_scheme() { + let dir_to_open = String::from(get_parent_path(&full_path).ok_or(Error::new(EINVAL))?); + Ok((dir_to_open, ref_path.as_ref().to_string())) + } else { + let full_path = canonicalize_with_cwd_internal(cwd_guard.as_deref(), ref_path.as_ref())?; + let redox_path = RedoxPath::from_absolute(&full_path).ok_or(Error::new(EINVAL))?; + let (_, path) = redox_path.as_parts().ok_or(Error::new(EINVAL))?; + let dir_to_open = String::from(get_parent_path(&full_path).ok_or(Error::new(EINVAL))?); + Ok((dir_to_open, path.as_ref().to_string())) + } +} + +fn get_parent_path(path: &str) -> Option<&str> { + path.rfind('/').and_then(|index| { + if index == 0 { + // Path is something like "/file.txt" or the root "/". + // The parent is the root directory "/". + Some("/") + } else { + // Path is something like "/a/b/c.txt". + // Take the slice from the beginning up to the last '/'. + Some(&path[..index]) + } + }) +} diff --git a/src/platform/redox/socket.rs b/src/platform/redox/socket.rs index 9a906de48c..f5342c4f5c 100644 --- a/src/platform/redox/socket.rs +++ b/src/platform/redox/socket.rs @@ -1,10 +1,14 @@ -use alloc::vec::Vec; +use alloc::{string::String, vec::Vec}; use core::{cmp, mem, ptr, slice, str}; -use redox_rt::{proc::FdGuard, protocol::SocketCall}; +use redox_rt::{ + proc::FdGuard, + protocol::{FsCall, SocketCall}, +}; use syscall::{self, flag::*}; use super::{ super::{types::*, Pal, PalSocket, ERRNO}, + path::dir_path_and_fd_path, Sys, }; use crate::{ @@ -522,15 +526,40 @@ impl PalSocket for Sys { ); let addr = slice::from_raw_parts(&data.sun_path as *const _ as *const u8, len); - let mut path = format!("{}", str::from_utf8(addr).unwrap()); + let path = format!("{}", str::from_utf8(addr).unwrap()); trace!("path: {:?}", path); + let (dir_path, mut fd_path) = dir_path_and_fd_path(&path)?; + redox_rt::sys::sys_call( socket as usize, - path.as_bytes_mut(), + fd_path.as_bytes_mut(), CallFlags::empty(), &[SocketCall::Bind as u64], )?; + + let fs_bind_result = (|| -> Result<()> { + let dirfd = FdGuard::new(syscall::open( + &dir_path, + syscall::O_RDONLY | syscall::O_DIRECTORY | syscall::O_CLOEXEC, + )?); + let fd_to_send = FdGuard::new(syscall::dup(socket as usize, &[])?); + let _ = syscall::sendfd(*dirfd, *fd_to_send, 0, 0)?; + Ok(()) + })(); + + if let Err(original_error) = fs_bind_result { + if let Err(unbind_error) = redox_rt::sys::sys_call( + socket as usize, + &mut [], + CallFlags::empty(), + &[SocketCall::Unbind as u64], + ) { + eprintln!("bind: CRITICAL: failed to unbind socket after a failed transaction: {:?}", unbind_error); + } + + return Err(original_error); + } } _ => { return Err(Errno(EAFNOSUPPORT)); @@ -570,9 +599,25 @@ impl PalSocket for Sys { let mut path = format!("{}", str::from_utf8(addr).unwrap()); trace!("path: {:?}", path); + let (_, fd_path) = dir_path_and_fd_path(&path)?; + + let target_path = format!("/{fd_path}"); + let socket_file_fd = FdGuard::new(syscall::open(&target_path, syscall::O_RDWR)?); + + const TOKEN_BUF_SIZE: usize = 16; + + let mut token_buf = [0u8; TOKEN_BUF_SIZE]; + + redox_rt::sys::sys_call( + *socket_file_fd, + &mut token_buf, + CallFlags::empty(), + &[FsCall::Connect as u64], + )?; + redox_rt::sys::sys_call( socket as usize, - path.as_bytes_mut(), + &mut token_buf, CallFlags::empty(), &[SocketCall::Connect as u64], )?;