Add support for RUNPATH

This commit is contained in:
Mateusz Tabaka
2020-09-29 19:30:42 +02:00
parent 58cc9efbc0
commit 7829a7ade9
3 changed files with 36 additions and 12 deletions
+1
View File
@@ -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 {
+33 -7
View File
@@ -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 {
+2 -5
View File
@@ -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) => {