Add VerNeed parsing for entries in the GNU extension section .gnu.version_r

These are one type of entries found in the .gnu.version_r section of type SHT_GNU_VERNEED.
This only parses the type, and is not hooked up to anything else yet.
This commit is contained in:
Christopher Cole 2022-10-25 18:19:06 -07:00
parent c8cb21089e
commit 929e099769
No known key found for this signature in database
GPG Key ID: 0AC856975983E9DB

View File

@ -114,6 +114,45 @@ impl ParseAt for VerDefAux {
}
}
/// The GNU extension section .gnu.version_r has a section type of SHT_GNU_VERNEED.
/// This section contains required symbol version definitions. The number of
/// entries in this section shall be contained in the DT_VERNEEDNUM entry of the
/// Dynamic Section .dynamic. The sh_link member of the section header shall
/// point to the referenced string table section.
///
/// The section shall contain an array of VerNeed structures optionally
/// followed by an array of VerNeedAux structures.
#[derive(Debug, PartialEq)]
pub struct VerNeed {
/// Version of structure. This value is currently set to 1.
pub vn_version: u16,
/// Number of associated verneed array entries.
pub vn_cnt: u16,
/// Offset to the file name string in the linked string table, in bytes.
pub vn_file: u32,
/// Offset to a corresponding entry in the VerNeedAux array, in bytes.
pub vn_aux: u32,
/// Offset to the next VerNeed entry, in bytes.
pub vn_next: u32,
}
impl ParseAt for VerNeed {
fn parse_at<P: EndianParseExt>(
endian: Endian,
_class: Class,
offset: &mut usize,
parser: &P,
) -> Result<Self, ParseError> {
Ok(VerNeed {
vn_version: parser.parse_u16_at(endian, offset)?,
vn_cnt: parser.parse_u16_at(endian, offset)?,
vn_file: parser.parse_u32_at(endian, offset)?,
vn_aux: parser.parse_u32_at(endian, offset)?,
vn_next: parser.parse_u32_at(endian, offset)?,
})
}
}
#[cfg(test)]
mod parse_tests {
use super::*;
@ -344,4 +383,87 @@ mod parse_tests {
);
}
}
//
// VerNeed
//
const ELFVERNEEDSIZE: usize = 16;
#[test]
fn parse_verneed32_lsb() {
let mut data = [0u8; ELFVERNEEDSIZE as usize];
for n in 0..ELFVERNEEDSIZE {
data[n as usize] = n as u8;
}
let mut offset = 0;
let entry = VerNeed::parse_at(Endian::Little, Class::ELF32, &mut offset, &data.as_ref())
.expect("Failed to parse VerNeed");
assert_eq!(
entry,
VerNeed {
vn_version: 0x0100,
vn_cnt: 0x0302,
vn_file: 0x07060504,
vn_aux: 0x0B0A0908,
vn_next: 0x0F0E0D0C,
}
);
assert_eq!(offset, ELFVERNEEDSIZE);
}
#[test]
fn parse_verneed32_fuzz_too_short() {
let data = [0u8; ELFVERNEEDSIZE];
for n in 0..ELFVERNEEDSIZE {
let buf = data.split_at(n).0.as_ref();
let mut offset: usize = 0;
let error = VerNeed::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_verneed64_msb() {
let mut data = [0u8; ELFVERNEEDSIZE as usize];
for n in 0..ELFVERNEEDSIZE {
data[n as usize] = n as u8;
}
let mut offset = 0;
let entry = VerNeed::parse_at(Endian::Big, Class::ELF64, &mut offset, &data.as_ref())
.expect("Failed to parse VerNeed");
assert_eq!(
entry,
VerNeed {
vn_version: 0x0001,
vn_cnt: 0x0203,
vn_file: 0x04050607,
vn_aux: 0x08090A0B,
vn_next: 0x0C0D0E0F,
}
);
assert_eq!(offset, ELFVERNEEDSIZE);
}
#[test]
fn parse_verneed64_fuzz_too_short() {
let data = [0u8; ELFVERNEEDSIZE];
for n in 0..ELFVERNEEDSIZE {
let buf = data.split_at(n).0.as_ref();
let mut offset: usize = 0;
let error = VerNeed::parse_at(Endian::Big, Class::ELF64, &mut offset, &buf)
.expect_err("Expected an error");
assert!(
matches!(error, ParseError::BadOffset(_)),
"Unexpected Error type found: {error}"
);
}
}
}