From 61fcc018fcf5f154f3eb0532a589745febe84e62 Mon Sep 17 00:00:00 2001 From: oddcoder <ahmedsoliman@oddcoder.com> Date: Mon, 10 Aug 2020 23:22:17 +0200 Subject: [PATCH] Refer to libraries with soname if available and avoid loading libs twice It is usually not optimal to load a library twice and for specifics, it is **terrible** idea to load libc twice it was enough trouble dealing with libc statically linked into ld.so. So What this patch does it check for soname and if a library is already loaded it won't get loaded again. Why soname ? because unfortunately some bins gets linked againt libc.so while of their dependencies gets linked against libc.so.6 while one is usually symbolic link for the other. --- src/ld_so/linker.rs | 79 ++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index c55e4a7d..34030513 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -15,9 +15,7 @@ use goblin::{ header::ET_DYN, program_header, r#dyn::{Dyn, DT_DEBUG}, - reloc, - sym, - Elf, + reloc, sym, Elf, }, error::{Error, Result}, }; @@ -25,7 +23,7 @@ use goblin::{ use crate::{ c_str::CString, fs::File, - header::{fcntl, sys_mman, unistd, errno::STR_ERROR}, + header::{errno::STR_ERROR, fcntl, sys_mman, unistd}, io::Read, platform::{errno, types::c_void}, }; @@ -147,9 +145,14 @@ impl Linker { deps.push(dep); } } - - lib.objects.insert(name.to_string(), data); - + let elf = Elf::parse(&data)?; + let key = match elf.soname { + Some(soname) => soname, + _ => name, + }; + if !lib.objects.contains_key(key) { + lib.objects.insert(key.to_string(), data); + } return Ok(deps); } @@ -471,11 +474,19 @@ impl Linker { -1, 0, ); - if ptr as usize == !0 /* MAP_FAILED */ { - return Err(Error::Malformed(format!("failed to map {}. errno: {}", elf_name, STR_ERROR[errno as usize]))); + if ptr as usize == !0 + /* MAP_FAILED */ + { + return Err(Error::Malformed(format!( + "failed to map {}. errno: {}", + elf_name, STR_ERROR[errno as usize] + ))); } if start as *mut c_void != ptr::null_mut() { - assert_eq!(ptr, start as *mut c_void, "mmap must always map on the destination we requested"); + assert_eq!( + ptr, start as *mut c_void, + "mmap must always map on the destination we requested" + ); } } start = addr + vaddr + vsize @@ -486,7 +497,10 @@ impl Linker { sys_mman::PROT_READ | sys_mman::PROT_WRITE, ); _r_debug.insert_first(addr as usize, &elf_name, addr + l_ld as usize); - (addr as usize, slice::from_raw_parts_mut(addr as *mut u8, size)) + ( + addr as usize, + slice::from_raw_parts_mut(addr as *mut u8, size), + ) } else { let (start, end) = bounds; let size = end - start; @@ -504,11 +518,19 @@ impl Linker { -1, 0, ); - if ptr as usize == !0 /* MAP_FAILED */ { - return Err(Error::Malformed(format!("failed to map {}. errno: {}", elf_name, STR_ERROR[errno as usize]))); + if ptr as usize == !0 + /* MAP_FAILED */ + { + return Err(Error::Malformed(format!( + "failed to map {}. errno: {}", + elf_name, STR_ERROR[errno as usize] + ))); } if start as *mut c_void != ptr::null_mut() { - assert_eq!(ptr, start as *mut c_void, "mmap must always map on the destination we requested"); + assert_eq!( + ptr, start as *mut c_void, + "mmap must always map on the destination we requested" + ); } ptr::write_bytes(ptr as *mut u8, 0, size); _r_debug.insert(ptr as usize, &elf_name, ptr as usize + l_ld as usize); @@ -590,7 +612,8 @@ impl Linker { }; let mmap_data = { - let range = ph.p_vaddr as usize - base_addr..ph.p_vaddr as usize + obj_data.len() - base_addr; + let range = ph.p_vaddr as usize - base_addr + ..ph.p_vaddr as usize + obj_data.len() - base_addr; match mmap.get_mut(range.clone()) { Some(some) => some, None => { @@ -598,7 +621,7 @@ impl Linker { return Err(Error::Malformed(format!( "failed to write {:x?}", range - ))) + ))); } } }; @@ -690,18 +713,20 @@ impl Linker { let name = elf.dynstrtab - .get(sym.st_name) - .ok_or(Error::Malformed(format!( - "missing name for symbol {:?}", - sym - )))??; - lib.get_sym(name) - .or_else(|| self.root.get_sym(name)) + .get(sym.st_name) + .ok_or(Error::Malformed(format!( + "missing name for symbol {:?}", + sym + )))??; + lib.get_sym(name).or_else(|| self.root.get_sym(name)) } else { None }; - let s = symbol.as_ref().map(|sym| sym.as_ptr() as usize).unwrap_or(0); + let s = symbol + .as_ref() + .map(|sym| sym.as_ptr() as usize) + .unwrap_or(0); let a = rel.r_addend.unwrap_or(0) as usize; @@ -757,9 +782,11 @@ impl Linker { reloc::R_X86_64_IRELATIVE => (), // Handled below reloc::R_X86_64_COPY => unsafe { // TODO: Make this work - let sym = symbol.as_ref().expect("R_X86_64_COPY called without valid symbol"); + let sym = symbol + .as_ref() + .expect("R_X86_64_COPY called without valid symbol"); ptr::copy_nonoverlapping(sym.as_ptr() as *const u8, ptr, sym.size as usize); - } + }, _ => { panic!( " {} unsupported", -- GitLab