Add VerDef parsing for entries in the GNU extension section .gnu.version_d

These type of entries are found in the .gnu.version_d section of type SHT_GNU_VERDEF,
alongside VerDefAux (not yet defined).
This only parses the type, and is not hooked up to anything else yet.
This commit is contained in:
Christopher Cole 2022-10-25 17:22:28 -07:00
parent 2142af70e0
commit f35a2936b4
No known key found for this signature in database
GPG Key ID: 0AC856975983E9DB

View File

@ -3,7 +3,7 @@ use crate::parse::{Class, Endian, EndianParseExt, ParseAt, ParseError, ParsingIt
pub type VersionIndexIterator<'data> = ParsingIterator<'data, VersionIndex>;
/// The special GNU extension section .gnu.version has a section type of SHT_GNU_versym.
/// The special GNU extension section .gnu.version has a section type of SHT_GNU_VERSYM.
/// This section shall have the same number of entries as the Dynamic Symbol Table in
/// the .dynsym section. The .gnu.version section shall contain an array of
/// elements of type Elfxx_Half (both of which are 16-bit unsigned integers).
@ -46,6 +46,51 @@ impl ParseAt for VersionIndex {
}
}
/// The special GNU extension section .gnu.version_d has a section type of SHT_GNU_VERDEF
/// This section shall contain symbol version definitions. The number of entries
/// in this section shall be contained in the DT_VERDEFNUM entry of the Dynamic
/// Section .dynamic. The sh_link member of the section header shall point to
/// the section that contains the strings referenced by this section.
///
/// The .gnu.version_d section shall contain an array of VerDef structures
/// optionally followed by an array of VerDefAux structures.
#[derive(Debug, PartialEq)]
pub struct VerDef {
/// Version revision. This field shall be set to 1.
pub vd_version: u16,
/// Version information flag bitmask.
pub vd_flags: u16,
/// VersionIndex value referencing the SHT_GNU_VERSYM section.
pub vd_ndx: u16,
/// Number of associated verdaux array entries.
pub vd_cnt: u16,
/// Version name hash value (ELF hash function).
pub vd_hash: u32,
/// Offset in bytes to a corresponding entry in an array of VerDefAux structures.
pub vd_aux: u32,
/// Offset to the next VerDef entry, in bytes.
pub vd_next: u32,
}
impl ParseAt for VerDef {
fn parse_at<P: EndianParseExt>(
endian: Endian,
_class: Class,
offset: &mut usize,
parser: &P,
) -> Result<Self, ParseError> {
Ok(VerDef {
vd_version: parser.parse_u16_at(endian, offset)?,
vd_flags: parser.parse_u16_at(endian, offset)?,
vd_ndx: parser.parse_u16_at(endian, offset)?,
vd_cnt: parser.parse_u16_at(endian, offset)?,
vd_hash: parser.parse_u32_at(endian, offset)?,
vd_aux: parser.parse_u32_at(endian, offset)?,
vd_next: parser.parse_u32_at(endian, offset)?,
})
}
}
#[cfg(test)]
mod parse_tests {
use super::*;
@ -114,4 +159,93 @@ mod parse_tests {
);
}
}
//
// VerDef
//
const ELFVERDEFSIZE: usize = 20;
#[test]
fn parse_verdef32_lsb() {
// All symbol tables are defined to have a zeroed out symbol at index 0.
let mut data = [0u8; ELFVERDEFSIZE as usize];
for n in 0..ELFVERDEFSIZE {
data[n as usize] = n as u8;
}
let mut offset = 0;
let entry = VerDef::parse_at(Endian::Little, Class::ELF32, &mut offset, &data.as_ref())
.expect("Failed to parse VerDef");
assert_eq!(
entry,
VerDef {
vd_version: 0x0100,
vd_flags: 0x0302,
vd_ndx: 0x0504,
vd_cnt: 0x0706,
vd_hash: 0x0B0A0908,
vd_aux: 0x0F0E0D0C,
vd_next: 0x13121110,
}
);
assert_eq!(offset, ELFVERDEFSIZE);
}
#[test]
fn parse_verdef32_fuzz_too_short() {
let data = [0u8; ELFVERDEFSIZE];
for n in 0..ELFVERDEFSIZE {
let buf = data.split_at(n).0.as_ref();
let mut offset: usize = 0;
let error = VerDef::parse_at(Endian::Big, Class::ELF32, &mut offset, &buf)
.expect_err("Expected an error");
assert!(
matches!(error, ParseError::BadOffset(_)),
"Unexpected Error type found: {error}"
);
}
}
#[test]
fn parse_verdef64_msb() {
// All symbol tables are defined to have a zeroed out symbol at index 0.
let mut data = [0u8; ELFVERDEFSIZE as usize];
for n in 0..ELFVERDEFSIZE {
data[n as usize] = n as u8;
}
let mut offset = 0;
let entry = VerDef::parse_at(Endian::Big, Class::ELF64, &mut offset, &data.as_ref())
.expect("Failed to parse VerDef");
assert_eq!(
entry,
VerDef {
vd_version: 0x0001,
vd_flags: 0x0203,
vd_ndx: 0x0405,
vd_cnt: 0x0607,
vd_hash: 0x08090A0B,
vd_aux: 0x0C0D0E0F,
vd_next: 0x10111213,
}
);
assert_eq!(offset, ELFVERDEFSIZE);
}
#[test]
fn parse_verdef64_fuzz_too_short() {
let data = [0u8; ELFVERDEFSIZE];
for n in 0..ELFVERDEFSIZE {
let buf = data.split_at(n).0.as_ref();
let mut offset: usize = 0;
let error = VerDef::parse_at(Endian::Big, Class::ELF64, &mut offset, &buf)
.expect_err("Expected an error");
assert!(
matches!(error, ParseError::BadOffset(_)),
"Unexpected Error type found: {error}"
);
}
}
}