From 7829a7ade9ded4a2eb981542d82a408b3ac1af82 Mon Sep 17 00:00:00 2001 From: Mateusz Tabaka <tab.debugteam@gmail.com> Date: Tue, 29 Sep 2020 19:30:42 +0200 Subject: [PATCH] Add support for RUNPATH --- src/ld_so/library.rs | 1 + src/ld_so/linker.rs | 40 +++++++++++++++++++++++++++++++++------- src/ld_so/start.rs | 7 ++----- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/ld_so/library.rs b/src/ld_so/library.rs index 88958e01..19862f7e 100644 --- a/src/ld_so/library.rs +++ b/src/ld_so/library.rs @@ -36,6 +36,7 @@ pub struct Library { pub dep_tree: DepTree, /// A set used to detect circular dependencies in the Linker::load function pub cir_dep: BTreeSet<String>, + pub runpath: Option<String>, } impl Library { pub fn new() -> Library { diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index a091e857..3f6b4d4c 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -14,7 +14,7 @@ use goblin::{ elf::{ header::ET_DYN, program_header, - r#dyn::{Dyn, DT_DEBUG}, + r#dyn::{Dyn, DT_DEBUG, DT_RUNPATH}, reloc, sym, Elf, }, error::{Error, Result}, @@ -63,7 +63,8 @@ impl Symbol { pub struct Linker { // Used by load /// Library path to search when loading library by name - library_path: String, + default_library_path: String, + ld_library_path: Option<String>, root: Library, verbose: bool, tls_index_offset: usize, @@ -73,9 +74,10 @@ pub struct Linker { } impl Linker { - pub fn new(library_path: &str, verbose: bool) -> Self { + pub fn new(ld_library_path: Option<String>, verbose: bool) -> Self { Self { - library_path: library_path.to_string(), + default_library_path: "/lib".to_string(), + ld_library_path: ld_library_path, root: Library::new(), verbose, tls_index_offset: 0, @@ -139,13 +141,30 @@ impl Linker { ) -> Result<Vec<DepTree>> { let elf = Elf::parse(&data)?; //println!("{:#?}", elf); + + // search for RUNPATH + lib.runpath = if let Some(dynamic) = elf.dynamic { + let entry = dynamic.dyns.iter().find(|d| d.d_tag == DT_RUNPATH); + match entry { + Some(entry) => { + let path = elf + .dynstrtab + .get(entry.d_val as usize) + .ok_or(Error::Malformed("Missing RUNPATH in dynstrtab".to_string()))??; + Some(path.to_string()) + } + _ => None, + } + } else { + None + }; + let mut deps = Vec::new(); for library in elf.libraries.iter() { if let Some(dep) = self._load_library(library, lib)? { deps.push(dep); } } - let elf = Elf::parse(&data)?; let key = match elf.soname { Some(soname) => soname, _ => name, @@ -171,8 +190,15 @@ impl Linker { } else if name.contains('/') { Ok(Some(self.load_recursive(name, name, lib)?)) } else { - let library_path = self.library_path.clone(); - for part in library_path.split(PATH_SEP) { + let mut paths = Vec::new(); + if let Some(ld_library_path) = &self.ld_library_path { + paths.push(ld_library_path); + } + if let Some(runpath) = &lib.runpath { + paths.push(runpath); + } + paths.push(&self.default_library_path); + for part in paths.iter() { let path = if part.is_empty() { format!("./{}", name) } else { diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs index 153b8992..6a9439d0 100644 --- a/src/ld_so/start.rs +++ b/src/ld_so/start.rs @@ -183,10 +183,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> } // Some variables that will be overridden by environment and auxiliary vectors - let library_path = match envs.get("LD_LIBRARY_PATH") { - Some(lib_path) => lib_path.to_owned() + ":/lib", - None => "/lib".to_owned(), - }; + let ld_library_path = envs.get("LD_LIBRARY_PATH").map(|s| s.to_owned()); let name_or_path = if is_manual { // ld.so is run directly by user and not via execve() or similar systemcall @@ -234,7 +231,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> } pr }; - let mut linker = Linker::new(&library_path, false); + let mut linker = Linker::new(ld_library_path, false); match linker.load(&path, &path) { Ok(()) => (), Err(err) => { -- GitLab