From 7b58f789730de9716335b7fe496e3864d57b1594 Mon Sep 17 00:00:00 2001 From: robbje <359146+robbje@users.noreply.github.com> Date: Sun, 9 Jun 2024 15:18:17 +0200 Subject: [PATCH] elf: parse library from symbol versioning table (#693) --- crates/examples/testfiles/elf/base-aarch64.objdump | 8 ++++---- crates/examples/testfiles/elf/base.objdump | 6 +++--- src/read/elf/file.rs | 14 +++++++++++--- src/read/elf/version.rs | 13 ++++++++++++- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/crates/examples/testfiles/elf/base-aarch64.objdump b/crates/examples/testfiles/elf/base-aarch64.objdump index 2c73255d..242a2cc0 100644 --- a/crates/examples/testfiles/elf/base-aarch64.objdump +++ b/crates/examples/testfiles/elf/base-aarch64.objdump @@ -152,12 +152,12 @@ Dynamic relocations (10fb8, Relocation { kind: Unknown, encoding: Generic, size: 0, target: Symbol(SymbolIndex(9)), addend: 0, implicit_addend: false, flags: Elf { r_type: 402 } }) Import { library: "", name: "_ITM_deregisterTMCloneTable" } -Import { library: "", name: "__cxa_finalize" } -Import { library: "", name: "__libc_start_main" } +Import { library: "libc.so.6", name: "__cxa_finalize" } +Import { library: "libc.so.6", name: "__libc_start_main" } Import { library: "", name: "__gmon_start__" } -Import { library: "", name: "abort" } +Import { library: "libc.so.6", name: "abort" } Import { library: "", name: "_ITM_registerTMCloneTable" } -Import { library: "", name: "printf" } +Import { library: "libc.so.6", name: "printf" } Symbol map 0x598 "_init" diff --git a/crates/examples/testfiles/elf/base.objdump b/crates/examples/testfiles/elf/base.objdump index 74d86f64..484db5cb 100644 --- a/crates/examples/testfiles/elf/base.objdump +++ b/crates/examples/testfiles/elf/base.objdump @@ -122,11 +122,11 @@ Dynamic relocations (200fd0, Relocation { kind: Unknown, encoding: Generic, size: 0, target: Symbol(SymbolIndex(2)), addend: 0, implicit_addend: false, flags: Elf { r_type: 7 } }) Import { library: "", name: "_ITM_deregisterTMCloneTable" } -Import { library: "", name: "printf" } -Import { library: "", name: "__libc_start_main" } +Import { library: "libc.so.6", name: "printf" } +Import { library: "libc.so.6", name: "__libc_start_main" } Import { library: "", name: "__gmon_start__" } Import { library: "", name: "_ITM_registerTMCloneTable" } -Import { library: "", name: "__cxa_finalize" } +Import { library: "libc.so.6", name: "__cxa_finalize" } Symbol map 0x520 "_init" diff --git a/src/read/elf/file.rs b/src/read/elf/file.rs index ca4e3ef9..01615e15 100644 --- a/src/read/elf/file.rs +++ b/src/read/elf/file.rs @@ -334,15 +334,23 @@ where } fn imports(&self) -> read::Result>> { + let versions = self.sections.versions(self.endian, self.data)?; + let mut imports = Vec::new(); - for symbol in self.dynamic_symbols.iter() { + for (index, symbol) in self.dynamic_symbols.enumerate() { if symbol.is_undefined(self.endian) { let name = symbol.name(self.endian, self.dynamic_symbols.strings())?; if !name.is_empty() { - // TODO: use symbol versioning to determine library + let library = if let Some(svt) = versions.as_ref() { + let vi = svt.version_index(self.endian, index); + svt.version(vi)?.and_then(|v| v.file()) + } else { + None + } + .unwrap_or(&[]); imports.push(Import { name: ByteString(name), - library: ByteString(&[]), + library: ByteString(library), }); } } diff --git a/src/read/elf/version.rs b/src/read/elf/version.rs index ae3f005b..d0bd504e 100644 --- a/src/read/elf/version.rs +++ b/src/read/elf/version.rs @@ -40,6 +40,7 @@ pub struct Version<'data> { hash: u32, // Used to keep track of valid indices in `VersionTable`. valid: bool, + file: Option<&'data [u8]>, } impl<'data> Version<'data> { @@ -52,6 +53,14 @@ impl<'data> Version<'data> { pub fn hash(&self) -> u32 { self.hash } + + /// Return the filename of the library containing this version. + /// + /// This is the `vn_file` field of the associated entry in [`elf::SHT_GNU_VERNEED`]. + /// or `None` if the version info was parsed from a [`elf::SHT_GNU_VERDEF`] section. + pub fn file(&self) -> Option<&'data [u8]> { + self.file + } } /// A table of version definitions and requirements. @@ -128,12 +137,13 @@ impl<'data, Elf: FileHeader> VersionTable<'data, Elf> { name: verdaux.name(endian, strings)?, hash: verdef.vd_hash.get(endian), valid: true, + file: None, }; } } } if let Some(mut verneeds) = verneeds { - while let Some((_, mut vernauxs)) = verneeds.next()? { + while let Some((verneed, mut vernauxs)) = verneeds.next()? { while let Some(vernaux) = vernauxs.next()? { let index = vernaux.vna_other.get(endian) & elf::VERSYM_VERSION; if index <= elf::VER_NDX_GLOBAL { @@ -144,6 +154,7 @@ impl<'data, Elf: FileHeader> VersionTable<'data, Elf> { name: vernaux.name(endian, strings)?, hash: vernaux.vna_hash.get(endian), valid: true, + file: Some(verneed.file(endian, strings)?), }; } }