Skip to content
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
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion common/bin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bin-lib"
version = "0.1.1"
version = "0.1.2"
edition = "2021"

[dependencies]
Expand Down
Binary file added common/bin/src/fixtures/lib_runpath.so
Binary file not shown.
2 changes: 2 additions & 0 deletions common/bin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub struct LibraryInfo {
pub names: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub undefined: Vec<String>,
#[serde(skip_serializing, default)]
pub rpath: Vec<String>,
#[serde(skip_serializing, default = "LibraryPriority::default")]
pub priority: LibraryPriority,
}
Expand Down
33 changes: 33 additions & 0 deletions common/bin/src/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ impl LibraryInfo {
N: AsRef<str>,
{
let mut needed = Vec::<String>::new();
let mut rpath = Vec::<String>::new();
let mut elf = ElfStream::<AnyEndian, S>::open_stream(source)?;
let mut name = String::from(name.as_ref());

Expand All @@ -65,6 +66,15 @@ impl LibraryInfo {
abi::DT_SONAME => {
name = String::from(dynstr_table.get(entry.d_val() as usize).unwrap());
}
abi::DT_RPATH | abi::DT_RUNPATH => {
rpath.extend(
dynstr_table
.get(entry.d_val() as usize)
.unwrap()
.split(":")
.map(|s| String::from(s)),
);
}
_ => {}
}
}
Expand Down Expand Up @@ -140,8 +150,31 @@ impl LibraryInfo {
needed,
symbols,
undefined,
rpath,
names: Default::default(),
priority: Default::default(),
})
}
}

#[cfg(test)]
mod tests {
use std::io::Cursor;

use crate::LibraryInfo;

#[test]
fn test_parse_runpath() {
// Fixture is a shared object built with -Wl,-rpath,'$ORIGIN/pulseaudio'
// -Wl,--enable-new-dtags, i.e. a DT_RUNPATH entry.
let mut content = Cursor::new(include_bytes!("fixtures/lib_runpath.so"));
let info = LibraryInfo::parse(&mut content, true, "lib_runpath.so")
.expect("should not have any error");
assert_eq!(info.name, "libfixture.so.1", "name should come from DT_SONAME");
assert!(
info.rpath.iter().any(|p| p == "$ORIGIN/pulseaudio"),
"rpath should capture DT_RUNPATH, got {:?}",
info.rpath
);
}
}
2 changes: 1 addition & 1 deletion common/ipk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ipk-lib"
version = "0.1.3"
version = "0.1.4"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
38 changes: 30 additions & 8 deletions common/ipk/src/component.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use common_path::common_path;
use std::borrow::Cow;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet, VecDeque};
use std::fs;
use std::fs::File;
use std::io::{Error, ErrorKind};
Expand Down Expand Up @@ -160,16 +160,30 @@ impl<T> Component<T> {
rpath: &Vec<PathBuf>,
links: &Symlinks,
) -> Result<Vec<LibraryInfo>, Error> {
let mut libs = HashMap::new();
let lib_dir = dir.join("lib").canonicalize();
let mut lib_dirs: Vec<(&Path, bool)> = rpath.iter().map(|p| (p.as_path(), true)).collect();
if let Ok(lib_dir) = lib_dir.as_ref() {
let mut libs: HashMap<PathBuf, LibraryInfo> = HashMap::new();
let mut visited_dirs: HashSet<PathBuf> = HashSet::new();
let mut queue: VecDeque<(PathBuf, bool)> = VecDeque::new();

for p in rpath {
queue.push_back((p.clone(), true));
}
if let Ok(lib_dir) = dir.join("lib").canonicalize() {
if !rpath.contains(&lib_dir) {
lib_dirs.push((lib_dir.as_path(), false));
queue.push_back((lib_dir, false));
}
}
for (lib_dir, is_rpath) in lib_dirs {
let Ok(entries) = fs::read_dir(lib_dir) else {

// Discover libraries by walking the executable's rpath directories and,
// transitively, each bundled library's own DT_RUNPATH/DT_RPATH
// ($ORIGIN-relative). This mirrors the dynamic loader: e.g. a bundled
// libpulse.so.0 with RUNPATH $ORIGIN/pulseaudio pulls in
// lib/pulseaudio/libpulsecommon-15.0.so, which a flat scan of lib/
// would miss.
while let Some((lib_dir, is_rpath)) = queue.pop_front() {
if !visited_dirs.insert(lib_dir.clone()) {
continue;
}
let Ok(entries) = fs::read_dir(&lib_dir) else {
continue;
};
for entry in entries {
Expand All @@ -190,9 +204,17 @@ impl<T> Component<T> {
} else {
LibraryPriority::Package
};
// A bundled library's own runpath can point at further bundled
// directories; queue them for discovery too.
for sub_dir in Self::rpath(&lib.rpath, &path) {
if !visited_dirs.contains(&sub_dir) {
queue.push_back((sub_dir, true));
}
}
libs.insert(path, lib);
}
}

for (path, lib) in &mut libs {
lib.names
.push(String::from(path.file_name().unwrap().to_string_lossy()));
Expand Down
2 changes: 1 addition & 1 deletion packages/ipk-verify/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ipk-verify"
version = "0.1.5"
version = "0.1.6"
edition = "2021"
description = "Command line tool for checking symbols in an exectuable and libraries in an IPK file"
authors = ["Mariotaku Lee <mariotaku.lee@gmail.com>"]
Expand Down
1 change: 1 addition & 0 deletions packages/ipk-verify/tests/global_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fn bundled_lib(name: &str, needed: &[&str], symbols: &[&str], undefined: &[&str]
symbols,
names: vec![name.to_string()],
undefined: undefined.iter().map(|s| s.to_string()).collect(),
rpath: vec![],
priority: LibraryPriority::Rpath,
}
}
Expand Down
Loading