From daee67dae658c4a060cda0ff885c87e3ca28c5ae Mon Sep 17 00:00:00 2001 From: K900 Date: Sat, 30 Jul 2022 12:31:15 +0300 Subject: [PATCH] make-initrd-ng: use goblin instead of shelling out to patchelf and friends --- .../kernel/make-initrd-ng/Cargo.lock | 92 +++++++++++++++++ .../kernel/make-initrd-ng/Cargo.toml | 1 + .../kernel/make-initrd-ng/src/main.rs | 98 +++++++++---------- 3 files changed, 141 insertions(+), 50 deletions(-) diff --git a/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock b/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock index 75e732029b51..cce94b3f4cfb 100644 --- a/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock +++ b/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock @@ -1,5 +1,97 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "goblin" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91766b1121940d622933a13e20665857648681816089c9bc2075c4b75a6e4f6b" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + [[package]] name = "make-initrd-ng" version = "0.1.0" +dependencies = [ + "goblin", +] + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "proc-macro2" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" diff --git a/pkgs/build-support/kernel/make-initrd-ng/Cargo.toml b/pkgs/build-support/kernel/make-initrd-ng/Cargo.toml index 9076f6b15617..c30eccd9fec7 100644 --- a/pkgs/build-support/kernel/make-initrd-ng/Cargo.toml +++ b/pkgs/build-support/kernel/make-initrd-ng/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +goblin = "0.5.0" diff --git a/pkgs/build-support/kernel/make-initrd-ng/src/main.rs b/pkgs/build-support/kernel/make-initrd-ng/src/main.rs index 32830ff4e795..de1e3ee724a6 100644 --- a/pkgs/build-support/kernel/make-initrd-ng/src/main.rs +++ b/pkgs/build-support/kernel/make-initrd-ng/src/main.rs @@ -3,11 +3,13 @@ use std::env; use std::ffi::OsStr; use std::fs; use std::hash::Hash; -use std::io::{BufRead, BufReader, Error, ErrorKind}; +use std::io::{BufRead, BufReader, Error}; use std::os::unix; use std::path::{Component, Path, PathBuf}; use std::process::Command; +use goblin::{elf::Elf, Object}; + struct NonRepeatingQueue { queue: VecDeque, seen: HashSet, @@ -38,50 +40,32 @@ impl NonRepeatingQueue { } } -fn patch_elf, P: AsRef>(mode: S, path: P) -> Result { - let output = Command::new("patchelf").arg(&mode).arg(&path).output()?; - if output.status.success() { - Ok(String::from_utf8(output.stdout).expect("Failed to parse output")) - } else { - Err(Error::new( - ErrorKind::Other, - format!( - "failed: patchelf {:?} {:?}", - OsStr::new(&mode), - OsStr::new(&path) - ), - )) - } -} - -fn copy_file + AsRef, S: AsRef + AsRef>( +fn add_dependencies + AsRef>( source: P, - target: S, + elf: Elf, queue: &mut NonRepeatingQueue>, -) -> Result<(), Error> { - fs::copy(&source, &target)?; - - if !Command::new("ldd").arg(&source).output()?.status.success() { - // Not dynamically linked - no need to recurse - return Ok(()); +) { + if let Some(interp) = elf.interpreter { + queue.push_back(Box::from(Path::new(interp))); } - let rpath_string = patch_elf("--print-rpath", &source)?; - let needed_string = patch_elf("--print-needed", &source)?; - // Shared libraries don't have an interpreter - if let Ok(interpreter_string) = patch_elf("--print-interpreter", &source) { - queue.push_back(Box::from(Path::new(&interpreter_string.trim()))); - } + let rpaths = if elf.runpaths.len() > 0 { + elf.runpaths + } else if elf.rpaths.len() > 0 { + elf.rpaths + } else { + vec![] + }; - let rpath = rpath_string - .trim() - .split(":") + let rpaths_as_path = rpaths + .into_iter() + .flat_map(|p| p.split(":")) .map(|p| Box::::from(Path::new(p))) .collect::>(); - for line in needed_string.lines() { + for line in elf.libraries { let mut found = false; - for path in &rpath { + for path in &rpaths_as_path { let lib = path.join(line); if lib.exists() { // No need to recurse. The queue will bring it back round. @@ -100,22 +84,36 @@ fn copy_file + AsRef, S: AsRef + AsRef>( ); } } +} - // Make file writable to strip it - let mut permissions = fs::metadata(&target)?.permissions(); - permissions.set_readonly(false); - fs::set_permissions(&target, permissions)?; +fn copy_file + AsRef, S: AsRef + AsRef>( + source: P, + target: S, + queue: &mut NonRepeatingQueue>, +) -> Result<(), Error> { + fs::copy(&source, &target)?; - // Strip further than normal - if !Command::new("strip") - .arg("--strip-all") - .arg(OsStr::new(&target)) - .output()? - .status - .success() - { - println!("{:?} was not successfully stripped.", OsStr::new(&target)); - } + let contents = fs::read(&source)?; + + if let Ok(Object::Elf(e)) = Object::parse(&contents) { + add_dependencies(source, e, queue); + + // Make file writable to strip it + let mut permissions = fs::metadata(&target)?.permissions(); + permissions.set_readonly(false); + fs::set_permissions(&target, permissions)?; + + // Strip further than normal + if !Command::new("strip") + .arg("--strip-all") + .arg(OsStr::new(&target)) + .output()? + .status + .success() + { + println!("{:?} was not successfully stripped.", OsStr::new(&target)); + } + }; Ok(()) }