Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions aya/src/bpf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1099,11 +1099,11 @@ impl Ebpf {
///
/// ```no_run
/// # let mut bpf = aya::Ebpf::load(&[])?;
/// use aya::programs::UProbe;
/// use aya::programs::{uprobe::UProbeScope, UProbe};
///
/// let program: &mut UProbe = bpf.program_mut("SSL_read").unwrap().try_into()?;
/// program.load()?;
/// program.attach("SSL_read", "libssl", None)?;
/// program.attach("SSL_read", "libssl", UProbeScope::AllProcesses)?;
/// # Ok::<(), aya::EbpfError>(())
/// ```
pub fn program_mut(&mut self, name: &str) -> Option<&mut Program> {
Expand Down
32 changes: 27 additions & 5 deletions aya/src/programs/uprobe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{
fmt::{self, Write},
fs,
io::{self, BufRead as _, Cursor, Read as _},
num::NonZeroU32,
os::unix::ffi::{OsStrExt as _, OsStringExt as _},
path::{Path, PathBuf},
sync::LazyLock,
Expand Down Expand Up @@ -88,6 +89,17 @@ impl<'a, L: Into<UProbeAttachLocation<'a>>> From<L> for UProbeAttachPoint<'a> {
}
}

/// Specifies which processes a uprobe should fire for.
#[derive(Debug, Clone, Copy)]
pub enum UProbeScope {
/// Fire for any process that hits the attach point.
AllProcesses,
/// Fire only when the calling process/thread hits the attach point.
CallingProcess,
/// Fire only when the given process hits the attach point.
OneProcess(NonZeroU32),
}

impl UProbe {
/// The type of the program according to the kernel.
pub const PROGRAM_TYPE: ProgramType = ProgramType::KProbe;
Expand All @@ -108,8 +120,8 @@ impl UProbe {
///
/// Attaches the uprobe to the function `fn_name` defined in the `target`.
/// If the attach point specifies an offset, it is added to the address of
/// the target function. If `pid` is not `None`, the program executes only
/// when the target function is executed by the given `pid`.
/// the target function. `scope` specifies which processes should trigger
/// the uprobe.
///
/// The `target` argument can be an absolute path to a binary or library, or
/// a library name (eg: `"libc"`).
Expand All @@ -128,10 +140,20 @@ impl UProbe {
&mut self,
point: Point,
target: T,
pid: Option<u32>,
scope: UProbeScope,
) -> Result<UProbeLinkId, ProgramError> {
let UProbeAttachPoint { location, cookie } = point.into();
let proc_map = pid.map(ProcMap::new).transpose()?;
let (proc_map_pid, perf_event_pid) = match scope {
UProbeScope::AllProcesses => (None, None),
// /proc/0/maps does not exist, so use the real pid for ProcMap
// resolution while keeping the kernel's pid=0 sentinel for attach.
UProbeScope::CallingProcess => (Some(std::process::id()), Some(0)),
UProbeScope::OneProcess(pid) => {
let pid = pid.get();
(Some(pid), Some(pid))
}
};
let proc_map = proc_map_pid.map(ProcMap::new).transpose()?;
let path = resolve_attach_path(target.as_ref(), proc_map.as_ref())?;
let (symbol, offset) = match location {
UProbeAttachLocation::Symbol(s) => (Some(s), 0),
Expand All @@ -151,7 +173,7 @@ impl UProbe {

let Self { data, kind } = self;
let path = path.as_os_str();
attach::<Self, _>(data, *kind, path, offset, pid, cookie)
attach::<Self, _>(data, *kind, path, offset, perf_event_pid, cookie)
}

/// Creates a program from a pinned entry on a bpffs.
Expand Down
8 changes: 6 additions & 2 deletions test/integration-test/src/tests/array.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use aya::{EbpfLoader, maps::Array, programs::UProbe};
use aya::{
EbpfLoader,
maps::Array,
programs::{UProbe, uprobe::UProbeScope},
};
use integration_common::array::{ARRAY_LEN, GET_INDEX, GET_PTR_INDEX, GET_PTR_MUT_INDEX};
use test_case::test_case;

Expand Down Expand Up @@ -68,7 +72,7 @@ fn test_array(
.unwrap_or_else(|err| panic!("program {prog_name} is not a uprobe: {err}"));
prog.load()
.unwrap_or_else(|err| panic!("load {prog_name}: {err}"));
prog.attach(symbol, "/proc/self/exe", None)
prog.attach(symbol, "/proc/self/exe", UProbeScope::AllProcesses)
.unwrap_or_else(|err| panic!("attach {prog_name}: {err}"));
}

Expand Down
4 changes: 2 additions & 2 deletions test/integration-test/src/tests/bloom_filter.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use aya::{
EbpfLoader,
maps::{Array, MapError, MapType, bloom_filter::BloomFilter},
programs::UProbe,
programs::{UProbe, uprobe::UProbeScope},
sys::is_map_supported,
};
use integration_common::bloom_filter::{
Expand Down Expand Up @@ -57,7 +57,7 @@ fn bloom_filter_basic(result_map: &str, filter_map: &str, insert_prog: &str, con
.unwrap_or_else(|err| panic!("program {prog_name} is not a uprobe: {err}"));
prog.load()
.unwrap_or_else(|err| panic!("load {prog_name}: {err}"));
prog.attach(symbol, "/proc/self/exe", None)
prog.attach(symbol, "/proc/self/exe", UProbeScope::AllProcesses)
.unwrap_or_else(|err| panic!("attach {prog_name}: {err}"));
}

Expand Down
9 changes: 7 additions & 2 deletions test/integration-test/src/tests/bpf_probe_read.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use aya::{Ebpf, maps::Array, programs::UProbe};
use aya::{
Ebpf,
maps::Array,
programs::{UProbe, uprobe::UProbeScope},
};
use integration_common::bpf_probe_read::{RESULT_BUF_LEN, TestResult};

#[test_log::test]
Expand Down Expand Up @@ -99,7 +103,8 @@ fn load_and_attach_uprobe(prog_name: &str, func_name: &str, bytes: &[u8]) -> Ebp
let prog: &mut UProbe = bpf.program_mut(prog_name).unwrap().try_into().unwrap();
prog.load().unwrap();

prog.attach(func_name, "/proc/self/exe", None).unwrap();
prog.attach(func_name, "/proc/self/exe", UProbeScope::AllProcesses)
.unwrap();

bpf
}
Expand Down
12 changes: 10 additions & 2 deletions test/integration-test/src/tests/btf_relocations.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use aya::{EbpfLoader, Endianness, maps::Array, programs::UProbe};
use aya::{
EbpfLoader, Endianness,
maps::Array,
programs::{UProbe, uprobe::UProbeScope},
};
use aya_obj::btf::Btf;
use test_case::test_case;

Expand Down Expand Up @@ -90,7 +94,11 @@ fn relocation_tests(
let program: &mut UProbe = bpf.program_mut("program").unwrap().try_into().unwrap();
program.load().unwrap();
program
.attach("trigger_btf_relocations_program", "/proc/self/exe", None)
.attach(
"trigger_btf_relocations_program",
"/proc/self/exe",
UProbeScope::AllProcesses,
)
.unwrap();

trigger_btf_relocations_program();
Expand Down
13 changes: 11 additions & 2 deletions test/integration-test/src/tests/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use std::{fs, panic, path::Path, time::SystemTime};
use aya::{
Ebpf,
maps::{Array, HashMap, IterableMap as _, MapError, MapType, loaded_maps},
programs::{ProgramError, ProgramType, SocketFilter, TracePoint, UProbe, loaded_programs},
programs::{
ProgramError, ProgramType, SocketFilter, TracePoint, UProbe, loaded_programs,
uprobe::UProbeScope,
},
sys::{is_map_supported, is_program_supported},
util::KernelVersion,
};
Expand Down Expand Up @@ -65,7 +68,13 @@ fn test_loaded_programs() {
};

// Ensure we can perform basic operations on the re-created program.
let res = p.attach("uprobe_function", "/proc/self/exe", None).unwrap();
let res = p
.attach(
"uprobe_function",
"/proc/self/exe",
UProbeScope::AllProcesses,
)
.unwrap();

// Ensure the program can be detached.
p.detach(res).unwrap();
Expand Down
9 changes: 7 additions & 2 deletions test/integration-test/src/tests/linear_data_structures.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use aya::{EbpfLoader, maps::Array, programs::UProbe};
use aya::{
EbpfLoader,
maps::Array,
programs::{UProbe, uprobe::UProbeScope},
};
use integration_common::linear_data_structures::{PEEK_INDEX, POP_INDEX};

enum Order {
Expand Down Expand Up @@ -47,7 +51,8 @@ macro_rules! define_linear_ds_host_test {
] {
let prog: &mut UProbe = bpf.program_mut(prog_name).unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach(symbol, "/proc/self/exe", None).unwrap();
prog.attach(symbol, "/proc/self/exe", UProbeScope::AllProcesses)
.unwrap();
}
let array_map = bpf.map("RESULT").unwrap();
let array = Array::<_, u64>::try_from(array_map).unwrap();
Expand Down
55 changes: 41 additions & 14 deletions test/integration-test/src/tests/load.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::{convert::TryInto as _, fs::remove_file, path::Path, thread, time::Duration};
use std::{
convert::TryInto as _, fs::remove_file, num::NonZeroU32, path::Path, thread, time::Duration,
};

use assert_matches::assert_matches;
use aya::{
Expand All @@ -14,12 +16,13 @@ use aya::{
loaded_links, loaded_programs,
tc::TcAttachOptions,
trace_point::{TracePointLink, TracePointLinkId},
uprobe::{UProbeLink, UProbeLinkId},
uprobe::{UProbeLink, UProbeLinkId, UProbeScope},
xdp::{XdpLink, XdpLinkId},
},
util::KernelVersion,
};
use aya_obj::programs::XdpAttachType;
use test_case::test_case;

const MAX_RETRIES: usize = 100;
pub(crate) const RETRY_DURATION: Duration = Duration::from_millis(10);
Expand Down Expand Up @@ -55,8 +58,12 @@ fn ringbuffer_btf_map() {

let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach("trigger_bpf_program", "/proc/self/exe", None)
.unwrap();
prog.attach(
"trigger_bpf_program",
"/proc/self/exe",
UProbeScope::AllProcesses,
)
.unwrap();

trigger_bpf_program();

Expand All @@ -77,8 +84,12 @@ fn multiple_btf_maps() {

let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach("trigger_bpf_program", "/proc/self/exe", None)
.unwrap();
prog.attach(
"trigger_bpf_program",
"/proc/self/exe",
UProbeScope::AllProcesses,
)
.unwrap();

trigger_bpf_program();

Expand Down Expand Up @@ -127,8 +138,12 @@ fn pin_lifecycle_multiple_btf_maps() {

let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach("trigger_bpf_program", "/proc/self/exe", None)
.unwrap();
prog.attach(
"trigger_bpf_program",
"/proc/self/exe",
UProbeScope::AllProcesses,
)
.unwrap();

trigger_bpf_program();

Expand Down Expand Up @@ -276,13 +291,14 @@ fn unload_xdp() {
);
}

fn run_unload_program_test<P>(
fn run_unload_program_test<P, F>(
bpf_image: &[u8],
program_name: &str,
attach: fn(&mut P) -> P::LinkId,
attach: F,
expect_fd_link: bool,
) where
P: UnloadProgramOps,
F: Fn(&mut P) -> P::LinkId,
P::OwnedLink: TryInto<FdLink, Error = LinkError>,
for<'a> &'a mut Program: TryInto<&'a mut P, Error = ProgramError>,
{
Expand Down Expand Up @@ -351,15 +367,22 @@ fn basic_tracepoint() {
);
}

#[test_case(UProbeScope::AllProcesses; "all_processes")]
#[test_case(UProbeScope::CallingProcess; "calling_process")]
#[test_case(
UProbeScope::OneProcess(NonZeroU32::new(std::process::id()).unwrap());
"one_process"
)]
#[test_log::test]
fn basic_uprobe() {
fn basic_uprobe_scopes(scope: UProbeScope) {
type P = UProbe;

let program_name = "test_uprobe";
let attach = |prog: &mut P| {
prog.attach("uprobe_function", "/proc/self/exe", None)
prog.attach("uprobe_function", "/proc/self/exe", scope)
.unwrap()
};

run_unload_program_test(
crate::TEST,
program_name,
Expand Down Expand Up @@ -659,8 +682,12 @@ fn pin_lifecycle_uprobe() {

let program_name = "test_uprobe";
let attach = |prog: &mut P| {
prog.attach("uprobe_function", "/proc/self/exe", None)
.unwrap()
prog.attach(
"uprobe_function",
"/proc/self/exe",
UProbeScope::AllProcesses,
)
.unwrap()
};
let program_pin = "/sys/fs/bpf/aya-uprobe-test-prog";
let link_pin = "/sys/fs/bpf/aya-uprobe-test-uprobe-function";
Expand Down
30 changes: 23 additions & 7 deletions test/integration-test/src/tests/log.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use std::{borrow::Cow, sync::Mutex};

use aya::{Ebpf, EbpfLoader, maps::Array, programs::UProbe};
use aya::{
Ebpf, EbpfLoader,
maps::Array,
programs::{UProbe, uprobe::UProbeScope},
};
use aya_log::EbpfLogger;
use integration_common::log::{BUF_LEN, Buffer};
use log::{Level, Log, Record};
Expand Down Expand Up @@ -69,8 +73,12 @@ fn log() {

let prog: &mut UProbe = bpf.program_mut("test_log").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach("trigger_ebpf_program", "/proc/self/exe", None)
.unwrap();
prog.attach(
"trigger_ebpf_program",
"/proc/self/exe",
UProbeScope::AllProcesses,
)
.unwrap();

// Call the function that the uprobe is attached to, so it starts logging.
trigger_ebpf_program();
Expand Down Expand Up @@ -248,8 +256,12 @@ fn log_level_only_error_warn() {

let prog: &mut UProbe = bpf.program_mut("test_log").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach("trigger_ebpf_program", "/proc/self/exe", None)
.unwrap();
prog.attach(
"trigger_ebpf_program",
"/proc/self/exe",
UProbeScope::AllProcesses,
)
.unwrap();

trigger_ebpf_program();
logger.flush();
Expand Down Expand Up @@ -303,8 +315,12 @@ fn log_level_prevents_verif_fail() {
.try_into()
.unwrap();
prog.load().unwrap();
prog.attach("trigger_ebpf_program", "/proc/self/exe", None)
.unwrap();
prog.attach(
"trigger_ebpf_program",
"/proc/self/exe",
UProbeScope::AllProcesses,
)
.unwrap();

trigger_ebpf_program();
logger.flush();
Expand Down
Loading