Procházet zdrojové kódy

Merge pull request #717 from ajwerner/no-libc-in-integration-tests

uprobe,integration-test: do not exercise dylib resolution in integration tests
ajwerner před 1 rokem
rodič
revize
de8604d011
2 změnil soubory, kde provedl 84 přidání a 48 odebrání
  1. 59 30
      aya/src/programs/uprobe.rs
  2. 25 18
      test/integration-test/src/tests/load.rs

+ 59 - 30
aya/src/programs/uprobe.rs

@@ -82,36 +82,7 @@ impl UProbe {
         target: T,
         pid: Option<pid_t>,
     ) -> Result<UProbeLinkId, ProgramError> {
-        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<T: AsRef<Path>>(
+    target: T,
+    pid: Option<pid_t>,
+) -> Result<String, UProbeError> {
+    // 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,

+ 25 - 18
test/integration-test/src/tests/load.rs

@@ -201,7 +201,9 @@ fn basic_uprobe() {
 
     prog.load().unwrap();
     assert_loaded("test_uprobe");
-    let link = prog.attach(Some("sleep"), 0, "libc", None).unwrap();
+    let link = prog
+        .attach(Some("uprobe_function"), 0, "/proc/self/exe", None)
+        .unwrap();
 
     {
         let _link_owned = prog.take_link(link).unwrap();
@@ -213,7 +215,8 @@ fn basic_uprobe() {
     prog.load().unwrap();
 
     assert_loaded("test_uprobe");
-    prog.attach(Some("sleep"), 0, "libc", None).unwrap();
+    prog.attach(Some("uprobe_function"), 0, "/proc/self/exe", None)
+        .unwrap();
 
     assert_loaded("test_uprobe");
     prog.unload().unwrap();
@@ -424,14 +427,23 @@ fn pin_lifecycle_kprobe() {
     assert_unloaded("test_kprobe");
 }
 
+#[no_mangle]
+#[inline(never)]
+extern "C" fn uprobe_function() {
+    core::hint::black_box(uprobe_function);
+}
+
 #[test]
 fn pin_lifecycle_uprobe() {
+    const FIRST_PIN_PATH: &str = "/sys/fs/bpf/aya-uprobe-test-prog-1";
+    const SECOND_PIN_PATH: &str = "/sys/fs/bpf/aya-uprobe-test-prog-2";
+
     // 1. Load Program and Pin
     {
         let mut bpf = Bpf::load(crate::TEST).unwrap();
         let prog: &mut UProbe = bpf.program_mut("test_uprobe").unwrap().try_into().unwrap();
         prog.load().unwrap();
-        prog.pin("/sys/fs/bpf/aya-uprobe-test-prog").unwrap();
+        prog.pin(FIRST_PIN_PATH).unwrap();
     }
 
     // should still be loaded since prog was pinned
@@ -439,11 +451,7 @@ fn pin_lifecycle_uprobe() {
 
     // 2. Load program from bpffs but don't attach it
     {
-        let _ = UProbe::from_pin(
-            "/sys/fs/bpf/aya-uprobe-test-prog",
-            aya::programs::ProbeKind::UProbe,
-        )
-        .unwrap();
+        let _ = UProbe::from_pin(FIRST_PIN_PATH, aya::programs::ProbeKind::UProbe).unwrap();
     }
 
     // should still be loaded since prog was pinned
@@ -451,17 +459,13 @@ fn pin_lifecycle_uprobe() {
 
     // 3. Load program from bpffs and attach
     {
-        let mut prog = UProbe::from_pin(
-            "/sys/fs/bpf/aya-uprobe-test-prog",
-            aya::programs::ProbeKind::UProbe,
-        )
-        .unwrap();
-        let link_id = prog.attach(Some("sleep"), 0, "libc", None).unwrap();
+        let mut prog = UProbe::from_pin(FIRST_PIN_PATH, aya::programs::ProbeKind::UProbe).unwrap();
+        let link_id = prog
+            .attach(Some("uprobe_function"), 0, "/proc/self/exe", None)
+            .unwrap();
         let link = prog.take_link(link_id).unwrap();
         let fd_link: FdLink = link.try_into().unwrap();
-        fd_link
-            .pin("/sys/fs/bpf/aya-uprobe-test-bash-sleep")
-            .unwrap();
+        fd_link.pin(SECOND_PIN_PATH).unwrap();
 
         // Unpin the program. It will stay attached since its links were pinned.
         prog.unpin().unwrap();
@@ -472,7 +476,7 @@ fn pin_lifecycle_uprobe() {
 
     // 4. unpin link, and make sure everything is unloaded
     {
-        PinnedLink::from_pin("/sys/fs/bpf/aya-uprobe-test-bash-sleep")
+        PinnedLink::from_pin(SECOND_PIN_PATH)
             .unwrap()
             .unpin()
             .unwrap();
@@ -480,4 +484,7 @@ fn pin_lifecycle_uprobe() {
 
     // program should be unloaded
     assert_unloaded("test_uprobe");
+
+    // Make sure the function isn't optimized out.
+    uprobe_function();
 }