diff --git a/src/ld_so/access.rs b/src/ld_so/access.rs new file mode 100644 index 0000000000..624edff861 --- /dev/null +++ b/src/ld_so/access.rs @@ -0,0 +1,53 @@ +// Wrapper over the access syscall that doesn't touch errno variable, +// Do not use outside of ld_so + +use crate::{c_str::CStr, platform::types::*}; + +#[cfg(target_os = "redox")] +use crate::header::unistd::{F_OK, R_OK, W_OK, X_OK}; + +#[cfg(target_os = "linux")] +pub unsafe fn access(path: *const c_char, mode: c_int) -> c_int { + let path = CStr::from_ptr(path); + syscall!(ACCESS, (path).as_ptr(), mode) as c_int +} + +// Wrapper over the systemcall, Do not use outside of ld_so +#[cfg(target_os = "redox")] +pub unsafe fn access(path: *const c_char, mode: c_int) -> c_int { + let path = CStr::from_ptr(path).to_bytes(); + let fd = match syscall::open(path, syscall::O_CLOEXEC) { + Ok(fd) => fd, + _ => return -1, + }; + if mode == F_OK { + return 0; + } + let mut stat = syscall::Stat::default(); + if syscall::fstat(fd, &mut stat).is_err() { + return -1; + } + let uid = match syscall::getuid() { + Ok(uid) => uid, + Err(_) => return -1, + }; + let gid = match syscall::getgid() { + Ok(gid) => gid, + Err(_) => return -1, + }; + + let perms = if stat.st_uid as usize == uid { + stat.st_mode >> (3 * 2 & 0o7) + } else if stat.st_gid as usize == gid { + stat.st_mode >> (3 * 1 & 0o7) + } else { + stat.st_mode & 0o7 + }; + if (mode & R_OK == R_OK && perms & 0o4 != 0o4) + || (mode & W_OK == W_OK && perms & 0o2 != 0o2) + || (mode & X_OK == X_OK && perms & 0o1 != 0o1) + { + return -1; + } + 0 +} diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index 0f42d79eb4..d6acf24097 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -21,16 +21,16 @@ use crate::{ c_str::CString, fs::File, header::{fcntl, sys_mman, unistd}, - io::{self, Read}, + io::Read, platform::types::c_void, }; use super::{ + access::access, debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug}, tcb::{Master, Tcb}, PAGE_SIZE, }; - #[cfg(target_os = "redox")] const PATH_SEP: char = ';'; @@ -94,54 +94,41 @@ impl Linker { } pub fn load(&mut self, name: &str, path: &str) -> Result<()> { - self.dep_tree = self.load_recursive(name, path)? - .ok_or(Error::Malformed(format!( - "failed to find '{}'", - path - )))?; + self.dep_tree = self.load_recursive(name, path)?; if self.verbose { println!("Dep tree: {:#?}", self.dep_tree); } return Ok(()); } - fn load_recursive(&mut self, name: &str, path: &str) -> Result> { + fn load_recursive(&mut self, name: &str, path: &str) -> Result { if self.verbose { println!("load {}: {}", name, path); } - - let path_c = CString::new(path) - .map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?; - - let mut data = Vec::new(); - { - let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC; - let mut file = match File::open(&path_c, flags) { - Ok(ok) => ok, - Err(err) => match err.kind() { - io::ErrorKind::NotFound => return Ok(None), - _ => return Err(Error::Malformed(format!("failed to open '{}': {}", path, err))) - } - }; - - file.read_to_end(&mut data) - .map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?; - } - if self.cir_dep.contains(name) { return Err(Error::Malformed(format!( "Circular dependency: {} is a dependency of itself", name ))); } - self.cir_dep.insert(name.to_string()); let mut deps = DepTree::new(name.to_string()); + let mut data = Vec::new(); + self.cir_dep.insert(name.to_string()); + let path_c = CString::new(path) + .map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?; + + { + let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC; + let mut file = File::open(&path_c, flags) + .map_err(|err| Error::Malformed(format!("failed to open '{}': {}", path, err)))?; + + file.read_to_end(&mut data) + .map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?; + } deps.deps = self.load_data(name, data.into_boxed_slice())?; - self.cir_dep.remove(name); - - Ok(Some(deps)) + Ok(deps) } pub fn load_data(&mut self, name: &str, data: Box<[u8]>) -> Result> { @@ -164,12 +151,7 @@ impl Linker { // It should be previously resolved so we don't need to worry about it Ok(None) } else if name.contains('/') { - Ok(Some(self.load_recursive(name, name)? - .ok_or(Error::Malformed(format!( - "failed to find '{}'", - name - )))? - )) + Ok(Some(self.load_recursive(name, name)?)) } else { let library_path = self.library_path.clone(); for part in library_path.split(PATH_SEP) { @@ -181,8 +163,19 @@ impl Linker { if self.verbose { println!("check {}", path); } - if let Some(deps) = self.load_recursive(name, &path)? { - return Ok(Some(deps)); + let access = unsafe { + let path_c = CString::new(path.as_bytes()).map_err(|err| { + Error::Malformed(format!("invalid path '{}': {}", path, err)) + })?; + + // TODO: Use R_OK | X_OK + // We cannot use unix stdlib because errno is thead local variable + // and fs:[0] is not set yet. + access(path_c.as_ptr(), unistd::F_OK) == 0 + }; + + if access { + return Ok(Some(self.load_recursive(name, &path)?)); } } diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index fbb62f290a..baa253e6e6 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -1,13 +1,15 @@ use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader}; use self::tcb::{Master, Tcb}; -use crate::{c_str::CStr, platform::types::*, start::Stack}; +use crate::start::Stack; pub const PAGE_SIZE: usize = 4096; +mod access; pub mod debug; pub mod linker; pub mod start; pub mod tcb; + pub fn static_init(sp: &'static Stack) { let mut phdr_opt = None; let mut phent_opt = None;