Skip to content
Open
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
5 changes: 4 additions & 1 deletion aya/src/programs/kprobe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::{
ProgramData, ProgramError, ProgramType, define_link_wrapper, impl_try_from_fdlink,
impl_try_into_fdlink, load_program_without_attach_type,
perf_attach::{PerfLinkIdInner, PerfLinkInner},
perf_event::PerfEventScope,
probe::{Probe, ProbeKind, attach},
},
};
Expand Down Expand Up @@ -87,7 +88,9 @@ impl KProbe {
*kind,
fn_name.as_ref(),
offset,
None, // pid
// For all-processes attachment, perf_event_open requires an explicit
// CPU. Use CPU 0 only to open the backing perf event.
PerfEventScope::AllProcessesOneCpu { cpu: 0 },
None, // cookie
)
}
Expand Down
27 changes: 27 additions & 0 deletions aya/src/programs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ use std::{
borrow::Cow,
ffi::CString,
io,
num::NonZeroU32,
os::fd::{AsFd, BorrowedFd},
path::{Path, PathBuf},
sync::Arc,
Expand Down Expand Up @@ -270,6 +271,32 @@ impl AsFd for ProgramFd {
}
}

/// A non-zero process identifier.
///
/// This type represents a real process ID. Kernel sentinel values such as `0`
/// are modeled separately by the APIs that accept them.
#[derive(Debug, Clone, Copy)]
pub struct Pid(NonZeroU32);

impl Pid {
/// Creates a process identifier from a raw PID.
///
/// Returns `None` if `pid` is zero.
pub fn new(pid: u32) -> Option<Self> {
NonZeroU32::new(pid).map(Self)
}

/// Returns the identifier of the current process.
pub fn current() -> Self {
Self(NonZeroU32::new(std::process::id()).unwrap())
}

/// Returns the raw PID value.
pub const fn get(self) -> u32 {
self.0.get()
}
}

/// A [`Program`] identifier.
pub struct ProgramId(u32);

Expand Down
4 changes: 2 additions & 2 deletions aya/src/programs/perf_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use aya_obj::generated::{

use crate::{
programs::{
ProgramData, ProgramError, ProgramType, impl_try_from_fdlink, impl_try_into_fdlink,
Pid, ProgramData, ProgramError, ProgramType, impl_try_from_fdlink, impl_try_into_fdlink,
links::define_link_wrapper,
load_program_without_attach_type,
perf_attach::{PerfLinkIdInner, PerfLinkInner, perf_attach},
Expand Down Expand Up @@ -372,7 +372,7 @@ pub enum PerfEventScope {
/// one process
OneProcess {
/// process id
pid: u32,
pid: Pid,
/// cpu id or any cpu if None
cpu: Option<u32>,
},
Expand Down
17 changes: 9 additions & 8 deletions aya/src/programs/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use std::{
use crate::{
programs::{
Link, ProgramData, ProgramError, perf_attach, perf_attach::PerfLinkInner,
perf_attach_debugfs, trace_point::read_sys_fs_trace_point_id, utils::find_tracefs_path,
perf_attach_debugfs, perf_event::PerfEventScope, trace_point::read_sys_fs_trace_point_id,
utils::find_tracefs_path,
},
sys::{SyscallError, perf_event_open_probe, perf_event_open_trace_point},
util::KernelVersion,
Expand Down Expand Up @@ -145,21 +146,21 @@ pub(crate) fn attach<P: Probe, T: Link + From<PerfLinkInner>>(
// separate argument.
fn_name: &OsStr,
offset: u64,
pid: Option<u32>,
scope: PerfEventScope,
cookie: Option<u64>,
) -> Result<T::Id, ProgramError> {
// https://github.com/torvalds/linux/commit/e12f03d7031a977356e3d7b75a68c2185ff8d155
// Use debugfs to create probe
let prog_fd = program_data.fd()?;
let prog_fd = prog_fd.as_fd();
let link = if KernelVersion::at_least(4, 17, 0) {
let perf_fd = create_as_probe::<P>(kind, fn_name, offset, pid)?;
let perf_fd = create_as_probe::<P>(kind, fn_name, offset, scope)?;
perf_attach(prog_fd, perf_fd, cookie)
} else {
if cookie.is_some() {
return Err(ProgramError::AttachCookieNotSupported);
}
let (perf_fd, event) = create_as_trace_point::<P>(kind, fn_name, offset, pid)?;
let (perf_fd, event) = create_as_trace_point::<P>(kind, fn_name, offset, scope)?;
perf_attach_debugfs(prog_fd, perf_fd, event)
}?;
program_data.links.insert(T::from(link))
Expand All @@ -176,7 +177,7 @@ fn create_as_probe<P: Probe>(
kind: ProbeKind,
fn_name: &OsStr,
offset: u64,
pid: Option<u32>,
scope: PerfEventScope,
) -> Result<crate::MockableFd, ProgramError> {
let perf_ty = read_sys_fs_perf_type(P::PMU)
.map_err(|(filename, io_error)| P::file_error(filename, io_error).into())?;
Expand All @@ -189,7 +190,7 @@ fn create_as_probe<P: Probe>(
ProbeKind::Entry => None,
};

perf_event_open_probe(perf_ty, ret_bit, fn_name, offset, pid)
perf_event_open_probe(perf_ty, ret_bit, fn_name, offset, scope)
.map_err(|io_error| SyscallError {
call: "perf_event_open",
io_error,
Expand All @@ -201,7 +202,7 @@ fn create_as_trace_point<P: Probe>(
kind: ProbeKind,
name: &OsStr,
offset: u64,
pid: Option<u32>,
scope: PerfEventScope,
) -> Result<(crate::MockableFd, ProbeEvent), ProgramError> {
let tracefs = find_tracefs_path()?;

Expand All @@ -214,7 +215,7 @@ fn create_as_trace_point<P: Probe>(
} = &event;
let category = format!("{}s", P::PMU);
let tpid = read_sys_fs_trace_point_id(tracefs, &category, event_alias.as_ref())?;
let perf_fd = perf_event_open_trace_point(tpid, pid).map_err(|io_error| SyscallError {
let perf_fd = perf_event_open_trace_point(tpid, scope).map_err(|io_error| SyscallError {
call: "perf_event_open",
io_error,
})?;
Expand Down
9 changes: 8 additions & 1 deletion aya/src/programs/trace_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{
ProgramData, ProgramError, ProgramType, define_link_wrapper, impl_try_from_fdlink,
impl_try_into_fdlink, load_program_without_attach_type,
perf_attach::{PerfLinkIdInner, PerfLinkInner, perf_attach},
perf_event::PerfEventScope,
utils::find_tracefs_path,
},
sys::{SyscallError, perf_event_open_trace_point},
Expand Down Expand Up @@ -80,7 +81,13 @@ impl TracePoint {
let prog_fd = prog_fd.as_fd();
let tracefs = find_tracefs_path()?;
let id = read_sys_fs_trace_point_id(tracefs, category, name.as_ref())?;
let perf_fd = perf_event_open_trace_point(id, None).map_err(|io_error| SyscallError {
let perf_fd = perf_event_open_trace_point(
id,
// For all-processes attachment, perf_event_open requires an explicit
// CPU. Use CPU 0 only to open the backing perf event.
PerfEventScope::AllProcessesOneCpu { cpu: 0 },
)
.map_err(|io_error| SyscallError {
call: "perf_event_open_trace_point",
io_error,
})?;
Expand Down
28 changes: 17 additions & 11 deletions aya/src/programs/uprobe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ 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 All @@ -19,9 +18,10 @@ use thiserror::Error;
use crate::{
VerifierLogLevel,
programs::{
ProgramData, ProgramError, ProgramType, define_link_wrapper, impl_try_from_fdlink,
Pid, ProgramData, ProgramError, ProgramType, define_link_wrapper, impl_try_from_fdlink,
impl_try_into_fdlink, load_program_without_attach_type,
perf_attach::{PerfLinkIdInner, PerfLinkInner},
perf_event::PerfEventScope,
probe::{OsStringExt as _, Probe, ProbeKind, attach},
},
util::MMap,
Expand Down Expand Up @@ -97,7 +97,7 @@ pub enum UProbeScope {
/// Fire only when the calling process/thread hits the attach point.
CallingProcess,
/// Fire only when the given process hits the attach point.
OneProcess(NonZeroU32),
OneProcess(Pid),
}

impl UProbe {
Expand Down Expand Up @@ -144,15 +144,21 @@ impl UProbe {
) -> Result<UProbeLinkId, ProgramError> {
let UProbeAttachPoint { location, cookie } = point.into();
let target = target.as_ref();
let (proc_map_pid, perf_event_pid) = match scope {
UProbeScope::AllProcesses => (None, None),
let (proc_map_pid, perf_event_scope) = match scope {
// For an all-processes uprobe, perf_event_open uses pid=-1 and
// requires an explicit CPU. Use CPU 0 only to open the backing
// perf event.
UProbeScope::AllProcesses => (None, PerfEventScope::AllProcessesOneCpu { cpu: 0 }),
// /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))
}
UProbeScope::CallingProcess => (
Some(std::process::id()),
PerfEventScope::CallingProcess { cpu: None },
),
UProbeScope::OneProcess(pid) => (
Some(pid.get()),
PerfEventScope::OneProcess { pid, cpu: None },
),
};

// Keep ProcMap in this scope so resolve_attach_target_basename can return
Expand Down Expand Up @@ -187,7 +193,7 @@ impl UProbe {

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

/// Creates a program from a pinned entry on a bpffs.
Expand Down
10 changes: 5 additions & 5 deletions aya/src/sys/fake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ use std::{cell::RefCell, ffi::c_void, io, ptr};

use super::{SysResult, Syscall};

type SyscallFn = unsafe fn(Syscall<'_>) -> SysResult;
type SyscallFn = dyn for<'a> Fn(Syscall<'a>) -> SysResult;

#[cfg(test)]
thread_local! {
pub(crate) static TEST_SYSCALL: RefCell<SyscallFn> = RefCell::new(test_syscall);
pub(crate) static TEST_SYSCALL: RefCell<Box<SyscallFn>> = RefCell::new(Box::new(test_syscall));
pub(crate) static TEST_MMAP_RET: RefCell<*mut c_void> = const { RefCell::new(ptr::null_mut()) };
}

#[cfg(test)]
unsafe fn test_syscall(_call: Syscall<'_>) -> SysResult {
fn test_syscall(_call: Syscall<'_>) -> SysResult {
Err((-1, io::Error::from_raw_os_error(libc::EINVAL)))
}

#[cfg(test)]
pub(crate) fn override_syscall(call: unsafe fn(Syscall<'_>) -> SysResult) {
TEST_SYSCALL.with(|test_impl| *test_impl.borrow_mut() = call);
pub(crate) fn override_syscall(call: impl for<'a> Fn(Syscall<'a>) -> SysResult + 'static) {
TEST_SYSCALL.with(|test_impl| *test_impl.borrow_mut() = Box::new(call));
}
3 changes: 1 addition & 2 deletions aya/src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ pub(crate) enum PerfEventIoctlRequest<'a> {
SetBpf(BorrowedFd<'a>),
}

#[cfg_attr(test, expect(dead_code, reason = "test stubs cut above this"))]
pub(crate) enum Syscall<'a> {
Ebpf {
cmd: bpf_cmd,
Expand Down Expand Up @@ -99,7 +98,7 @@ impl std::fmt::Debug for Syscall<'_> {
fn syscall(call: Syscall<'_>) -> SysResult {
#[cfg(test)]
{
TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) })
TEST_SYSCALL.with(|test_impl| test_impl.borrow()(call))
}

#[cfg(not(test))]
Expand Down
Loading