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