From 6d0637715401ab8983d141461208a5862bb7bd1d Mon Sep 17 00:00:00 2001 From: Kai Stuhlemmer Date: Mon, 2 Jun 2025 17:44:10 +0200 Subject: [PATCH] fix(dso): ensure all (r|run)paths are relative to sysroot Also make sure we split them on colons. --- src/args.rs | 12 ++++---- src/cleaners.rs | 11 ++++++-- src/cleaners/dso.rs | 69 ++++++++++++++++++++++++++------------------- 3 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/args.rs b/src/args.rs index a1db7e6..3e8fa5f 100644 --- a/src/args.rs +++ b/src/args.rs @@ -3,7 +3,10 @@ use std::path::PathBuf; -use clap::{builder::{PathBufValueParser, TypedValueParser}, Parser}; +use clap::{ + Parser, + builder::{PathBufValueParser, TypedValueParser}, +}; #[derive(Clone, Default)] struct AbsolutePathBufValueParser; @@ -20,10 +23,8 @@ impl TypedValueParser for AbsolutePathBufValueParser { let pathbuf_parser = PathBufValueParser::new(); let v = pathbuf_parser.parse_ref(cmd, arg, value)?; - v.canonicalize().map_err(|e| clap::Error::raw( - clap::error::ErrorKind::Io, - e, - )) + v.canonicalize() + .map_err(|e| clap::Error::raw(clap::error::ErrorKind::Io, e)) } } @@ -59,4 +60,3 @@ pub struct Args { /// The location of the sysroot to clean up pub sysroot_location: PathBuf, } - diff --git a/src/cleaners.rs b/src/cleaners.rs index 9351d7d..93369bc 100644 --- a/src/cleaners.rs +++ b/src/cleaners.rs @@ -206,7 +206,12 @@ impl Runner { "regular file" }; let size = Self::get_file_size(path)?; - log::info!("(dry-run) would remove {} {} ({})", ty, path.display(), size); + log::info!( + "(dry-run) would remove {} {} ({})", + ty, + path.display(), + size + ); Ok(size) }) } else { @@ -225,8 +230,8 @@ impl Runner { Err(err) => { log::error!("failed to get metadata from: {}, {}", file.display(), err); FileSize(0) - }, - Ok(lstat) => FileSize(lstat.st_size as u64) + } + Ok(lstat) => FileSize(lstat.st_size as u64), }; Ok(size) } diff --git a/src/cleaners/dso.rs b/src/cleaners/dso.rs index b0a0264..433f500 100644 --- a/src/cleaners/dso.rs +++ b/src/cleaners/dso.rs @@ -159,7 +159,7 @@ impl State { } let current_dir = std::env::current_dir()?; - let mut dst_path = std::fs::read_link(path)?; + let mut dst_path = fs::read_link(path)?; if dst_path.is_absolute() { dst_path = dst_path.strip_prefix("/")?.into(); } else { @@ -197,10 +197,12 @@ impl State { } let search_paths = determine_lib_search_paths(path, elf)?; + log::trace!("determined search paths {:#?}", search_paths); 'next_lib: for &library in elf.libraries.iter() { for lib_path in search_paths.iter() { - let tentative_path = PathBuf::from(lib_path).strip_prefix("/")?.join(library); + assert!(Path::new(&lib_path).is_relative()); + let tentative_path = PathBuf::from(lib_path).join(library); let dst = match nix::sys::stat::lstat(&tentative_path) { Ok(dst) => dst, Err(Errno::ENOENT) => continue, @@ -219,7 +221,11 @@ impl State { continue 'next_lib; } - log::warn!("{}: unable to find library {}, ignoring (this might produce wrong results)!", path.display(), library); + log::warn!( + "{}: unable to find library {}, ignoring (this might produce wrong results)!", + path.display(), + library + ); } Ok(()) @@ -257,7 +263,7 @@ impl State { {:?} }}" }, - petgraph::dot::Dot::with_attr_getters( + dot::Dot::with_attr_getters( &self.graph, &[ dot::Config::NodeNoLabel, @@ -267,8 +273,12 @@ impl State { &|_, _| { String::new() }, &|_, n| { let paths = self.paths_map.get(&n.id()).unwrap(); - let first_path = paths.iter().next().unwrap_or_else(|| panic!("dso: you have a path map with an empty entry for inode {}", - n.id())); + let first_path = paths.iter().next().unwrap_or_else(|| { + panic!( + "dso: you have a path map with an empty entry for inode {}", + n.id() + ) + }); format!( "label = \"({}, {})\"", n.weight(), @@ -285,10 +295,13 @@ impl State { } fn determine_lib_search_paths(path: &Path, elf: &Elf<'_>) -> Result> { + log::trace!("elf.runpaths = {:#?}", elf.runpaths); + log::trace!("elf.rpaths = {:#?}", elf.rpaths); + let mut search_paths = vec![]; let current_dir = std::env::current_dir()?; - let origin = std::fs::canonicalize(path)? + let origin = fs::canonicalize(path)? .parent() .unwrap() .strip_prefix(current_dir)? @@ -297,34 +310,32 @@ fn determine_lib_search_paths(path: &Path, elf: &Elf<'_>) -> Result> .into_string() .map_err(|s| anyhow::anyhow!("cannot represent {:?} as a UTF-8 string", s))?; - if elf.rpaths != vec![""] { - if elf.runpaths != vec![""] { - let mut rpaths = elf - .rpaths - .iter() - .map(|p| p.replace("$ORIGIN", &origin)) - .collect::>(); - search_paths.append(&mut rpaths); - } - - search_paths.append(&mut get_env_library_paths()); + if elf.runpaths.is_empty() { + collect_paths(&elf.rpaths, &mut search_paths, &origin); } - if elf.runpaths != vec![""] { - let mut runpaths = elf - .runpaths - .iter() - .map(|p| p.replace("$ORIGIN", &origin)) - .collect::>(); - search_paths.append(&mut runpaths); - } + search_paths.append(&mut get_env_library_paths()); - search_paths.push("/usr/local/lib".into()); - search_paths.push("/lib".into()); - search_paths.push("/usr/lib".into()); + collect_paths(&elf.runpaths, &mut search_paths, &origin); + + search_paths.push("usr/local/lib".into()); + search_paths.push("lib".into()); + search_paths.push("usr/lib".into()); Ok(search_paths) } +fn collect_paths(elf_paths: &Vec<&str>, search_paths: &mut Vec, origin: &str) { + if elf_paths.iter().any(|p| !p.is_empty()) { + let mut paths = elf_paths + .iter() + .flat_map(|p| p.split(':')) + .map(|p| p.replace("$ORIGIN", origin)) + .map(|p| p.trim_start_matches('/').to_string()) + .collect::>(); + search_paths.append(&mut paths); + } +} + fn get_env_library_paths() -> Vec { let ld_config_path = std::env::var("LD_LIBRARY_PATH"); ld_config_path