diff --git a/Cargo.lock b/Cargo.lock index bb40e2cab335510c6944cfa34e17b635084a3e84..7323874ee13c9369edc17d52d75155784034b2cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -351,6 +351,14 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.2.9" +source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=fsgsbase#519a09e96400309a14375c04815da00f7cf5f526" +dependencies = [ + "bitflags", +] + [[package]] name = "relibc" version = "0.2.5" @@ -366,7 +374,7 @@ dependencies = [ "posix-regex", "ralloc", "rand 0.5.6", - "redox_syscall 0.2.9", + "redox_syscall 0.2.9 (git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=fsgsbase)", "sc", "spin 0.9.2", ] @@ -541,7 +549,7 @@ dependencies = [ "cfg-if", "libc", "rand 0.8.4", - "redox_syscall 0.2.9", + "redox_syscall 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all", "winapi", ] diff --git a/Cargo.toml b/Cargo.toml index 24c5e591fdbad1d4ee9d3d533459bf1b5e02e319..182cbfd5e75bd67f867d1a9579c1d3413058e5c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ optional = true sc = "0.2.3" [target.'cfg(target_os = "redox")'.dependencies] -redox_syscall = "0.2.9" +redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "fsgsbase" } spin = "0.9.0" [features] diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index 9ee7ea5322868ec06fddd2914d4cd7989373ed25..9ea90885c5d85976a8f5c2c892017dc2cc38fd07 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -28,6 +28,41 @@ static mut STATIC_TCB_MASTER: Master = Master { offset: 0, }; +fn panic_notls(msg: impl core::fmt::Display) -> ! { + eprintln!("panicked in ld.so: {}", msg); + + unsafe { + core::intrinsics::abort(); + } +} + +pub trait ExpectTlsFree { + type Unwrapped; + + fn expect_notls(self, msg: &str) -> Self::Unwrapped; +} +impl<T, E: core::fmt::Debug> ExpectTlsFree for Result<T, E> { + type Unwrapped = T; + + fn expect_notls(self, msg: &str) -> T { + match self { + Ok(t) => t, + Err(err) => panic_notls(format_args!("expect failed for Result with err: {:?}", err)), + } + } +} +impl<T> ExpectTlsFree for Option<T> { + type Unwrapped = T; + + fn expect_notls(self, msg: &str) -> T { + match self { + Some(t) => t, + None => panic_notls("expect failed for Option"), + } + } +} + +#[inline(never)] pub fn static_init(sp: &'static Stack) { let mut phdr_opt = None; let mut phent_opt = None; @@ -50,9 +85,9 @@ pub fn static_init(sp: &'static Stack) { auxv = unsafe { auxv.add(1) }; } - let phdr = phdr_opt.expect("failed to find AT_PHDR"); - let phent = phent_opt.expect("failed to find AT_PHENT"); - let phnum = phnum_opt.expect("failed to find AT_PHNUM"); + let phdr = phdr_opt.expect_notls("failed to find AT_PHDR"); + let phent = phent_opt.expect_notls("failed to find AT_PHENT"); + let phnum = phnum_opt.expect_notls("failed to find AT_PHNUM"); for i in 0..phnum { let ph_addr = phdr + phent * i; @@ -63,7 +98,7 @@ pub fn static_init(sp: &'static Stack) { program_header64::SIZEOF_PHDR => { unsafe { *(ph_addr as *const program_header64::ProgramHeader) }.into() } - _ => panic!("unknown AT_PHENT size {}", phent), + _ => panic_notls(format_args!("unknown AT_PHENT size {}", phent)), }; let page_size = Sys::getpagesize(); @@ -84,10 +119,10 @@ pub fn static_init(sp: &'static Stack) { STATIC_TCB_MASTER.len = ph.p_filesz as usize; STATIC_TCB_MASTER.offset = valign; - let tcb = Tcb::new(vsize).expect("failed to allocate TCB"); + let tcb = Tcb::new(vsize).expect_notls("failed to allocate TCB"); tcb.masters_ptr = &mut STATIC_TCB_MASTER; tcb.masters_len = mem::size_of::<Master>(); - tcb.copy_masters().expect("failed to copy TLS master data"); + tcb.copy_masters().expect_notls("failed to copy TLS master data"); tcb.activate(); } @@ -99,19 +134,35 @@ pub fn static_init(sp: &'static Stack) { } } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "redox"))] pub unsafe fn init(sp: &'static Stack) { let mut tp = 0usize; - const ARCH_GET_FS: usize = 0x1003; - syscall!(ARCH_PRCTL, ARCH_GET_FS, &mut tp as *mut usize); + + #[cfg(target_os = "linux")] + { + const ARCH_GET_FS: usize = 0x1003; + syscall!(ARCH_PRCTL, ARCH_GET_FS, &mut tp as *mut usize); + } + #[cfg(target_os = "redox")] + { + let mut env = syscall::EnvRegisters::default(); + + let file = syscall::open("thisproc:current/regs/env", syscall::O_CLOEXEC | syscall::O_RDONLY) + .expect_notls("failed to open handle for process registers"); + + let _ = syscall::read(file, &mut env) + .expect_notls("failed to read fsbase"); + + let _ = syscall::close(file); + + tp = env.fsbase as usize; + } + if tp == 0 { static_init(sp); } } -#[cfg(target_os = "redox")] -pub unsafe fn init(_sp: &'static Stack) {} - pub unsafe fn fini() { if let Some(tcb) = Tcb::current() { if tcb.linker_ptr != ptr::null_mut() { diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index e9133c849c27167ac47c9ff702e021e0f08de65e..620c10a9a4c0dc0c8d0cf308a3463e81c017b9c4 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -4,7 +4,7 @@ use goblin::error::{Error, Result}; use crate::{ header::sys_mman, - ld_so::linker::Linker, + ld_so::{linker::Linker, ExpectTlsFree}, platform::{Pal, Sys}, sync::mutex::Mutex, }; @@ -186,30 +186,14 @@ impl Tcb { Ok(slice::from_raw_parts_mut(ptr as *mut u8, size)) } - /// OS specific code to create a new TLS and TCB - Linux - #[cfg(target_os = "linux")] + /// OS specific code to create a new TLS and TCB - Linux and Redox + #[cfg(any(target_os = "linux", target_os = "redox"))] unsafe fn os_new(size: usize) -> Result<(&'static mut [u8], &'static mut [u8])> { let page_size = Sys::getpagesize(); let tls_tcb = Self::map(size + page_size)?; Ok(tls_tcb.split_at_mut(size)) } - /// OS specific code to create a new TLS and TCB - Redox - #[cfg(target_os = "redox")] - unsafe fn os_new(size: usize) -> Result<(&'static mut [u8], &'static mut [u8])> { - use crate::header::unistd; - //TODO: better method of finding fs offset - let pid = unistd::getpid(); - let page_size = Sys::getpagesize(); - let tcb_addr = 0xB000_0000 + pid as usize * page_size; - let tls = Self::map(size)?; - Ok(( - tls, - //TODO: Consider allocating TCB as part of TLS - slice::from_raw_parts_mut(tcb_addr as *mut u8, page_size), - )) - } - /// Architecture specific code to read a usize from the TCB - x86_64 #[inline(always)] #[cfg(target_arch = "aarch64")] @@ -230,13 +214,12 @@ impl Tcb { #[cfg(target_arch = "x86_64")] unsafe fn arch_read(offset: usize) -> usize { let value; - llvm_asm!(" - mov rax, fs:[rdi] + asm!( " - : "={rax}"(value) - : "{rdi}"(offset) - : - : "intel" + mov {}, fs:[{}] + ", + out(reg) value, + in(reg) offset, ); value } @@ -257,7 +240,20 @@ impl Tcb { /// OS and architecture specific code to activate TLS - Redox x86_64 #[cfg(all(target_os = "redox", target_arch = "x86_64"))] unsafe fn os_arch_activate(tp: usize) { - //TODO: Consider setting FS offset to TCB pointer + let mut env = syscall::EnvRegisters::default(); + + let file = syscall::open("thisproc:current/regs/env", syscall::O_CLOEXEC | syscall::O_RDWR) + .expect_notls("failed to open handle for process registers"); + + let _ = syscall::read(file, &mut env) + .expect_notls("failed to read fsbase"); + + env.fsbase = tp as u64; + + let _ = syscall::write(file, &env) + .expect_notls("failed to write fsbase"); + + let _ = syscall::close(file); } } diff --git a/src/lib.rs b/src/lib.rs index 9adc47796910f6cffbc637bd52167d596cb8ef52..42560052e08e47ab9b6ae21e38dcbaab61c54fee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ #![feature(asm)] #![feature(box_into_pin)] #![feature(c_variadic)] +#![feature(const_btree_new)] #![feature(const_raw_ptr_deref)] #![feature(core_intrinsics)] #![feature(global_asm)] diff --git a/src/platform/pte.rs b/src/platform/pte.rs index d69d9f82aef5940dbd1aad664931557909fa23f0..a7f2d86239dbabdf04586ef2417d1e1b3c06af33 100644 --- a/src/platform/pte.rs +++ b/src/platform/pte.rs @@ -2,6 +2,7 @@ use alloc::{boxed::Box, collections::BTreeMap}; use core::{ + cell::UnsafeCell, intrinsics, ptr, sync::atomic::{AtomicU32, Ordering}, }; @@ -45,16 +46,14 @@ static mut pid_mutexes_lock: Mutex<()> = Mutex::new(()); static mut pid_stacks: Option<BTreeMap<pte_osThreadHandle, (*mut c_void, size_t)>> = None; static mut pid_stacks_lock: Mutex<()> = Mutex::new(()); +// TODO: VecMap/SLOB (speed) / radix tree (speed while allowing randomization for security). #[thread_local] -static mut LOCALS: *mut BTreeMap<c_uint, *mut c_void> = ptr::null_mut(); +static LOCALS: UnsafeCell<BTreeMap<c_uint, *mut c_void>> = UnsafeCell::new(BTreeMap::new()); static NEXT_KEY: AtomicU32 = AtomicU32::new(0); -unsafe fn locals() -> &'static mut BTreeMap<c_uint, *mut c_void> { - if LOCALS.is_null() { - LOCALS = Box::into_raw(Box::new(BTreeMap::new())); - } - &mut *LOCALS +unsafe fn locals<'a>() -> &'a mut BTreeMap<c_uint, *mut c_void> { + &mut *LOCALS.get() } // pte_osResult pte_osInit(void) @@ -403,7 +402,7 @@ pub unsafe extern "C" fn pte_osTlsGetValue(index: c_uint) -> *mut c_void { #[no_mangle] pub unsafe extern "C" fn pte_osTlsAlloc(pKey: *mut c_uint) -> pte_osResult { - *pKey = NEXT_KEY.fetch_add(1, Ordering::SeqCst); + *pKey = NEXT_KEY.fetch_add(1, Ordering::Relaxed); PTE_OS_OK }