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

Bug 1847098 - Add version number of so files #103

Merged
merged 2 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 77 additions & 5 deletions src/linux/maps_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,44 @@ impl MappingInfo {
Ok(soname.to_string())
}

pub fn get_mapping_effective_path_and_name(&self) -> Result<(PathBuf, String)> {
/// Attempts to retrieve the .so version of the elf via its filename as a
/// `(major, minor, release)` triplet
fn elf_file_so_version(&self) -> (u32, u32, u32) {
const DEF: (u32, u32, u32) = (0, 0, 0);
let Some(so_name) = self.name.as_deref() else {
return DEF;
};
let Some(filename) = std::path::Path::new(so_name).file_name() else {
return DEF;
};

// Avoid an allocation unless the string contains non-utf8
let filename = filename.to_string_lossy();

let Some((_, version)) = filename.split_once(".so.") else {
return DEF;
};

let mut triplet = [0, 0, 0];

for (so, trip) in version.split('.').zip(triplet.iter_mut()) {
// In some cases the release/patch version is alphanumeric (eg. '2rc5'),
// so try to parse as much as we can rather than completely ignoring
for digit in so
.chars()
.filter_map(|c: char| c.is_ascii_digit().then_some(c as u8 - b'0'))
{
*trip *= 10;
*trip += digit as u32;
}
}

(triplet[0], triplet[1], triplet[2])
}

pub fn get_mapping_effective_path_name_and_version(
&self,
) -> Result<(PathBuf, String, (u32, u32, u32))> {
let mut file_path = PathBuf::from(self.name.clone().unwrap_or_default());

// Tools such as minidump_stackwalk use the name of the module to look up
Expand All @@ -321,7 +358,7 @@ impl MappingInfo {
.file_name()
.map(|s| s.to_string_lossy().into_owned())
.unwrap_or_default();
return Ok((file_path, file_name));
return Ok((file_path, file_name, self.elf_file_so_version()));
};

if self.is_executable() && self.offset != 0 {
Expand All @@ -337,7 +374,7 @@ impl MappingInfo {
file_path.set_file_name(&file_name);
}

Ok((file_path, file_name))
Ok((file_path, file_name, self.elf_file_so_version()))
}

pub fn is_contained_in(&self, user_mapping_list: &MappingList) -> bool {
Expand Down Expand Up @@ -628,13 +665,48 @@ a4840000-a4873000 rw-p 09021000 08:12 393449 /data/app/org.mozilla.firefox-1
);
assert_eq!(mappings.len(), 1);

let (file_path, file_name) = mappings[0]
.get_mapping_effective_path_and_name()
let (file_path, file_name, _version) = mappings[0]
.get_mapping_effective_path_name_and_version()
.expect("Couldn't get effective name for mapping");
assert_eq!(file_name, "libmozgtk.so");
assert_eq!(file_path, PathBuf::from("/home/martin/Documents/mozilla/devel/mozilla-central/obj/widget/gtk/mozgtk/gtk3/libmozgtk.so"));
}

#[test]
fn test_elf_file_so_version() {
let mappings = get_mappings_for(
"\
7f877ab9f000-7f877aba0000 rw-p 0001f000 00:1b 100457459 /home/alex/bin/firefox/libmozsandbox.so
7f877ae65000-7f877ae68000 rw-p 00265000 00:1b 90432393 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.32
7f877ae76000-7f877ae77000 rw-p 0000a000 00:1b 90443112 /usr/lib/x86_64-linux-gnu/libcairo-gobject.so.2.11800.0
7f877ae7c000-7f877ae8c000 r--p 00000000 00:1b 93439971 /usr/lib/x86_64-linux-gnu/libm.so.6
7f877af70000-7f877af71000 rw-p 00003000 00:1b 93439980 /usr/lib/x86_64-linux-gnu/libpthread.so.0
7f877af78000-7f877af79000 rw-p 00005000 00:1b 90423049 /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0.7800.0
7f877ae7c000-7f877ae8c000 rw-p 00000000 00:1b 93439971 /usr/lib/x86_64-linux-gnu/libabsl_time_zone.so.20220623.0.0
7f877ae7c000-7f877ae8c000 rw-p 00000000 00:1b 93439971 /usr/lib/x86_64-linux-gnu/libdbus-1.so.3.34.2rc5
7f877ae7c000-7f877ae8c000 rw-p 00000000 00:1b 93439971 /usr/lib/x86_64-linux-gnu/libtoto.so.AAA",
0x7ffe091bf000,
);
assert_eq!(mappings.len(), 9);

let expected = [
(0, 0, 0),
(6, 0, 32),
(2, 11800, 0),
(6, 0, 0),
(0, 0, 0),
(0, 7800, 0),
(20220623, 0, 0),
(3, 34, 25),
(0, 0, 0),
];

for (i, (map, exp)) in mappings.into_iter().zip(expected).enumerate() {
let version = map.elf_file_so_version();
assert_eq!(version, exp, "{i}");
}
}

#[test]
fn test_whitespaces_in_name() {
let mappings = get_mappings_for(
Expand Down
16 changes: 12 additions & 4 deletions src/linux/sections/mappings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,24 @@ fn fill_raw_module(
sig_section.location()
};

let (file_path, _) = mapping
.get_mapping_effective_path_and_name()
let (file_path, _, (major, minor, release)) = mapping
.get_mapping_effective_path_name_and_version()
.map_err(|e| errors::SectionMappingsError::GetEffectivePathError(mapping.clone(), e))?;
let name_header = write_string_to_location(buffer, file_path.to_string_lossy().as_ref())?;

Ok(MDRawModule {
let mut raw_module = MDRawModule {
base_of_image: mapping.start_address as u64,
size_of_image: mapping.size as u32,
cv_record,
module_name_rva: name_header.rva,
..Default::default()
})
};

raw_module.version_info.signature = format::VS_FFI_SIGNATURE;
raw_module.version_info.struct_version = format::VS_FFI_STRUCVERSION;
raw_module.version_info.file_version_hi = major;
raw_module.version_info.file_version_lo = minor;
raw_module.version_info.product_version_hi = release;

Ok(raw_module)
}
Loading