···11+commit 4d2c1556d769695770c95a982e0dcda4d70eee57
22+Author: kuflierl <41301536+kuflierl@users.noreply.github.com>
33+Date: Sun Apr 13 19:57:50 2025 +0200
44+55+ service.rs: profile path fix for strace
66+ Enable path env fixing when path env doesn't have strace to unbreak tool on unique systems and units.
77+ This fixes handling on non FHS operating systems and systemd units that define their own PATH that doesn't include strace.
88+99+diff --git a/src/systemd/service.rs b/src/systemd/service.rs
1010+index 908fdf0..e9294cf 100644
1111+--- a/src/systemd/service.rs
1212++++ b/src/systemd/service.rs
1313+@@ -7,6 +7,7 @@ use std::{
1414+ ops::RangeInclusive,
1515+ path::{Path, PathBuf},
1616+ process::{Command, Stdio},
1717++ ffi::OsString,
1818+ };
1919+2020+ use anyhow::Context as _;
2121+@@ -99,6 +100,41 @@ impl Service {
2222+ )
2323+ }
2424+2525++ // A function for locating the parent directory i.e. PATH of an executable
2626++ fn resolve_exec_path<P>(exe_name: &P, path_env: OsString) -> Option<PathBuf>
2727++ where P: AsRef<Path> + ?Sized,
2828++ {
2929++ env::split_paths(&path_env).filter_map(|dir| {
3030++ let full_path = dir.join(&exe_name);
3131++ if full_path.is_file() {
3232++ Some(dir)
3333++ } else {
3434++ None
3535++ }
3636++ }).next()
3737++ }
3838++
3939++ // determine PATH env used for unit
4040++ pub(crate) fn get_exec_path(config_paths: &Vec<&Path>) -> anyhow::Result<String> {
4141++ let old_path_env_option = Self::config_vals("Environment", &config_paths)?
4242++ .into_iter().filter(|x| x.starts_with("\"PATH=")).last().map(|x| x.trim_matches('\"').get(5..).unwrap().to_owned());
4343++ Ok(match old_path_env_option {
4444++ Some(path_env) => {
4545++ log::info!("Found hard coded PATH environment in unit: {path_env}");
4646++ path_env
4747++ },
4848++ None => {
4949++ let output = Command::new("systemd-path").arg("search-binaries-default").output()?;
5050++ if !output.status.success() {
5151++ anyhow::bail!("systemd-path invocation failed with code {:?}", output.status);
5252++ }
5353++ let default_systemd_path = output.stdout.lines().next().ok_or_else(|| anyhow::anyhow!("Unable to get global systemd default PATH"))??;
5454++ log::info!("Could not find hard coded PATH environment in unit, using systemd default: {default_systemd_path}");
5555++ default_systemd_path
5656++ }
5757++ })
5858++ }
5959++
6060+ /// Get systemd "exposure level" for the service (0-100).
6161+ /// 100 means extremely exposed (no hardening), 0 means so sandboxed it can't do much.
6262+ /// Although this is a very crude heuristic, below 40-50 is generally good.
6363+@@ -170,6 +206,20 @@ impl Service {
6464+ writeln!(fragment_file, "KillMode=control-group")?;
6565+ writeln!(fragment_file, "StandardOutput=journal")?;
6666+6767++ // Modifying Env Path for strace availability if needed
6868++ let old_path_env = Self::get_exec_path(&config_paths)?;
6969++ match Self::resolve_exec_path("strace", (&old_path_env).into()) {
7070++ Some(_) => log::info!("Found strace in previous path, no correction needed"),
7171++ None => {
7272++ let path_with_strace = Self::resolve_exec_path("strace", env::var_os("PATH").unwrap()).unwrap();
7373++ log::info!("Found strace from local PATH in {}, inserting it into unit config!", path_with_strace.display());
7474++ let mut paths = env::split_paths(&old_path_env).collect::<Vec<_>>();
7575++ paths.push(path_with_strace);
7676++ let new_path = env::join_paths(paths)?;
7777++ writeln!(fragment_file, "Environment=\"PATH={}\"", new_path.to_str().unwrap())?;
7878++ },
7979++ }
8080++
8181+ // Profile data dir
8282+ let mut rng = rand::rng();
8383+ let profile_data_dir = PathBuf::from(format!(