Skip to content

Commit 759087b

Browse files
swananantamird
authored andcommitted
aya: replace pid Option<u32> with UProbeScope
Replace the pid Option in UProbe::attach with UProbeScope so the all-processes, calling-process, and explicit-pid cases are all expressed directly in the type. This removes pid=0 as a magic value from the public API, keeps the calling-process case explicit, and uses the current pid for ProcMap resolution introduced in the previous commit. Update docs and integration tests to use the new scope-based API.
1 parent 8912e41 commit 759087b

21 files changed

Lines changed: 225 additions & 90 deletions

aya/src/bpf.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,11 +1099,11 @@ impl Ebpf {
10991099
///
11001100
/// ```no_run
11011101
/// # let mut bpf = aya::Ebpf::load(&[])?;
1102-
/// use aya::programs::UProbe;
1102+
/// use aya::programs::{uprobe::UProbeScope, UProbe};
11031103
///
11041104
/// let program: &mut UProbe = bpf.program_mut("SSL_read").unwrap().try_into()?;
11051105
/// program.load()?;
1106-
/// program.attach("SSL_read", "libssl", None)?;
1106+
/// program.attach("SSL_read", "libssl", UProbeScope::AllProcesses)?;
11071107
/// # Ok::<(), aya::EbpfError>(())
11081108
/// ```
11091109
pub fn program_mut(&mut self, name: &str) -> Option<&mut Program> {

aya/src/programs/uprobe.rs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
fmt::{self, Write},
77
fs,
88
io::{self, BufRead as _, Cursor, Read as _},
9+
num::NonZeroU32,
910
os::unix::ffi::{OsStrExt as _, OsStringExt as _},
1011
path::{Path, PathBuf},
1112
sync::LazyLock,
@@ -88,6 +89,17 @@ impl<'a, L: Into<UProbeAttachLocation<'a>>> From<L> for UProbeAttachPoint<'a> {
8889
}
8990
}
9091

92+
/// Specifies which processes a uprobe should fire for.
93+
#[derive(Debug, Clone, Copy)]
94+
pub enum UProbeScope {
95+
/// Fire for any process that hits the attach point.
96+
AllProcesses,
97+
/// Fire only when the calling process/thread hits the attach point.
98+
CallingProcess,
99+
/// Fire only when the given process hits the attach point.
100+
OneProcess(NonZeroU32),
101+
}
102+
91103
impl UProbe {
92104
/// The type of the program according to the kernel.
93105
pub const PROGRAM_TYPE: ProgramType = ProgramType::KProbe;
@@ -108,9 +120,8 @@ impl UProbe {
108120
///
109121
/// Attaches the uprobe to the function `fn_name` defined in the `target`.
110122
/// If the attach point specifies an offset, it is added to the address of
111-
/// the target function. If `pid` is not `None`, the program executes only
112-
/// when the target function is executed by the given `pid`; `Some(0)`
113-
/// means the calling process/thread.
123+
/// the target function. `scope` specifies which processes should trigger
124+
/// the uprobe.
114125
///
115126
/// The `target` argument can be an absolute path to a binary or library, or
116127
/// a library name (eg: `"libc"`).
@@ -129,12 +140,19 @@ impl UProbe {
129140
&mut self,
130141
point: Point,
131142
target: T,
132-
pid: Option<u32>,
143+
scope: UProbeScope,
133144
) -> Result<UProbeLinkId, ProgramError> {
134145
let UProbeAttachPoint { location, cookie } = point.into();
135-
// /proc/0/maps does not exist; use the current pid only for ProcMap
136-
// resolution and preserve pid=0 for the actual attach semantics.
137-
let proc_map_pid = pid.map(|pid| if pid == 0 { std::process::id() } else { pid });
146+
let (proc_map_pid, perf_event_pid) = match scope {
147+
UProbeScope::AllProcesses => (None, None),
148+
// /proc/0/maps does not exist, so use the real pid for ProcMap
149+
// resolution while keeping the kernel's pid=0 sentinel for attach.
150+
UProbeScope::CallingProcess => (Some(std::process::id()), Some(0)),
151+
UProbeScope::OneProcess(pid) => {
152+
let pid = pid.get();
153+
(Some(pid), Some(pid))
154+
}
155+
};
138156
let proc_map = proc_map_pid.map(ProcMap::new).transpose()?;
139157
let path = resolve_attach_path(target.as_ref(), proc_map.as_ref())?;
140158
let (symbol, offset) = match location {
@@ -155,7 +173,7 @@ impl UProbe {
155173

156174
let Self { data, kind } = self;
157175
let path = path.as_os_str();
158-
attach::<Self, _>(data, *kind, path, offset, pid, cookie)
176+
attach::<Self, _>(data, *kind, path, offset, perf_event_pid, cookie)
159177
}
160178

161179
/// Creates a program from a pinned entry on a bpffs.

test/integration-test/src/tests/array.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use aya::{EbpfLoader, maps::Array, programs::UProbe};
1+
use aya::{
2+
EbpfLoader,
3+
maps::Array,
4+
programs::{UProbe, uprobe::UProbeScope},
5+
};
26
use integration_common::array::{ARRAY_LEN, GET_INDEX, GET_PTR_INDEX, GET_PTR_MUT_INDEX};
37
use test_case::test_case;
48

@@ -68,7 +72,7 @@ fn test_array(
6872
.unwrap_or_else(|err| panic!("program {prog_name} is not a uprobe: {err}"));
6973
prog.load()
7074
.unwrap_or_else(|err| panic!("load {prog_name}: {err}"));
71-
prog.attach(symbol, "/proc/self/exe", None)
75+
prog.attach(symbol, "/proc/self/exe", UProbeScope::AllProcesses)
7276
.unwrap_or_else(|err| panic!("attach {prog_name}: {err}"));
7377
}
7478

test/integration-test/src/tests/bloom_filter.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use aya::{
22
EbpfLoader,
33
maps::{Array, MapError, MapType, bloom_filter::BloomFilter},
4-
programs::UProbe,
4+
programs::{UProbe, uprobe::UProbeScope},
55
sys::is_map_supported,
66
};
77
use integration_common::bloom_filter::{
@@ -57,7 +57,7 @@ fn bloom_filter_basic(result_map: &str, filter_map: &str, insert_prog: &str, con
5757
.unwrap_or_else(|err| panic!("program {prog_name} is not a uprobe: {err}"));
5858
prog.load()
5959
.unwrap_or_else(|err| panic!("load {prog_name}: {err}"));
60-
prog.attach(symbol, "/proc/self/exe", None)
60+
prog.attach(symbol, "/proc/self/exe", UProbeScope::AllProcesses)
6161
.unwrap_or_else(|err| panic!("attach {prog_name}: {err}"));
6262
}
6363

test/integration-test/src/tests/bpf_probe_read.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use aya::{Ebpf, maps::Array, programs::UProbe};
1+
use aya::{
2+
Ebpf,
3+
maps::Array,
4+
programs::{UProbe, uprobe::UProbeScope},
5+
};
26
use integration_common::bpf_probe_read::{RESULT_BUF_LEN, TestResult};
37

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

102-
prog.attach(func_name, "/proc/self/exe", None).unwrap();
106+
prog.attach(func_name, "/proc/self/exe", UProbeScope::AllProcesses)
107+
.unwrap();
103108

104109
bpf
105110
}

test/integration-test/src/tests/btf_relocations.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use aya::{EbpfLoader, Endianness, maps::Array, programs::UProbe};
1+
use aya::{
2+
EbpfLoader, Endianness,
3+
maps::Array,
4+
programs::{UProbe, uprobe::UProbeScope},
5+
};
26
use aya_obj::btf::Btf;
37
use test_case::test_case;
48

@@ -90,7 +94,11 @@ fn relocation_tests(
9094
let program: &mut UProbe = bpf.program_mut("program").unwrap().try_into().unwrap();
9195
program.load().unwrap();
9296
program
93-
.attach("trigger_btf_relocations_program", "/proc/self/exe", None)
97+
.attach(
98+
"trigger_btf_relocations_program",
99+
"/proc/self/exe",
100+
UProbeScope::AllProcesses,
101+
)
94102
.unwrap();
95103

96104
trigger_btf_relocations_program();

test/integration-test/src/tests/info.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use std::{fs, panic, path::Path, time::SystemTime};
1111
use aya::{
1212
Ebpf,
1313
maps::{Array, HashMap, IterableMap as _, MapError, MapType, loaded_maps},
14-
programs::{ProgramError, ProgramType, SocketFilter, TracePoint, UProbe, loaded_programs},
14+
programs::{
15+
ProgramError, ProgramType, SocketFilter, TracePoint, UProbe, loaded_programs,
16+
uprobe::UProbeScope,
17+
},
1518
sys::{is_map_supported, is_program_supported},
1619
util::KernelVersion,
1720
};
@@ -65,7 +68,13 @@ fn test_loaded_programs() {
6568
};
6669

6770
// Ensure we can perform basic operations on the re-created program.
68-
let res = p.attach("uprobe_function", "/proc/self/exe", None).unwrap();
71+
let res = p
72+
.attach(
73+
"uprobe_function",
74+
"/proc/self/exe",
75+
UProbeScope::AllProcesses,
76+
)
77+
.unwrap();
6978

7079
// Ensure the program can be detached.
7180
p.detach(res).unwrap();

test/integration-test/src/tests/linear_data_structures.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use aya::{EbpfLoader, maps::Array, programs::UProbe};
1+
use aya::{
2+
EbpfLoader,
3+
maps::Array,
4+
programs::{UProbe, uprobe::UProbeScope},
5+
};
26
use integration_common::linear_data_structures::{PEEK_INDEX, POP_INDEX};
37

48
enum Order {
@@ -47,7 +51,8 @@ macro_rules! define_linear_ds_host_test {
4751
] {
4852
let prog: &mut UProbe = bpf.program_mut(prog_name).unwrap().try_into().unwrap();
4953
prog.load().unwrap();
50-
prog.attach(symbol, "/proc/self/exe", None).unwrap();
54+
prog.attach(symbol, "/proc/self/exe", UProbeScope::AllProcesses)
55+
.unwrap();
5156
}
5257
let array_map = bpf.map("RESULT").unwrap();
5358
let array = Array::<_, u64>::try_from(array_map).unwrap();

test/integration-test/src/tests/load.rs

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use std::{convert::TryInto as _, fs::remove_file, path::Path, thread, time::Duration};
1+
use std::{
2+
convert::TryInto as _, fs::remove_file, num::NonZeroU32, path::Path, thread, time::Duration,
3+
};
24

35
use assert_matches::assert_matches;
46
use aya::{
@@ -14,12 +16,13 @@ use aya::{
1416
loaded_links, loaded_programs,
1517
tc::TcAttachOptions,
1618
trace_point::{TracePointLink, TracePointLinkId},
17-
uprobe::{UProbeLink, UProbeLinkId},
19+
uprobe::{UProbeLink, UProbeLinkId, UProbeScope},
1820
xdp::{XdpLink, XdpLinkId},
1921
},
2022
util::KernelVersion,
2123
};
2224
use aya_obj::programs::XdpAttachType;
25+
use test_case::test_case;
2326

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

5659
let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap();
5760
prog.load().unwrap();
58-
prog.attach("trigger_bpf_program", "/proc/self/exe", None)
59-
.unwrap();
61+
prog.attach(
62+
"trigger_bpf_program",
63+
"/proc/self/exe",
64+
UProbeScope::AllProcesses,
65+
)
66+
.unwrap();
6067

6168
trigger_bpf_program();
6269

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

7885
let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap();
7986
prog.load().unwrap();
80-
prog.attach("trigger_bpf_program", "/proc/self/exe", None)
81-
.unwrap();
87+
prog.attach(
88+
"trigger_bpf_program",
89+
"/proc/self/exe",
90+
UProbeScope::AllProcesses,
91+
)
92+
.unwrap();
8293

8394
trigger_bpf_program();
8495

@@ -127,8 +138,12 @@ fn pin_lifecycle_multiple_btf_maps() {
127138

128139
let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap();
129140
prog.load().unwrap();
130-
prog.attach("trigger_bpf_program", "/proc/self/exe", None)
131-
.unwrap();
141+
prog.attach(
142+
"trigger_bpf_program",
143+
"/proc/self/exe",
144+
UProbeScope::AllProcesses,
145+
)
146+
.unwrap();
132147

133148
trigger_bpf_program();
134149

@@ -276,13 +291,14 @@ fn unload_xdp() {
276291
);
277292
}
278293

279-
fn run_unload_program_test<P>(
294+
fn run_unload_program_test<P, F>(
280295
bpf_image: &[u8],
281296
program_name: &str,
282-
attach: fn(&mut P) -> P::LinkId,
297+
attach: F,
283298
expect_fd_link: bool,
284299
) where
285300
P: UnloadProgramOps,
301+
F: Fn(&mut P) -> P::LinkId,
286302
P::OwnedLink: TryInto<FdLink, Error = LinkError>,
287303
for<'a> &'a mut Program: TryInto<&'a mut P, Error = ProgramError>,
288304
{
@@ -351,32 +367,22 @@ fn basic_tracepoint() {
351367
);
352368
}
353369

370+
#[test_case(UProbeScope::AllProcesses; "all_processes")]
371+
#[test_case(UProbeScope::CallingProcess; "calling_process")]
372+
#[test_case(
373+
UProbeScope::OneProcess(NonZeroU32::new(std::process::id()).unwrap());
374+
"one_process"
375+
)]
354376
#[test_log::test]
355-
fn basic_uprobe() {
377+
fn basic_uprobe_scopes(scope: UProbeScope) {
356378
type P = UProbe;
357379

358380
let program_name = "test_uprobe";
359381
let attach = |prog: &mut P| {
360-
prog.attach("uprobe_function", "/proc/self/exe", None)
382+
prog.attach("uprobe_function", "/proc/self/exe", scope)
361383
.unwrap()
362384
};
363-
run_unload_program_test(
364-
crate::TEST,
365-
program_name,
366-
attach,
367-
aya::features().bpf_perf_link(), // probe uses perf_attach.
368-
);
369-
}
370-
371-
#[test_log::test]
372-
fn basic_uprobe_pid_zero_is_self() {
373-
type P = UProbe;
374385

375-
let program_name = "test_uprobe";
376-
let attach = |prog: &mut P| {
377-
prog.attach("uprobe_function", "/proc/self/exe", Some(0))
378-
.unwrap()
379-
};
380386
run_unload_program_test(
381387
crate::TEST,
382388
program_name,
@@ -676,8 +682,12 @@ fn pin_lifecycle_uprobe() {
676682

677683
let program_name = "test_uprobe";
678684
let attach = |prog: &mut P| {
679-
prog.attach("uprobe_function", "/proc/self/exe", None)
680-
.unwrap()
685+
prog.attach(
686+
"uprobe_function",
687+
"/proc/self/exe",
688+
UProbeScope::AllProcesses,
689+
)
690+
.unwrap()
681691
};
682692
let program_pin = "/sys/fs/bpf/aya-uprobe-test-prog";
683693
let link_pin = "/sys/fs/bpf/aya-uprobe-test-uprobe-function";

0 commit comments

Comments
 (0)