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