Skip to main content

aya_friday/programs/
info.rs

1//! Metadata information about an eBPF program.
2
3use std::{
4    ffi::CString,
5    os::fd::{AsFd as _, BorrowedFd},
6    path::Path,
7    sync::OnceLock,
8    time::{Duration, SystemTime},
9};
10
11use aya_obj::generated::{bpf_prog_info, bpf_prog_type};
12
13use super::{
14    ProgramError, ProgramFd,
15    utils::{boot_time, get_fdinfo},
16};
17use crate::{
18    FEATURES,
19    sys::{
20        SyscallError, bpf_get_object, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd,
21        feature_probe::{is_prog_info_license_supported, is_prog_info_map_ids_supported},
22        iter_prog_ids,
23    },
24    util::bytes_of_bpf_name,
25};
26
27/// Provides metadata information about a loaded eBPF program.
28///
29/// Introduced in kernel v4.13.
30#[doc(alias = "bpf_prog_info")]
31#[derive(Debug)]
32pub struct ProgramInfo(pub(crate) bpf_prog_info);
33
34impl ProgramInfo {
35    pub(crate) fn new_from_fd(fd: BorrowedFd<'_>) -> Result<Self, ProgramError> {
36        let info = bpf_prog_get_info_by_fd(fd, &mut [])?;
37        Ok(Self(info))
38    }
39
40    /// The type of program.
41    ///
42    /// Introduced in kernel v4.13.
43    pub fn program_type(&self) -> bpf_prog_type {
44        bpf_prog_type::try_from(self.0.type_).unwrap_or(bpf_prog_type::__MAX_BPF_PROG_TYPE)
45    }
46
47    /// The unique ID for this program.
48    ///
49    /// Introduced in kernel v4.13.
50    pub const fn id(&self) -> u32 {
51        self.0.id
52    }
53
54    /// The program tag.
55    ///
56    /// The tag is a SHA sum of the program's instructions which be used as an alternative to
57    /// [`Self::id()`]. A program's ID can vary every time it's loaded or unloaded, but the tag
58    /// will remain the same.
59    ///
60    /// Introduced in kernel v4.13.
61    #[expect(
62        clippy::big_endian_bytes,
63        reason = "the kernel exposes the tag as a big-endian byte array"
64    )]
65    pub const fn tag(&self) -> u64 {
66        u64::from_be_bytes(self.0.tag)
67    }
68
69    /// The size in bytes of the program's JIT-compiled machine code.
70    ///
71    /// Note that this field is only updated when BPF JIT compiler is enabled. Kernels v4.15 and
72    /// above may already have it enabled by default.
73    ///
74    /// Introduced in kernel v4.13.
75    pub const fn size_jitted(&self) -> u32 {
76        self.0.jited_prog_len
77    }
78
79    /// The size in bytes of the program's translated eBPF bytecode.
80    ///
81    /// The translated bytecode is after it has been passed though the verifier where it was
82    /// possibly modified by the kernel.
83    ///
84    /// `None` is returned if the field is not available.
85    ///
86    /// Introduced in kernel v4.15.
87    pub fn size_translated(&self) -> Option<u32> {
88        (self.0.xlated_prog_len > 0).then_some(self.0.xlated_prog_len)
89    }
90
91    /// The time when the program was loaded.
92    ///
93    /// `None` is returned if the field is not available.
94    ///
95    /// Introduced in kernel v4.15.
96    pub fn loaded_at(&self) -> Option<SystemTime> {
97        (self.0.load_time > 0).then_some(boot_time() + Duration::from_nanos(self.0.load_time))
98    }
99
100    /// The user ID of the process who loaded the program.
101    ///
102    /// `None` is returned if the field is not available.
103    ///
104    /// Introduced in kernel v4.15.
105    pub fn created_by_uid(&self) -> Option<u32> {
106        // This field was introduced in the same commit as `load_time`.
107        (self.0.load_time > 0).then_some(self.0.created_by_uid)
108    }
109
110    /// The IDs of the maps used by the program.
111    ///
112    /// `None` is returned if the field is not available.
113    ///
114    /// Introduced in kernel v4.15.
115    pub fn map_ids(&self) -> Result<Option<Vec<u32>>, ProgramError> {
116        static CACHE: OnceLock<bool> = OnceLock::new();
117        CACHE
118            .get_or_init(|| {
119                self.0.nr_map_ids > 0 || matches!(is_prog_info_map_ids_supported(), Ok(true))
120            })
121            .then(|| {
122                let mut map_ids = vec![0u32; self.0.nr_map_ids as usize];
123                bpf_prog_get_info_by_fd(self.fd()?.as_fd(), &mut map_ids)?;
124                Ok(map_ids)
125            })
126            .transpose()
127    }
128
129    /// The name of the program as was provided when it was load. This is limited to 16 bytes.
130    ///
131    /// Introduced in kernel v4.15.
132    pub fn name(&self) -> &[u8] {
133        bytes_of_bpf_name(&self.0.name)
134    }
135
136    /// The name of the program as a &str.
137    ///
138    /// `None` is returned if the name was not valid unicode or if field is not available.
139    ///
140    /// Introduced in kernel v4.15.
141    pub fn name_as_str(&self) -> Option<&str> {
142        let name = std::str::from_utf8(self.name()).ok()?;
143        (FEATURES.bpf_name() || !name.is_empty()).then_some(name)
144    }
145
146    /// Returns true if the program is defined with a GPL-compatible license.
147    ///
148    /// `None` is returned if the field is not available.
149    ///
150    /// Introduced in kernel v4.18.
151    pub fn gpl_compatible(&self) -> Option<bool> {
152        static CACHE: OnceLock<bool> = OnceLock::new();
153        CACHE
154            .get_or_init(|| {
155                self.0.gpl_compatible() != 0 || matches!(is_prog_info_license_supported(), Ok(true))
156            })
157            .then_some(self.0.gpl_compatible() != 0)
158    }
159
160    /// The BTF ID for the program.
161    ///
162    /// Introduced in kernel v5.0.
163    pub fn btf_id(&self) -> Option<u32> {
164        (self.0.btf_id > 0).then_some(self.0.btf_id)
165    }
166
167    /// The accumulated time that the program has been actively running.
168    ///
169    /// This is not to be confused with the duration since the program was
170    /// first loaded on the host.
171    ///
172    /// Note this field is only updated for as long as
173    /// [`enable_stats`](crate::sys::enable_stats) is enabled
174    /// with [`Stats::RunTime`](crate::sys::Stats::RunTime).
175    ///
176    /// Introduced in kernel v5.1.
177    pub const fn run_time(&self) -> Duration {
178        Duration::from_nanos(self.0.run_time_ns)
179    }
180
181    /// The accumulated execution count of the program.
182    ///
183    /// Note this field is only updated for as long as
184    /// [`enable_stats`](crate::sys::enable_stats) is enabled
185    /// with [`Stats::RunTime`](crate::sys::Stats::RunTime).
186    ///
187    /// Introduced in kernel v5.1.
188    pub const fn run_count(&self) -> u64 {
189        self.0.run_cnt
190    }
191
192    /// The number of verified instructions in the program.
193    ///
194    /// This may be less than the total number of instructions in the compiled program due to dead
195    /// code elimination in the verifier.
196    ///
197    /// `None` is returned if the field is not available.
198    ///
199    /// Introduced in kernel v5.16.
200    pub fn verified_instruction_count(&self) -> Option<u32> {
201        (self.0.verified_insns > 0).then_some(self.0.verified_insns)
202    }
203
204    /// How much memory in bytes has been allocated and locked for the program.
205    pub fn memory_locked(&self) -> Result<u32, ProgramError> {
206        get_fdinfo(self.fd()?.as_fd(), "memlock")
207    }
208
209    /// Returns a file descriptor referencing the program.
210    ///
211    /// The returned file descriptor can be closed at any time and doing so does
212    /// not influence the life cycle of the program.
213    ///
214    /// Uses kernel v4.13 features.
215    pub fn fd(&self) -> Result<ProgramFd, ProgramError> {
216        let Self(info) = self;
217        let fd = bpf_prog_get_fd_by_id(info.id)?;
218        Ok(ProgramFd(fd))
219    }
220
221    /// Loads a program from a pinned path in bpffs.
222    ///
223    /// Uses kernel v4.4 and v4.13 features.
224    pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Self, ProgramError> {
225        use std::os::unix::ffi::OsStrExt as _;
226
227        // TODO: avoid this unwrap by adding a new error variant.
228        let path_string = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();
229        let fd = bpf_get_object(&path_string).map_err(|io_error| SyscallError {
230            call: "BPF_OBJ_GET",
231            io_error,
232        })?;
233
234        Self::new_from_fd(fd.as_fd())
235    }
236}
237
238/// Returns information about a loaded program with the [`ProgramInfo`] structure.
239///
240/// This information is populated at load time by the kernel and can be used
241/// to correlate a given [`crate::programs::Program`] to it's corresponding [`ProgramInfo`]
242/// metadata.
243macro_rules! impl_info {
244    ($($struct_name:ident),+ $(,)?) => {
245        $(
246            impl $struct_name {
247                /// Returns metadata information of this program.
248                ///
249                /// Uses kernel v4.13 features.
250                pub fn info(&self) -> Result<ProgramInfo, ProgramError> {
251                    let ProgramFd(fd) = self.fd()?;
252                    ProgramInfo::new_from_fd(fd.as_fd())
253                }
254            }
255        )+
256    }
257}
258
259pub(crate) use impl_info;
260
261/// Returns an iterator of [`ProgramInfo`] over all eBPF programs loaded on the host.
262///
263/// Unlike [`Ebpf::programs`](crate::Ebpf::programs), this includes **all** programs on the host
264/// system, not just those tied to a specific [`crate::Ebpf`] instance.
265///
266/// Uses kernel v4.13 features.
267///
268/// # Example
269/// ```
270/// # use aya::programs::loaded_programs;
271/// #
272/// for p in loaded_programs() {
273///     match p {
274///         Ok(program) => println!("{}", String::from_utf8_lossy(program.name())),
275///         Err(e) => println!("error iterating programs: {:?}", e),
276///     }
277/// }
278/// ```
279///
280/// # Errors
281///
282/// Returns [`ProgramError::SyscallError`] if any of the syscalls required to either get
283/// next program id, get the program fd, or the [`ProgramInfo`] fail.
284///
285/// In cases where iteration can't be performed, for example the caller does not have the necessary
286/// privileges, a single item will be yielded containing the error that occurred.
287pub fn loaded_programs() -> impl Iterator<Item = Result<ProgramInfo, ProgramError>> {
288    iter_prog_ids()
289        .map(|id| {
290            let id = id?;
291            bpf_prog_get_fd_by_id(id)
292        })
293        .map(|fd| {
294            let fd = fd?;
295            bpf_prog_get_info_by_fd(fd.as_fd(), &mut [])
296        })
297        .map(|result| result.map(ProgramInfo).map_err(Into::into))
298}
299
300/// The type of LSM program.
301#[derive(Clone, Copy, Debug, PartialEq, Eq)]
302pub enum LsmAttachType {
303    /// A MAC (Mandatory Access Control) LSM program.
304    Mac,
305    /// A cGroup LSM program.
306    Cgroup,
307}
308
309/// The type of eBPF program.
310#[non_exhaustive]
311#[doc(alias = "bpf_prog_type")]
312#[derive(Clone, Copy, Debug, PartialEq)]
313pub enum ProgramType {
314    /// An unspecified program type.
315    #[doc(alias = "BPF_PROG_TYPE_UNSPEC")]
316    Unspecified,
317    /// A Socket Filter program type. See [`SocketFilter`](super::socket_filter::SocketFilter)
318    /// for the program implementation.
319    ///
320    /// Introduced in kernel v3.19.
321    #[doc(alias = "BPF_PROG_TYPE_SOCKET_FILTER")]
322    SocketFilter,
323    /// A Kernel Probe program type. See [`KProbe`](super::kprobe::KProbe) and
324    /// [`UProbe`](super::uprobe::UProbe) for the program implementations.
325    ///
326    /// Introduced in kernel v4.1.
327    #[doc(alias = "BPF_PROG_TYPE_KPROBE")]
328    KProbe,
329    /// A Traffic Control (TC) Classifier program type. See
330    /// [`SchedClassifier`](super::tc::SchedClassifier) for the program implementation.
331    ///
332    /// Introduced in kernel v4.1.
333    #[doc(alias = "BPF_PROG_TYPE_SCHED_CLS")]
334    SchedClassifier,
335    /// A Traffic Control (TC) Action program type.
336    ///
337    /// Introduced in kernel v4.1.
338    #[doc(alias = "BPF_PROG_TYPE_SCHED_ACT")]
339    SchedAction,
340    /// A Tracepoint program type. See [`TracePoint`](super::trace_point::TracePoint) for the
341    /// program implementation.
342    ///
343    /// Introduced in kernel v4.7.
344    #[doc(alias = "BPF_PROG_TYPE_TRACEPOINT")]
345    TracePoint,
346    /// An Express Data Path (XDP) program type. See [`Xdp`](super::xdp::Xdp) for the program
347    /// implementation.
348    ///
349    /// Introduced in kernel v4.8.
350    #[doc(alias = "BPF_PROG_TYPE_XDP")]
351    Xdp,
352    /// A Perf Event program type. See [`PerfEvent`](super::perf_event::PerfEvent) for the program
353    /// implementation.
354    ///
355    /// Introduced in kernel v4.9.
356    #[doc(alias = "BPF_PROG_TYPE_PERF_EVENT")]
357    PerfEvent,
358    /// A cGroup Socket Buffer program type. See [`CgroupSkb`](super::cgroup_skb::CgroupSkb) for
359    /// the program implementation.
360    ///
361    /// Introduced in kernel v4.10.
362    #[doc(alias = "BPF_PROG_TYPE_CGROUP_SKB")]
363    CgroupSkb,
364    /// A cGroup Socket program type. See [`CgroupSock`](super::cgroup_sock::CgroupSock) for the
365    /// program implementation.
366    ///
367    /// Introduced in kernel v4.10.
368    #[doc(alias = "BPF_PROG_TYPE_CGROUP_SOCK")]
369    CgroupSock,
370    /// A Lightweight Tunnel (LWT) Input program type.
371    ///
372    /// Introduced in kernel v4.10.
373    #[doc(alias = "BPF_PROG_TYPE_LWT_IN")]
374    LwtInput,
375    /// A Lightweight Tunnel (LWT) Output program type.
376    ///
377    /// Introduced in kernel v4.10.
378    #[doc(alias = "BPF_PROG_TYPE_LWT_OUT")]
379    LwtOutput,
380    /// A Lightweight Tunnel (LWT) Transmit program type.
381    ///
382    /// Introduced in kernel v4.10.
383    #[doc(alias = "BPF_PROG_TYPE_LWT_XMIT")]
384    LwtXmit,
385    /// A Socket Operation program type. See [`SockOps`](super::sock_ops::SockOps) for the program
386    /// implementation.
387    ///
388    /// Introduced in kernel v4.13.
389    #[doc(alias = "BPF_PROG_TYPE_SOCK_OPS")]
390    SockOps,
391    /// A Socket-to-Socket Buffer program type. See [`SkSkb`](super::sk_skb::SkSkb) for the program
392    /// implementation.
393    ///
394    /// Introduced in kernel v4.14.
395    #[doc(alias = "BPF_PROG_TYPE_SK_SKB")]
396    SkSkb,
397    /// A cGroup Device program type. See [`CgroupDevice`](super::cgroup_device::CgroupDevice)
398    /// for the program implementation.
399    ///
400    /// Introduced in kernel v4.15.
401    #[doc(alias = "BPF_PROG_TYPE_CGROUP_DEVICE")]
402    CgroupDevice,
403    /// A Socket Message program type. See [`SkMsg`](super::sk_msg::SkMsg) for the program
404    /// implementation.
405    ///
406    /// Introduced in kernel v4.17.
407    #[doc(alias = "BPF_PROG_TYPE_SK_MSG")]
408    SkMsg,
409    /// A Raw Tracepoint program type. See [`RawTracePoint`](super::raw_trace_point::RawTracePoint)
410    /// for the program implementation.
411    ///
412    /// Introduced in kernel v4.17.
413    #[doc(alias = "BPF_PROG_TYPE_RAW_TRACEPOINT")]
414    RawTracePoint,
415    /// A cGroup Socket Address program type. See
416    /// [`CgroupSockAddr`](super::cgroup_sock_addr::CgroupSockAddr) for the program implementation.
417    ///
418    /// Introduced in kernel v4.17.
419    #[doc(alias = "BPF_PROG_TYPE_CGROUP_SOCK_ADDR")]
420    CgroupSockAddr,
421    /// A Lightweight Tunnel (LWT) Seg6local program type.
422    ///
423    /// Introduced in kernel v4.18.
424    #[doc(alias = "BPF_PROG_TYPE_LWT_SEG6LOCAL")]
425    LwtSeg6local,
426    /// A Linux Infrared Remote Control (LIRC) Mode2 program type. See
427    /// [`LircMode2`](super::lirc_mode2::LircMode2) for the program implementation.
428    ///
429    /// Introduced in kernel v4.18.
430    #[doc(alias = "BPF_PROG_TYPE_LIRC_MODE2")]
431    LircMode2,
432    /// A Socket Reuseport program type.
433    ///
434    /// Introduced in kernel v4.19.
435    #[doc(alias = "BPF_PROG_TYPE_SK_REUSEPORT")]
436    SkReuseport,
437    /// A Flow Dissector program type.
438    ///
439    /// Introduced in kernel v4.20.
440    #[doc(alias = "BPF_PROG_TYPE_FLOW_DISSECTOR")]
441    FlowDissector,
442    /// A cGroup Sysctl program type. See [`CgroupSysctl`](super::cgroup_sysctl::CgroupSysctl) for
443    /// the program implementation.
444    ///
445    /// Introduced in kernel v5.2.
446    #[doc(alias = "BPF_PROG_TYPE_CGROUP_SYSCTL")]
447    CgroupSysctl,
448    /// A Writable Raw Tracepoint program type.
449    ///
450    /// Introduced in kernel v5.2.
451    #[doc(alias = "BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE")]
452    RawTracePointWritable,
453    /// A cGroup Socket Option program type. See [`CgroupSockopt`](super::cgroup_sockopt::CgroupSockopt)
454    /// for the program implementation.
455    ///
456    /// Introduced in kernel v5.3.
457    #[doc(alias = "BPF_PROG_TYPE_CGROUP_SOCKOPT")]
458    CgroupSockopt,
459    /// A Tracing program type. See [`FEntry`](super::fentry::FEntry), [`FExit`](super::fexit::FExit),
460    /// and [`BtfTracePoint`](super::tp_btf::BtfTracePoint) for the program implementations.
461    ///
462    /// Introduced in kernel v5.5.
463    #[doc(alias = "BPF_PROG_TYPE_TRACING")]
464    Tracing,
465    /// A Struct Ops program type.
466    ///
467    /// Introduced in kernel v5.6.
468    #[doc(alias = "BPF_PROG_TYPE_STRUCT_OPS")]
469    StructOps,
470    /// A Extension program type. See [`Extension`](super::extension::Extension) for the program
471    /// implementation.
472    ///
473    /// Introduced in kernel v5.6.
474    #[doc(alias = "BPF_PROG_TYPE_EXT")]
475    Extension,
476    /// A Linux Security Module (LSM) program type. See [`Lsm`](super::lsm::Lsm) for the program
477    /// implementation.
478    ///
479    /// Introduced in kernel v5.7.
480    #[doc(alias = "BPF_PROG_TYPE_LSM")]
481    Lsm(LsmAttachType),
482    /// A Socket Lookup program type. See [`SkLookup`](super::sk_lookup::SkLookup) for the program
483    /// implementation.
484    ///
485    /// Introduced in kernel v5.9.
486    #[doc(alias = "BPF_PROG_TYPE_SK_LOOKUP")]
487    SkLookup,
488    /// A Syscall program type.
489    ///
490    /// Introduced in kernel v5.14.
491    #[doc(alias = "BPF_PROG_TYPE_SYSCALL")]
492    Syscall,
493    /// A Netfilter program type.
494    ///
495    /// Introduced in kernel v6.4.
496    #[doc(alias = "BPF_PROG_TYPE_NETFILTER")]
497    Netfilter,
498}
499
500impl From<ProgramType> for bpf_prog_type {
501    fn from(value: ProgramType) -> Self {
502        match value {
503            ProgramType::Unspecified => Self::BPF_PROG_TYPE_UNSPEC,
504            ProgramType::SocketFilter => Self::BPF_PROG_TYPE_SOCKET_FILTER,
505            ProgramType::KProbe => Self::BPF_PROG_TYPE_KPROBE,
506            ProgramType::SchedClassifier => Self::BPF_PROG_TYPE_SCHED_CLS,
507            ProgramType::SchedAction => Self::BPF_PROG_TYPE_SCHED_ACT,
508            ProgramType::TracePoint => Self::BPF_PROG_TYPE_TRACEPOINT,
509            ProgramType::Xdp => Self::BPF_PROG_TYPE_XDP,
510            ProgramType::PerfEvent => Self::BPF_PROG_TYPE_PERF_EVENT,
511            ProgramType::CgroupSkb => Self::BPF_PROG_TYPE_CGROUP_SKB,
512            ProgramType::CgroupSock => Self::BPF_PROG_TYPE_CGROUP_SOCK,
513            ProgramType::LwtInput => Self::BPF_PROG_TYPE_LWT_IN,
514            ProgramType::LwtOutput => Self::BPF_PROG_TYPE_LWT_OUT,
515            ProgramType::LwtXmit => Self::BPF_PROG_TYPE_LWT_XMIT,
516            ProgramType::SockOps => Self::BPF_PROG_TYPE_SOCK_OPS,
517            ProgramType::SkSkb => Self::BPF_PROG_TYPE_SK_SKB,
518            ProgramType::CgroupDevice => Self::BPF_PROG_TYPE_CGROUP_DEVICE,
519            ProgramType::SkMsg => Self::BPF_PROG_TYPE_SK_MSG,
520            ProgramType::RawTracePoint => Self::BPF_PROG_TYPE_RAW_TRACEPOINT,
521            ProgramType::CgroupSockAddr => Self::BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
522            ProgramType::LwtSeg6local => Self::BPF_PROG_TYPE_LWT_SEG6LOCAL,
523            ProgramType::LircMode2 => Self::BPF_PROG_TYPE_LIRC_MODE2,
524            ProgramType::SkReuseport => Self::BPF_PROG_TYPE_SK_REUSEPORT,
525            ProgramType::FlowDissector => Self::BPF_PROG_TYPE_FLOW_DISSECTOR,
526            ProgramType::CgroupSysctl => Self::BPF_PROG_TYPE_CGROUP_SYSCTL,
527            ProgramType::RawTracePointWritable => Self::BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
528            ProgramType::CgroupSockopt => Self::BPF_PROG_TYPE_CGROUP_SOCKOPT,
529            ProgramType::Tracing => Self::BPF_PROG_TYPE_TRACING,
530            ProgramType::StructOps => Self::BPF_PROG_TYPE_STRUCT_OPS,
531            ProgramType::Extension => Self::BPF_PROG_TYPE_EXT,
532            ProgramType::Lsm(_) => Self::BPF_PROG_TYPE_LSM,
533            ProgramType::SkLookup => Self::BPF_PROG_TYPE_SK_LOOKUP,
534            ProgramType::Syscall => Self::BPF_PROG_TYPE_SYSCALL,
535            ProgramType::Netfilter => Self::BPF_PROG_TYPE_NETFILTER,
536        }
537    }
538}