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}