tugger_binary_analysis/
audit.rs1use {
8 crate::{
9 find_minimum_distro_version, find_undefined_elf_symbols, UndefinedSymbol,
10 GCC_VERSIONS_BY_DISTRO, GLIBC_VERSIONS_BY_DISTRO, LSB_SHARED_LIBRARIES,
11 },
12 std::{collections::BTreeMap, fs::File, io::Read, path::PathBuf},
13};
14
15pub fn analyze_file(path: PathBuf) {
16 let mut fd = File::open(path).unwrap();
17 let mut buffer = Vec::new();
18 fd.read_to_end(&mut buffer).unwrap();
19 analyze_data(&buffer);
20}
21
22pub fn analyze_data(buffer: &[u8]) {
23 match goblin::Object::parse(buffer).unwrap() {
24 goblin::Object::Elf(elf) => {
25 let mut undefined_symbols = find_undefined_elf_symbols(buffer, &elf);
26 undefined_symbols.sort();
27
28 analyze_elf_libraries(&elf.libraries, &undefined_symbols);
29 }
30 goblin::Object::PE(_pe) => {
31 panic!("PE not yet supported");
32 }
33 goblin::Object::Mach(_mach) => {
34 panic!("mach not yet supported");
35 }
36 goblin::Object::Archive(_archive) => {
37 panic!("archive not yet supported");
38 }
39 goblin::Object::Unknown(magic) => panic!("unknown magic: {:#x}", magic),
40 }
41}
42
43pub fn analyze_elf_libraries(libs: &[&str], undefined_symbols: &[UndefinedSymbol]) {
44 let mut latest_symbols: BTreeMap<String, version_compare::Version> = BTreeMap::new();
45
46 println!("Shared Library Dependencies");
47 println!("===========================");
48
49 let mut libs = libs.to_vec();
50 libs.sort_unstable();
51 for lib in libs {
52 println!("{}", lib);
53
54 if LSB_SHARED_LIBRARIES.contains(&lib) {
55 println!(" OK - Library part of Linux Standard Base and present on most distros");
56 } else {
57 println!(" PROBLEMATIC - Shared library dependency may not be on all machines");
58 }
59
60 let mut symbols: Vec<&UndefinedSymbol> = Vec::new();
61
62 for symbol in undefined_symbols {
63 if symbol.filename == Some((*lib).to_string()) {
64 symbols.push(symbol);
65 }
66 }
67
68 for symbol in symbols {
75 match &symbol.version {
76 Some(version) => {
77 let parts: Vec<&str> = version.splitn(2, '_').collect();
78
79 match parts.len() {
80 1 => { }
81 2 => {
82 let v = version_compare::Version::from(parts[1])
83 .expect("unable to parse version");
84
85 match latest_symbols.get(parts[0]) {
86 Some(existing) => {
87 if &v > existing {
88 latest_symbols.insert(parts[0].to_string(), v);
89 }
90 }
91 None => {
92 latest_symbols.insert(parts[0].to_string(), v);
93 }
94 }
95 }
96 _ => {}
97 }
98
99 }
101 None => {
102 }
104 }
105 }
106
107 println!();
108 }
109
110 println!("Symbol Versioning");
111 println!("=================");
112
113 for (name, version) in &latest_symbols {
114 match name.as_str() {
115 "GLIBC" => {
116 println!();
117 println!("glibc");
118 println!("-----");
119 println!();
120 println!("Minimum Version: {}", version);
121 println!("Minimum Distro Versions:");
122
123 for s in find_minimum_distro_version(version, &GLIBC_VERSIONS_BY_DISTRO) {
124 println!(" {}", s);
125 }
126 }
127 "GCC" => {
128 println!();
129 println!("gcc");
130 println!("-----");
131 println!();
132 println!("Minimum Version: {}", version);
133 println!("Minimum Distro Versions:");
134
135 for s in find_minimum_distro_version(version, &GCC_VERSIONS_BY_DISTRO) {
136 println!(" {}", s);
137 }
138 }
139 other => {
140 println!();
141 println!("{}", other);
142 println!("-----");
143 println!();
144 println!("Minimum Version: {}", version);
145 println!("Minimum Distro Versions: Unknown");
146 }
147 }
148 }
149}