Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elf gnu symbol versioning #280

Merged
merged 20 commits into from Sep 14, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0ab34dc
elf.dynamic: Parse DT_VERDEF + DT_VERDEFNUM dynamic tags into Dynamic…
johannst Aug 10, 2021
7a1a6e6
elf.symver: add struct definitions and reading part for .gnu.version_…
johannst Aug 13, 2021
dc1e26b
elf.symver: add tests for parsing .gnu.version_r section
johannst Aug 13, 2021
85ed28d
elf.symver: make structs used by user more ergonomic by using usize
johannst Aug 13, 2021
de9a4e7
elf.symver: API updates
johannst Aug 14, 2021
61c00ef
elf.symver: add struct definitions and reading part for .gnu.version_…
johannst Aug 15, 2021
753ad13
elf.symver: Use sub-module as feature guard
johannst Aug 15, 2021
8b882af
add tests for parsing .gnu.version_d section
johannst Aug 15, 2021
89697c4
elf.symver: add struct definitions and reading part for .gnu.version …
johannst Aug 15, 2021
b472420
elf.symver: add tests for parsing .gnu.version section
johannst Aug 15, 2021
fa03ec3
elf.symver: fix clippy warnings
johannst Aug 15, 2021
8bd8bc8
elf.symver: added some convenience methods to Verdef
johannst Aug 15, 2021
097d6e5
elf.symver: apply review feedback
johannst Aug 16, 2021
b2d780f
elf.symver: apply review feedback
johannst Aug 16, 2021
7c41301
elf.symver: apply review feedback
johannst Aug 17, 2021
8dad2eb
elf.symver: add doc comments to constants and move field doc comments…
johannst Aug 17, 2021
49d2b38
elf.symver: fix comments in test
johannst Sep 5, 2021
74e6fb0
elf.symver: move cfg guard globally on module
johannst Sep 6, 2021
f029db3
elf.symver: apply review feedback
johannst Sep 8, 2021
5bc5c52
elf.symver: apply review feedback
johannst Sep 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
66 changes: 8 additions & 58 deletions src/elf/symver.rs
Expand Up @@ -17,10 +17,10 @@
//! for need_file in verneed.iter() {
//! println!(
//! "Depend on {:?} with version(s):",
//! verneed.verstr.get_at(need_file.vn_file)
//! binary.dynstrtab.get_at(need_file.vn_file)
//! );
//! for need_ver in need_file.iter() {
//! println!("{:?}", verneed.verstr.get_at(need_ver.vna_name));
//! println!("{:?}", binary.dynstrtab.get_at(need_ver.vna_name));
//! }
//! }
//! }
Expand All @@ -40,7 +40,7 @@
//! if let Some(verdef) = &binary.verdef {
//! for def in verdef.iter() {
//! for (n, aux) in def.iter().enumerate() {
//! let name = verdef.verstr.get_at(aux.vda_name);
//! let name = binary.dynstrtab.get_at(aux.vda_name);
//! match n {
//! 0 => print!("Name: {:?}", name),
//! 1 => print!(" Parent: {:?}", name),
Expand All @@ -61,8 +61,7 @@

use crate::container;
use crate::elf::section_header::{SectionHeader, SHT_GNU_VERDEF, SHT_GNU_VERNEED, SHT_GNU_VERSYM};
use crate::error::{Error, Result};
use crate::strtab::Strtab;
use crate::error::Result;
use core::iter::FusedIterator;
use scroll::Pread;

Expand Down Expand Up @@ -320,7 +319,6 @@ impl From<ElfVersym> for Versym {
#[derive(Debug)]
pub struct VerdefSection<'a> {
/// String table used to resolve version strings.
pub verstr: Strtab<'a>,
bytes: &'a [u8],
count: usize,
ctx: container::Ctx,
Expand All @@ -333,10 +331,9 @@ impl<'a> VerdefSection<'a> {
ctx: container::Ctx,
) -> Result<Option<VerdefSection<'a>>> {
// Get fields needed from optional `version definition` section.
let (link_idx, offset, size, count) =
let (offset, size, count) =
if let Some(shdr) = shdrs.iter().find(|shdr| shdr.sh_type == SHT_GNU_VERDEF) {
(
shdr.sh_link as usize, // Encodes the string table.
shdr.sh_offset as usize,
shdr.sh_size as usize,
shdr.sh_info as usize, // Encodes the number of ElfVerdef entries.
Expand All @@ -345,32 +342,10 @@ impl<'a> VerdefSection<'a> {
return Ok(None);
};

// Get string table which is used to resolve version strings.
let verstr = {
// Linked section refers to string table.
let shdr_link = shdrs.get(link_idx).ok_or_else(|| {
Error::Malformed(
"Section header of string table for SHT_GNU_VERDEF section not found!".into(),
)
})?;

Strtab::parse(
bytes,
shdr_link.sh_offset as usize,
shdr_link.sh_size as usize,
0x0, /* Delimiter */
)?
};

// Get a slice of bytes of the `version definition` section content.
let bytes: &'a [u8] = bytes.pread_with(offset, size)?;

Ok(Some(VerdefSection {
verstr,
bytes,
count,
ctx,
}))
Ok(Some(VerdefSection { bytes, count, ctx }))
}

/// Get an iterator over the [`Verdef`] entries.
Expand Down Expand Up @@ -597,8 +572,6 @@ pub struct Verdaux {
/// Auxiliary][Vernaux] entries.
#[derive(Debug)]
pub struct VerneedSection<'a> {
/// String table used to resolve version strings.
pub verstr: Strtab<'a>,
johannst marked this conversation as resolved.
Show resolved Hide resolved
bytes: &'a [u8],
count: usize,
ctx: container::Ctx,
Expand All @@ -612,10 +585,9 @@ impl<'a> VerneedSection<'a> {
ctx: container::Ctx,
) -> Result<Option<VerneedSection<'a>>> {
// Get fields needed from optional `version needed` section.
let (link_idx, offset, size, count) =
let (offset, size, count) =
if let Some(shdr) = shdrs.iter().find(|shdr| shdr.sh_type == SHT_GNU_VERNEED) {
(
shdr.sh_link as usize, // Encodes the string table.
shdr.sh_offset as usize,
shdr.sh_size as usize,
shdr.sh_info as usize, // Encodes the number of ElfVerneed entries.
Expand All @@ -624,32 +596,10 @@ impl<'a> VerneedSection<'a> {
return Ok(None);
};

// Get string table which is used to resolve version strings.
let verstr = {
// Linked section refers to string table.
let shdr_link = shdrs.get(link_idx).ok_or_else(|| {
Error::Malformed(
"Section header of string table for SHT_GNU_VERNEED section not found!".into(),
)
})?;

Strtab::parse(
bytes,
shdr_link.sh_offset as usize,
shdr_link.sh_size as usize,
0x0, /* Delimiter */
)?
};

// Get a slice of bytes of the `version needed` section content.
let bytes: &'a [u8] = bytes.pread_with(offset, size)?;

Ok(Some(VerneedSection {
verstr,
bytes,
count,
ctx,
}))
Ok(Some(VerneedSection { bytes, count, ctx }))
}

/// Get an iterator over the [`Verneed`] entries.
Expand Down
23 changes: 13 additions & 10 deletions tests/elf.rs
@@ -1,8 +1,10 @@
use goblin::elf::section_header::SHT_GNU_HASH;
use goblin::elf::sym::Sym;
use goblin::elf::sym::{Sym, Symtab};
use goblin::elf::symver::{VerdefSection, VerneedSection, VersymSection};
use goblin::elf::Elf;
use goblin::elf32::gnu_hash::GnuHash as GnuHash32;
use goblin::elf64::gnu_hash::GnuHash as GnuHash64;
use goblin::strtab::Strtab;

#[repr(C)]
#[repr(align(64))] // Align to cache lines
Expand Down Expand Up @@ -39,7 +41,6 @@ fn parse_text_section_size_lazy(base: &[u8]) -> Result<u64, &'static str> {

use goblin::container::{Container, Ctx};
use goblin::elf::SectionHeader;
use goblin::strtab::Strtab;

let ctx = Ctx {
le: scroll::Endian::Little,
Expand Down Expand Up @@ -258,7 +259,7 @@ fn check_symver_expectations(
assert!(elf.verneed.is_some());

let verneed = elf.verneed.as_ref().unwrap();
check_symver_expectations_verneed(verneed, expect_verneed);
check_symver_expectations_verneed(verneed, expect_verneed, &elf.dynstrtab);
}

if expect_verdef.is_empty() {
Expand All @@ -269,15 +270,15 @@ fn check_symver_expectations(
assert!(elf.verdef.is_some());

let verdef = elf.verdef.as_ref().unwrap();
check_symver_expectations_verdef(verdef, expect_verdef);
check_symver_expectations_verdef(verdef, expect_verdef, &elf.dynstrtab);
}

Ok(())
}

fn check_symver_expectations_versym(
versym: &goblin::elf::VersymSection<'_>,
dynsyms: &goblin::elf::Symtab<'_>,
versym: &VersymSection<'_>,
dynsyms: &Symtab<'_>,
expect_versym: &Vec<u16>,
) {
// VERSYM section must contain one entry per DYNSYM.
Expand All @@ -298,11 +299,12 @@ fn check_symver_expectations_versym(
}

fn check_symver_expectations_verneed(
verneed: &goblin::elf::VerneedSection<'_>,
verneed: &VerneedSection<'_>,
expect_verneed: &SymverExpectation,
strtab: &Strtab<'_>,
) {
// Resolve version strings.
let verstr = |idx| verneed.verstr.get_at(idx).unwrap();
let verstr = |idx| strtab.get_at(idx).unwrap();

// ELF file dependencies with version requirements.
let need_files: Vec<_> = verneed.iter().collect();
Expand Down Expand Up @@ -349,11 +351,12 @@ fn check_symver_expectations_verneed(
}

fn check_symver_expectations_verdef(
verdef: &goblin::elf::VerdefSection<'_>,
verdef: &VerdefSection<'_>,
expect_verdef: &SymverExpectation,
strtab: &Strtab<'_>,
) {
// Resolve version strings.
let verstr = |idx| verdef.verstr.get_at(idx).unwrap();
let verstr = |idx| strtab.get_at(idx).unwrap();

// ELF version definitions.
let defined_vers: Vec<_> = verdef.iter().collect();
Expand Down