From dcc6b84a8803cfee37ab4e138c89616f1fc1b002 Mon Sep 17 00:00:00 2001 From: Andrew Werner Date: Tue, 1 Aug 2023 20:50:23 -0400 Subject: [PATCH] programs/uprobe: extract library path resolving The function is extracted so that a test could be written. This test is valid on linux-gnu targets, and it doesn't need any special privileges. This is in anticipation of removing the code that uses this functionality (seemingly incidentally) from integration tests. --- aya/src/programs/uprobe.rs | 89 +++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 30 deletions(-) diff --git a/aya/src/programs/uprobe.rs b/aya/src/programs/uprobe.rs index 8c42ced0..9c018233 100644 --- a/aya/src/programs/uprobe.rs +++ b/aya/src/programs/uprobe.rs @@ -82,36 +82,7 @@ impl UProbe { target: T, pid: Option, ) -> Result { - let target = target.as_ref(); - let target_str = &*target.as_os_str().to_string_lossy(); - - let mut path = if let Some(pid) = pid { - find_lib_in_proc_maps(pid, target_str).map_err(|io_error| UProbeError::FileError { - filename: format!("/proc/{pid}/maps"), - io_error, - })? - } else { - None - }; - - if path.is_none() { - path = if target.is_absolute() { - Some(target_str) - } else { - let cache = - LD_SO_CACHE - .as_ref() - .map_err(|error| UProbeError::InvalidLdSoCache { - io_error: error.clone(), - })?; - cache.resolve(target_str) - } - .map(String::from) - }; - - let path = path.ok_or(UProbeError::InvalidTarget { - path: target.to_owned(), - })?; + let path = resolve_attach_path(target, pid)?; let sym_offset = if let Some(fn_name) = fn_name { resolve_symbol(&path, fn_name).map_err(|error| UProbeError::SymbolError { @@ -152,6 +123,64 @@ impl UProbe { } } +fn resolve_attach_path>( + target: T, + pid: Option, +) -> Result { + // Look up the path for the target. If it there is a pid, and the target is a library name that + // is in the process's memory map, use the path of that library. Otherwise, use the target + // as-is. + let target = target.as_ref(); + let target_str = &*target.as_os_str().to_string_lossy(); + + let mut path = if let Some(pid) = pid { + find_lib_in_proc_maps(pid, target_str).map_err(|io_error| UProbeError::FileError { + filename: format!("/proc/{pid}/maps"), + io_error, + })? + } else { + None + }; + + if path.is_none() { + path = if target.is_absolute() { + Some(target_str) + } else { + let cache = LD_SO_CACHE + .as_ref() + .map_err(|error| UProbeError::InvalidLdSoCache { + io_error: error.clone(), + })?; + cache.resolve(target_str) + } + .map(String::from) + }; + + path.ok_or(UProbeError::InvalidTarget { + path: target.to_owned(), + }) +} + +// Only run this test on linux with glibc because only in that configuration do we know that we'll +// be dynamically linked to libc and can exercise resolving the path to libc via the current +// process's memory map. +#[test] +#[cfg_attr( + any(miri, not(all(target_os = "linux", target_env = "gnu"))), + ignore = "requires glibc, doesn't work in miri" +)] +fn test_resolve_attach_path() { + // Look up the current process's pid. + let pid = std::process::id().try_into().unwrap(); + + // Now let's resolve the path to libc. It should exist in the current process's memory map and + // then in the ld.so.cache. + let libc_path = resolve_attach_path("libc", Some(pid)).unwrap(); + + // Make sure we got a path that contains libc. + assert!(libc_path.contains("libc"), "libc_path: {}", libc_path); +} + define_link_wrapper!( /// The link used by [UProbe] programs. UProbeLink,