From c3ae8022bad7e1aca96524ff47558bd5f5ae9cde Mon Sep 17 00:00:00 2001 From: no name Date: Tue, 9 Jun 2020 11:18:28 +0000 Subject: [PATCH 1/3] Revert "Handle missing paths in load_library search without using access" This reverts commit b0dde81c75255abddfb6acff9f3a4b14ba804346. The main issue was not with "access" being used, it was with errno being accessed. This patch accesses errno as well LD_LIBRARY_PATH="/folder/with/no/libc" ./a.out gives segfault with the following stack trace 0x00000000004d1cae in relibc::platform::sys::e (sys=18446744073709551614) at src/platform/linux/mod.rs:54 54 errno = -(sys as isize) as c_int; (gdb) bt #0 0x00000000004d1cae in relibc::platform::sys::e (sys=18446744073709551614) at src/platform/linux/mod.rs:54 #1 0x00000000004d361e in ::open (path=0x5555555634c0, oflag=524288, mode=0) at src/platform/linux/mod.rs:330 #2 0x000000000049a2ad in relibc::fs::File::open (path=0x5555555634c0, oflag=524288) at src/fs.rs:28 #3 0x0000000000482b49 in relibc::ld_so::linker::Linker::load_recursive (self=0x7fffffffdd30, name=..., path=...) at src/ld_so/linker.rs:119 #4 0x0000000000484963 in relibc::ld_so::linker::Linker::load_library (self=0x7fffffffdd30, name=...) at src/ld_so/linker.rs:184 #5 0x0000000000483b53 in relibc::ld_so::linker::Linker::load_data (self=0x7fffffffdd30, name=..., data=...) at src/ld_so/linker.rs:152 #6 0x00000000004831fe in relibc::ld_so::linker::Linker::load_recursive (self=0x7fffffffdd30, name=..., path=...) at src/ld_so/linker.rs:140 #7 0x000000000048228a in relibc::ld_so::linker::Linker::load (self=0x7fffffffdd30, name=..., path=...) at src/ld_so/linker.rs:97 #8 0x0000000000414a3b in relibc_ld_so_start (sp=0x7fffffffe310, ld_entry=4198896) at src/ld_so/start.rs:182 #9 0x0000000000401209 in _start () at src/ld_so/src/lib.rs:10 #10 0x0000000000000001 in ?? () #11 0x00007fffffffe592 in ?? () #12 0x0000000000000000 in ?? () --- src/ld_so/linker.rs | 58 +++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index a835a2e917..b70a46faed 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -21,7 +21,7 @@ use crate::{ c_str::CString, fs::File, header::{fcntl, sys_mman, unistd}, - io::{self, Read}, + io::Read, platform::types::c_void, }; @@ -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,9 +163,7 @@ impl Linker { if self.verbose { println!("check {}", path); } - if let Some(deps) = self.load_recursive(name, &path)? { - return Ok(Some(deps)); - } + return Ok(Some(self.load_recursive(name, &path)?)); } Err(Error::Malformed(format!("failed to locate '{}'", name))) From d5b63a85a4a49a3314e86ed12762bcf813c61a2f Mon Sep 17 00:00:00 2001 From: no name Date: Tue, 9 Jun 2020 11:20:43 +0000 Subject: [PATCH 2/3] Revert "Fix compilation on Redox by removing use of access in ld_so" This reverts commit d9bacaec0477ec494bf8937126aa5eb3e6cfabd0. --- src/ld_so/linker.rs | 16 +++++++++++++++- src/ld_so/mod.rs | 6 ++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index b70a46faed..149f26543f 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -26,6 +26,7 @@ use crate::{ }; use super::{ + access, debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug}, tcb::{Master, Tcb}, PAGE_SIZE, @@ -163,7 +164,20 @@ impl Linker { if self.verbose { println!("check {}", path); } - return Ok(Some(self.load_recursive(name, &path)?)); + 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)?)); + } } Err(Error::Malformed(format!("failed to locate '{}'", name))) diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index fbb62f290a..b39a5e7e26 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -79,6 +79,12 @@ pub fn static_init(sp: &'static Stack) { } } +// Wrapper over the systemcall, Do not use outside of ld_so +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 +} + #[cfg(target_os = "linux")] pub unsafe fn init(sp: &'static Stack) { let mut tp = 0usize; From 81da1bb1a3eb70e6c4c47f14b49ab419d501d277 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Sat, 13 Jun 2020 19:50:08 +0200 Subject: [PATCH 3/3] Fix the avoid accessing errno issue from ld_so for real this time This patch implements access function for both redox and linux and makes sure that neither access errno variable --- src/ld_so/access.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++ src/ld_so/linker.rs | 3 +-- src/ld_so/mod.rs | 10 +++------ 3 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 src/ld_so/access.rs 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 149f26543f..ff6d89669a 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -26,12 +26,11 @@ use crate::{ }; use super::{ - access, + access::access, debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug}, tcb::{Master, Tcb}, PAGE_SIZE, }; - #[cfg(target_os = "redox")] const PATH_SEP: char = ';'; diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index b39a5e7e26..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; @@ -79,12 +81,6 @@ pub fn static_init(sp: &'static Stack) { } } -// Wrapper over the systemcall, Do not use outside of ld_so -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 -} - #[cfg(target_os = "linux")] pub unsafe fn init(sp: &'static Stack) { let mut tp = 0usize;