1 // `rustdoc` is buggy, claiming that we have some links to private items 2 // when they are actually public. 3 #![allow(rustdoc::private_intra_doc_links)] 4 5 use std::ffi::c_void; 6 use std::ffi::CStr; 7 use std::ffi::OsStr; 8 use std::marker::PhantomData; 9 use std::mem; 10 use std::mem::size_of; 11 use std::mem::size_of_val; 12 use std::mem::transmute; 13 use std::ops::Deref; 14 use std::os::unix::ffi::OsStrExt as _; 15 use std::os::unix::io::AsFd; 16 use std::os::unix::io::AsRawFd; 17 use std::os::unix::io::BorrowedFd; 18 use std::os::unix::io::FromRawFd; 19 use std::os::unix::io::OwnedFd; 20 use std::path::Path; 21 use std::ptr; 22 use std::ptr::NonNull; 23 use std::slice; 24 25 use libbpf_sys::bpf_func_id; 26 27 use crate::netfilter; 28 use crate::util; 29 use crate::util::validate_bpf_ret; 30 use crate::util::BpfObjectType; 31 use crate::AsRawLibbpf; 32 use crate::Error; 33 use crate::ErrorExt as _; 34 use crate::Link; 35 use crate::Mut; 36 use crate::Result; 37 38 /// Options to optionally be provided when attaching to a uprobe. 39 #[derive(Clone, Debug, Default)] 40 pub struct UprobeOpts { 41 /// Offset of kernel reference counted USDT semaphore. 42 pub ref_ctr_offset: usize, 43 /// Custom user-provided value accessible through `bpf_get_attach_cookie`. 44 pub cookie: u64, 45 /// uprobe is return probe, invoked at function return time. 46 pub retprobe: bool, 47 /// Function name to attach to. 48 /// 49 /// Could be an unqualified ("abc") or library-qualified "abc@LIBXYZ" name. 50 /// To specify function entry, `func_name` should be set while `func_offset` 51 /// argument to should be 0. To trace an offset within a function, specify 52 /// `func_name` and use `func_offset` argument to specify offset within the 53 /// function. Shared library functions must specify the shared library 54 /// binary_path. 55 pub func_name: String, 56 #[doc(hidden)] 57 pub _non_exhaustive: (), 58 } 59 60 /// Options to optionally be provided when attaching to a USDT. 61 #[derive(Clone, Debug, Default)] 62 pub struct UsdtOpts { 63 /// Custom user-provided value accessible through `bpf_usdt_cookie`. 64 pub cookie: u64, 65 #[doc(hidden)] 66 pub _non_exhaustive: (), 67 } 68 69 impl From<UsdtOpts> for libbpf_sys::bpf_usdt_opts { from(opts: UsdtOpts) -> Self70 fn from(opts: UsdtOpts) -> Self { 71 let UsdtOpts { 72 cookie, 73 _non_exhaustive, 74 } = opts; 75 #[allow(clippy::needless_update)] 76 libbpf_sys::bpf_usdt_opts { 77 sz: size_of::<Self>() as _, 78 usdt_cookie: cookie, 79 // bpf_usdt_opts might have padding fields on some platform 80 ..Default::default() 81 } 82 } 83 } 84 85 /// Options to optionally be provided when attaching to a tracepoint. 86 #[derive(Clone, Debug, Default)] 87 pub struct TracepointOpts { 88 /// Custom user-provided value accessible through `bpf_get_attach_cookie`. 89 pub cookie: u64, 90 #[doc(hidden)] 91 pub _non_exhaustive: (), 92 } 93 94 impl From<TracepointOpts> for libbpf_sys::bpf_tracepoint_opts { from(opts: TracepointOpts) -> Self95 fn from(opts: TracepointOpts) -> Self { 96 let TracepointOpts { 97 cookie, 98 _non_exhaustive, 99 } = opts; 100 101 #[allow(clippy::needless_update)] 102 libbpf_sys::bpf_tracepoint_opts { 103 sz: size_of::<Self>() as _, 104 bpf_cookie: cookie, 105 // bpf_tracepoint_opts might have padding fields on some platform 106 ..Default::default() 107 } 108 } 109 } 110 111 112 /// An immutable parsed but not yet loaded BPF program. 113 pub type OpenProgram<'obj> = OpenProgramImpl<'obj>; 114 /// A mutable parsed but not yet loaded BPF program. 115 pub type OpenProgramMut<'obj> = OpenProgramImpl<'obj, Mut>; 116 117 /// Represents a parsed but not yet loaded BPF program. 118 /// 119 /// This object exposes operations that need to happen before the program is loaded. 120 #[derive(Debug)] 121 #[repr(transparent)] 122 pub struct OpenProgramImpl<'obj, T = ()> { 123 ptr: NonNull<libbpf_sys::bpf_program>, 124 _phantom: PhantomData<&'obj T>, 125 } 126 127 impl<'obj> OpenProgram<'obj> { 128 /// Create a new [`OpenProgram`] from a ptr to a `libbpf_sys::bpf_program`. new(prog: &'obj libbpf_sys::bpf_program) -> Self129 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self { 130 // SAFETY: We inferred the address from a reference, which is always 131 // valid. 132 Self { 133 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) }, 134 _phantom: PhantomData, 135 } 136 } 137 138 /// The `ProgramType` of this `OpenProgram`. prog_type(&self) -> ProgramType139 pub fn prog_type(&self) -> ProgramType { 140 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) }) 141 } 142 143 /// Retrieve the name of this `OpenProgram`. name(&self) -> &OsStr144 pub fn name(&self) -> &OsStr { 145 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) }; 146 let name_c_str = unsafe { CStr::from_ptr(name_ptr) }; 147 // SAFETY: `bpf_program__name` always returns a non-NULL pointer. 148 OsStr::from_bytes(name_c_str.to_bytes()) 149 } 150 151 /// Retrieve the name of the section this `OpenProgram` belongs to. section(&self) -> &OsStr152 pub fn section(&self) -> &OsStr { 153 // SAFETY: The program is always valid. 154 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) }; 155 // SAFETY: `bpf_program__section_name` will always return a non-NULL 156 // pointer. 157 let section_c_str = unsafe { CStr::from_ptr(p) }; 158 let section = OsStr::from_bytes(section_c_str.to_bytes()); 159 section 160 } 161 162 /// Returns the number of instructions that form the program. 163 /// 164 /// Note: Keep in mind, libbpf can modify the program's instructions 165 /// and consequently its instruction count, as it processes the BPF object file. 166 /// So [`OpenProgram::insn_cnt`] and [`Program::insn_cnt`] may return different values. insn_cnt(&self) -> usize167 pub fn insn_cnt(&self) -> usize { 168 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize } 169 } 170 171 /// Gives read-only access to BPF program's underlying BPF instructions. 172 /// 173 /// Keep in mind, libbpf can modify and append/delete BPF program's 174 /// instructions as it processes BPF object file and prepares everything for 175 /// uploading into the kernel. So [`OpenProgram::insns`] and [`Program::insns`] may return 176 /// different sets of instructions. As an example, during BPF object load phase BPF program 177 /// instructions will be CO-RE-relocated, BPF subprograms instructions will be appended, ldimm64 178 /// instructions will have FDs embedded, etc. So instructions returned before load and after it 179 /// might be quite different. insns(&self) -> &[libbpf_sys::bpf_insn]180 pub fn insns(&self) -> &[libbpf_sys::bpf_insn] { 181 let count = self.insn_cnt(); 182 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) }; 183 unsafe { slice::from_raw_parts(ptr, count) } 184 } 185 } 186 187 impl<'obj> OpenProgramMut<'obj> { 188 /// Create a new [`OpenProgram`] from a ptr to a `libbpf_sys::bpf_program`. new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self189 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self { 190 Self { 191 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) }, 192 _phantom: PhantomData, 193 } 194 } 195 196 /// Set the program type. set_prog_type(&mut self, prog_type: ProgramType)197 pub fn set_prog_type(&mut self, prog_type: ProgramType) { 198 let rc = unsafe { libbpf_sys::bpf_program__set_type(self.ptr.as_ptr(), prog_type as u32) }; 199 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}"); 200 } 201 202 /// Set the attachment type of the program. set_attach_type(&mut self, attach_type: ProgramAttachType)203 pub fn set_attach_type(&mut self, attach_type: ProgramAttachType) { 204 let rc = unsafe { 205 libbpf_sys::bpf_program__set_expected_attach_type(self.ptr.as_ptr(), attach_type as u32) 206 }; 207 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}"); 208 } 209 210 /// Bind the program to a particular network device. 211 /// 212 /// Currently only used for hardware offload and certain XDP features such like HW metadata. set_ifindex(&mut self, idx: u32)213 pub fn set_ifindex(&mut self, idx: u32) { 214 unsafe { libbpf_sys::bpf_program__set_ifindex(self.ptr.as_ptr(), idx) } 215 } 216 217 /// Set the log level for the bpf program. 218 /// 219 /// The log level is interpreted by bpf kernel code and interpretation may 220 /// change with newer kernel versions. Refer to the kernel source code for 221 /// details. 222 /// 223 /// In general, a value of `0` disables logging while values `> 0` enables 224 /// it. set_log_level(&mut self, log_level: u32)225 pub fn set_log_level(&mut self, log_level: u32) { 226 let rc = unsafe { libbpf_sys::bpf_program__set_log_level(self.ptr.as_ptr(), log_level) }; 227 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}"); 228 } 229 230 /// Set whether a bpf program should be automatically loaded by default 231 /// when the bpf object is loaded. set_autoload(&mut self, autoload: bool)232 pub fn set_autoload(&mut self, autoload: bool) { 233 let rc = unsafe { libbpf_sys::bpf_program__set_autoload(self.ptr.as_ptr(), autoload) }; 234 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}"); 235 } 236 237 #[allow(missing_docs)] set_attach_target( &mut self, attach_prog_fd: i32, attach_func_name: Option<String>, ) -> Result<()>238 pub fn set_attach_target( 239 &mut self, 240 attach_prog_fd: i32, 241 attach_func_name: Option<String>, 242 ) -> Result<()> { 243 let ret = if let Some(name) = attach_func_name { 244 // NB: we must hold onto a CString otherwise our pointer dangles 245 let name_c = util::str_to_cstring(&name)?; 246 unsafe { 247 libbpf_sys::bpf_program__set_attach_target( 248 self.ptr.as_ptr(), 249 attach_prog_fd, 250 name_c.as_ptr(), 251 ) 252 } 253 } else { 254 unsafe { 255 libbpf_sys::bpf_program__set_attach_target( 256 self.ptr.as_ptr(), 257 attach_prog_fd, 258 ptr::null(), 259 ) 260 } 261 }; 262 util::parse_ret(ret) 263 } 264 265 /// Set flags on the program. set_flags(&mut self, flags: u32)266 pub fn set_flags(&mut self, flags: u32) { 267 let rc = unsafe { libbpf_sys::bpf_program__set_flags(self.ptr.as_ptr(), flags) }; 268 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}"); 269 } 270 } 271 272 impl<'obj> Deref for OpenProgramMut<'obj> { 273 type Target = OpenProgram<'obj>; 274 deref(&self) -> &Self::Target275 fn deref(&self) -> &Self::Target { 276 // SAFETY: `OpenProgramImpl` is `repr(transparent)` and so 277 // in-memory representation of both types is the same. 278 unsafe { transmute::<&OpenProgramMut<'obj>, &OpenProgram<'obj>>(self) } 279 } 280 } 281 282 impl<T> AsRawLibbpf for OpenProgramImpl<'_, T> { 283 type LibbpfType = libbpf_sys::bpf_program; 284 285 /// Retrieve the underlying [`libbpf_sys::bpf_program`]. as_libbpf_object(&self) -> NonNull<Self::LibbpfType>286 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> { 287 self.ptr 288 } 289 } 290 291 /// Type of a [`Program`]. Maps to `enum bpf_prog_type` in kernel uapi. 292 #[non_exhaustive] 293 #[repr(u32)] 294 #[derive(Copy, Clone, Debug)] 295 // TODO: Document variants. 296 #[allow(missing_docs)] 297 pub enum ProgramType { 298 Unspec = 0, 299 SocketFilter = libbpf_sys::BPF_PROG_TYPE_SOCKET_FILTER, 300 Kprobe = libbpf_sys::BPF_PROG_TYPE_KPROBE, 301 SchedCls = libbpf_sys::BPF_PROG_TYPE_SCHED_CLS, 302 SchedAct = libbpf_sys::BPF_PROG_TYPE_SCHED_ACT, 303 Tracepoint = libbpf_sys::BPF_PROG_TYPE_TRACEPOINT, 304 Xdp = libbpf_sys::BPF_PROG_TYPE_XDP, 305 PerfEvent = libbpf_sys::BPF_PROG_TYPE_PERF_EVENT, 306 CgroupSkb = libbpf_sys::BPF_PROG_TYPE_CGROUP_SKB, 307 CgroupSock = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCK, 308 LwtIn = libbpf_sys::BPF_PROG_TYPE_LWT_IN, 309 LwtOut = libbpf_sys::BPF_PROG_TYPE_LWT_OUT, 310 LwtXmit = libbpf_sys::BPF_PROG_TYPE_LWT_XMIT, 311 SockOps = libbpf_sys::BPF_PROG_TYPE_SOCK_OPS, 312 SkSkb = libbpf_sys::BPF_PROG_TYPE_SK_SKB, 313 CgroupDevice = libbpf_sys::BPF_PROG_TYPE_CGROUP_DEVICE, 314 SkMsg = libbpf_sys::BPF_PROG_TYPE_SK_MSG, 315 RawTracepoint = libbpf_sys::BPF_PROG_TYPE_RAW_TRACEPOINT, 316 CgroupSockAddr = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCK_ADDR, 317 LwtSeg6local = libbpf_sys::BPF_PROG_TYPE_LWT_SEG6LOCAL, 318 LircMode2 = libbpf_sys::BPF_PROG_TYPE_LIRC_MODE2, 319 SkReuseport = libbpf_sys::BPF_PROG_TYPE_SK_REUSEPORT, 320 FlowDissector = libbpf_sys::BPF_PROG_TYPE_FLOW_DISSECTOR, 321 CgroupSysctl = libbpf_sys::BPF_PROG_TYPE_CGROUP_SYSCTL, 322 RawTracepointWritable = libbpf_sys::BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, 323 CgroupSockopt = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCKOPT, 324 Tracing = libbpf_sys::BPF_PROG_TYPE_TRACING, 325 StructOps = libbpf_sys::BPF_PROG_TYPE_STRUCT_OPS, 326 Ext = libbpf_sys::BPF_PROG_TYPE_EXT, 327 Lsm = libbpf_sys::BPF_PROG_TYPE_LSM, 328 SkLookup = libbpf_sys::BPF_PROG_TYPE_SK_LOOKUP, 329 Syscall = libbpf_sys::BPF_PROG_TYPE_SYSCALL, 330 /// See [`MapType::Unknown`][crate::MapType::Unknown] 331 Unknown = u32::MAX, 332 } 333 334 impl ProgramType { 335 /// Detects if host kernel supports this BPF program type 336 /// 337 /// Make sure the process has required set of CAP_* permissions (or runs as 338 /// root) when performing feature checking. is_supported(&self) -> Result<bool>339 pub fn is_supported(&self) -> Result<bool> { 340 let ret = unsafe { libbpf_sys::libbpf_probe_bpf_prog_type(*self as u32, ptr::null()) }; 341 match ret { 342 0 => Ok(false), 343 1 => Ok(true), 344 _ => Err(Error::from_raw_os_error(-ret)), 345 } 346 } 347 348 /// Detects if host kernel supports the use of a given BPF helper from this BPF program type. 349 /// * `helper_id` - BPF helper ID (enum bpf_func_id) to check support for 350 /// 351 /// Make sure the process has required set of CAP_* permissions (or runs as 352 /// root) when performing feature checking. is_helper_supported(&self, helper_id: bpf_func_id) -> Result<bool>353 pub fn is_helper_supported(&self, helper_id: bpf_func_id) -> Result<bool> { 354 let ret = 355 unsafe { libbpf_sys::libbpf_probe_bpf_helper(*self as u32, helper_id, ptr::null()) }; 356 match ret { 357 0 => Ok(false), 358 1 => Ok(true), 359 _ => Err(Error::from_raw_os_error(-ret)), 360 } 361 } 362 } 363 364 impl From<u32> for ProgramType { from(value: u32) -> Self365 fn from(value: u32) -> Self { 366 use ProgramType::*; 367 368 match value { 369 x if x == Unspec as u32 => Unspec, 370 x if x == SocketFilter as u32 => SocketFilter, 371 x if x == Kprobe as u32 => Kprobe, 372 x if x == SchedCls as u32 => SchedCls, 373 x if x == SchedAct as u32 => SchedAct, 374 x if x == Tracepoint as u32 => Tracepoint, 375 x if x == Xdp as u32 => Xdp, 376 x if x == PerfEvent as u32 => PerfEvent, 377 x if x == CgroupSkb as u32 => CgroupSkb, 378 x if x == CgroupSock as u32 => CgroupSock, 379 x if x == LwtIn as u32 => LwtIn, 380 x if x == LwtOut as u32 => LwtOut, 381 x if x == LwtXmit as u32 => LwtXmit, 382 x if x == SockOps as u32 => SockOps, 383 x if x == SkSkb as u32 => SkSkb, 384 x if x == CgroupDevice as u32 => CgroupDevice, 385 x if x == SkMsg as u32 => SkMsg, 386 x if x == RawTracepoint as u32 => RawTracepoint, 387 x if x == CgroupSockAddr as u32 => CgroupSockAddr, 388 x if x == LwtSeg6local as u32 => LwtSeg6local, 389 x if x == LircMode2 as u32 => LircMode2, 390 x if x == SkReuseport as u32 => SkReuseport, 391 x if x == FlowDissector as u32 => FlowDissector, 392 x if x == CgroupSysctl as u32 => CgroupSysctl, 393 x if x == RawTracepointWritable as u32 => RawTracepointWritable, 394 x if x == CgroupSockopt as u32 => CgroupSockopt, 395 x if x == Tracing as u32 => Tracing, 396 x if x == StructOps as u32 => StructOps, 397 x if x == Ext as u32 => Ext, 398 x if x == Lsm as u32 => Lsm, 399 x if x == SkLookup as u32 => SkLookup, 400 x if x == Syscall as u32 => Syscall, 401 _ => Unknown, 402 } 403 } 404 } 405 406 /// Attach type of a [`Program`]. Maps to `enum bpf_attach_type` in kernel uapi. 407 #[non_exhaustive] 408 #[repr(u32)] 409 #[derive(Clone, Debug)] 410 // TODO: Document variants. 411 #[allow(missing_docs)] 412 pub enum ProgramAttachType { 413 CgroupInetIngress = libbpf_sys::BPF_CGROUP_INET_INGRESS, 414 CgroupInetEgress = libbpf_sys::BPF_CGROUP_INET_EGRESS, 415 CgroupInetSockCreate = libbpf_sys::BPF_CGROUP_INET_SOCK_CREATE, 416 CgroupSockOps = libbpf_sys::BPF_CGROUP_SOCK_OPS, 417 SkSkbStreamParser = libbpf_sys::BPF_SK_SKB_STREAM_PARSER, 418 SkSkbStreamVerdict = libbpf_sys::BPF_SK_SKB_STREAM_VERDICT, 419 CgroupDevice = libbpf_sys::BPF_CGROUP_DEVICE, 420 SkMsgVerdict = libbpf_sys::BPF_SK_MSG_VERDICT, 421 CgroupInet4Bind = libbpf_sys::BPF_CGROUP_INET4_BIND, 422 CgroupInet6Bind = libbpf_sys::BPF_CGROUP_INET6_BIND, 423 CgroupInet4Connect = libbpf_sys::BPF_CGROUP_INET4_CONNECT, 424 CgroupInet6Connect = libbpf_sys::BPF_CGROUP_INET6_CONNECT, 425 CgroupInet4PostBind = libbpf_sys::BPF_CGROUP_INET4_POST_BIND, 426 CgroupInet6PostBind = libbpf_sys::BPF_CGROUP_INET6_POST_BIND, 427 CgroupUdp4Sendmsg = libbpf_sys::BPF_CGROUP_UDP4_SENDMSG, 428 CgroupUdp6Sendmsg = libbpf_sys::BPF_CGROUP_UDP6_SENDMSG, 429 LircMode2 = libbpf_sys::BPF_LIRC_MODE2, 430 FlowDissector = libbpf_sys::BPF_FLOW_DISSECTOR, 431 CgroupSysctl = libbpf_sys::BPF_CGROUP_SYSCTL, 432 CgroupUdp4Recvmsg = libbpf_sys::BPF_CGROUP_UDP4_RECVMSG, 433 CgroupUdp6Recvmsg = libbpf_sys::BPF_CGROUP_UDP6_RECVMSG, 434 CgroupGetsockopt = libbpf_sys::BPF_CGROUP_GETSOCKOPT, 435 CgroupSetsockopt = libbpf_sys::BPF_CGROUP_SETSOCKOPT, 436 TraceRawTp = libbpf_sys::BPF_TRACE_RAW_TP, 437 TraceFentry = libbpf_sys::BPF_TRACE_FENTRY, 438 TraceFexit = libbpf_sys::BPF_TRACE_FEXIT, 439 ModifyReturn = libbpf_sys::BPF_MODIFY_RETURN, 440 LsmMac = libbpf_sys::BPF_LSM_MAC, 441 TraceIter = libbpf_sys::BPF_TRACE_ITER, 442 CgroupInet4Getpeername = libbpf_sys::BPF_CGROUP_INET4_GETPEERNAME, 443 CgroupInet6Getpeername = libbpf_sys::BPF_CGROUP_INET6_GETPEERNAME, 444 CgroupInet4Getsockname = libbpf_sys::BPF_CGROUP_INET4_GETSOCKNAME, 445 CgroupInet6Getsockname = libbpf_sys::BPF_CGROUP_INET6_GETSOCKNAME, 446 XdpDevmap = libbpf_sys::BPF_XDP_DEVMAP, 447 CgroupInetSockRelease = libbpf_sys::BPF_CGROUP_INET_SOCK_RELEASE, 448 XdpCpumap = libbpf_sys::BPF_XDP_CPUMAP, 449 SkLookup = libbpf_sys::BPF_SK_LOOKUP, 450 Xdp = libbpf_sys::BPF_XDP, 451 SkSkbVerdict = libbpf_sys::BPF_SK_SKB_VERDICT, 452 SkReuseportSelect = libbpf_sys::BPF_SK_REUSEPORT_SELECT, 453 SkReuseportSelectOrMigrate = libbpf_sys::BPF_SK_REUSEPORT_SELECT_OR_MIGRATE, 454 PerfEvent = libbpf_sys::BPF_PERF_EVENT, 455 /// See [`MapType::Unknown`][crate::MapType::Unknown] 456 Unknown = u32::MAX, 457 } 458 459 impl From<u32> for ProgramAttachType { from(value: u32) -> Self460 fn from(value: u32) -> Self { 461 use ProgramAttachType::*; 462 463 match value { 464 x if x == CgroupInetIngress as u32 => CgroupInetIngress, 465 x if x == CgroupInetEgress as u32 => CgroupInetEgress, 466 x if x == CgroupInetSockCreate as u32 => CgroupInetSockCreate, 467 x if x == CgroupSockOps as u32 => CgroupSockOps, 468 x if x == SkSkbStreamParser as u32 => SkSkbStreamParser, 469 x if x == SkSkbStreamVerdict as u32 => SkSkbStreamVerdict, 470 x if x == CgroupDevice as u32 => CgroupDevice, 471 x if x == SkMsgVerdict as u32 => SkMsgVerdict, 472 x if x == CgroupInet4Bind as u32 => CgroupInet4Bind, 473 x if x == CgroupInet6Bind as u32 => CgroupInet6Bind, 474 x if x == CgroupInet4Connect as u32 => CgroupInet4Connect, 475 x if x == CgroupInet6Connect as u32 => CgroupInet6Connect, 476 x if x == CgroupInet4PostBind as u32 => CgroupInet4PostBind, 477 x if x == CgroupInet6PostBind as u32 => CgroupInet6PostBind, 478 x if x == CgroupUdp4Sendmsg as u32 => CgroupUdp4Sendmsg, 479 x if x == CgroupUdp6Sendmsg as u32 => CgroupUdp6Sendmsg, 480 x if x == LircMode2 as u32 => LircMode2, 481 x if x == FlowDissector as u32 => FlowDissector, 482 x if x == CgroupSysctl as u32 => CgroupSysctl, 483 x if x == CgroupUdp4Recvmsg as u32 => CgroupUdp4Recvmsg, 484 x if x == CgroupUdp6Recvmsg as u32 => CgroupUdp6Recvmsg, 485 x if x == CgroupGetsockopt as u32 => CgroupGetsockopt, 486 x if x == CgroupSetsockopt as u32 => CgroupSetsockopt, 487 x if x == TraceRawTp as u32 => TraceRawTp, 488 x if x == TraceFentry as u32 => TraceFentry, 489 x if x == TraceFexit as u32 => TraceFexit, 490 x if x == ModifyReturn as u32 => ModifyReturn, 491 x if x == LsmMac as u32 => LsmMac, 492 x if x == TraceIter as u32 => TraceIter, 493 x if x == CgroupInet4Getpeername as u32 => CgroupInet4Getpeername, 494 x if x == CgroupInet6Getpeername as u32 => CgroupInet6Getpeername, 495 x if x == CgroupInet4Getsockname as u32 => CgroupInet4Getsockname, 496 x if x == CgroupInet6Getsockname as u32 => CgroupInet6Getsockname, 497 x if x == XdpDevmap as u32 => XdpDevmap, 498 x if x == CgroupInetSockRelease as u32 => CgroupInetSockRelease, 499 x if x == XdpCpumap as u32 => XdpCpumap, 500 x if x == SkLookup as u32 => SkLookup, 501 x if x == Xdp as u32 => Xdp, 502 x if x == SkSkbVerdict as u32 => SkSkbVerdict, 503 x if x == SkReuseportSelect as u32 => SkReuseportSelect, 504 x if x == SkReuseportSelectOrMigrate as u32 => SkReuseportSelectOrMigrate, 505 x if x == PerfEvent as u32 => PerfEvent, 506 _ => Unknown, 507 } 508 } 509 } 510 511 /// The input a program accepts. 512 /// 513 /// This type is mostly used in conjunction with the [`Program::test_run`] 514 /// facility. 515 #[derive(Debug, Default)] 516 pub struct Input<'dat> { 517 /// The input context to provide. 518 /// 519 /// The input is mutable because the kernel may modify it. 520 pub context_in: Option<&'dat mut [u8]>, 521 /// The output context buffer provided to the program. 522 pub context_out: Option<&'dat mut [u8]>, 523 /// Additional data to provide to the program. 524 pub data_in: Option<&'dat [u8]>, 525 /// The output data buffer provided to the program. 526 pub data_out: Option<&'dat mut [u8]>, 527 /// The 'cpu' value passed to the kernel. 528 pub cpu: u32, 529 /// The 'flags' value passed to the kernel. 530 pub flags: u32, 531 /// The struct is non-exhaustive and open to extension. 532 #[doc(hidden)] 533 pub _non_exhaustive: (), 534 } 535 536 /// The output a program produces. 537 /// 538 /// This type is mostly used in conjunction with the [`Program::test_run`] 539 /// facility. 540 #[derive(Debug)] 541 pub struct Output<'dat> { 542 /// The value returned by the program. 543 pub return_value: u32, 544 /// The output context filled by the program/kernel. 545 pub context: Option<&'dat mut [u8]>, 546 /// Output data filled by the program. 547 pub data: Option<&'dat mut [u8]>, 548 /// The struct is non-exhaustive and open to extension. 549 #[doc(hidden)] 550 pub _non_exhaustive: (), 551 } 552 553 /// An immutable loaded BPF program. 554 pub type Program<'obj> = ProgramImpl<'obj>; 555 /// A mutable loaded BPF program. 556 pub type ProgramMut<'obj> = ProgramImpl<'obj, Mut>; 557 558 559 /// Represents a loaded [`Program`]. 560 /// 561 /// This struct is not safe to clone because the underlying libbpf resource cannot currently 562 /// be protected from data races. 563 /// 564 /// If you attempt to attach a `Program` with the wrong attach method, the `attach_*` 565 /// method will fail with the appropriate error. 566 #[derive(Debug)] 567 #[repr(transparent)] 568 pub struct ProgramImpl<'obj, T = ()> { 569 pub(crate) ptr: NonNull<libbpf_sys::bpf_program>, 570 _phantom: PhantomData<&'obj T>, 571 } 572 573 impl<'obj> Program<'obj> { 574 /// Create a [`Program`] from a [`libbpf_sys::bpf_program`] new(prog: &'obj libbpf_sys::bpf_program) -> Self575 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self { 576 // SAFETY: We inferred the address from a reference, which is always 577 // valid. 578 Self { 579 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) }, 580 _phantom: PhantomData, 581 } 582 } 583 584 /// Retrieve the name of this `Program`. name(&self) -> &OsStr585 pub fn name(&self) -> &OsStr { 586 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) }; 587 let name_c_str = unsafe { CStr::from_ptr(name_ptr) }; 588 // SAFETY: `bpf_program__name` always returns a non-NULL pointer. 589 OsStr::from_bytes(name_c_str.to_bytes()) 590 } 591 592 /// Retrieve the name of the section this `Program` belongs to. section(&self) -> &OsStr593 pub fn section(&self) -> &OsStr { 594 // SAFETY: The program is always valid. 595 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) }; 596 // SAFETY: `bpf_program__section_name` will always return a non-NULL 597 // pointer. 598 let section_c_str = unsafe { CStr::from_ptr(p) }; 599 let section = OsStr::from_bytes(section_c_str.to_bytes()); 600 section 601 } 602 603 /// Retrieve the type of the program. prog_type(&self) -> ProgramType604 pub fn prog_type(&self) -> ProgramType { 605 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) }) 606 } 607 608 #[deprecated = "renamed to Program::fd_from_id"] 609 #[allow(missing_docs)] 610 #[inline] get_fd_by_id(id: u32) -> Result<OwnedFd>611 pub fn get_fd_by_id(id: u32) -> Result<OwnedFd> { 612 Self::fd_from_id(id) 613 } 614 615 /// Returns program file descriptor given a program ID. fd_from_id(id: u32) -> Result<OwnedFd>616 pub fn fd_from_id(id: u32) -> Result<OwnedFd> { 617 let ret = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(id) }; 618 let fd = util::parse_ret_i32(ret)?; 619 // SAFETY 620 // A file descriptor coming from the bpf_prog_get_fd_by_id function is always suitable for 621 // ownership and can be cleaned up with close. 622 Ok(unsafe { OwnedFd::from_raw_fd(fd) }) 623 } 624 625 // TODO: Remove once 0.25 is cut. 626 #[deprecated = "renamed to Program::id_from_fd"] 627 #[allow(missing_docs)] 628 #[inline] get_id_by_fd(fd: BorrowedFd<'_>) -> Result<u32>629 pub fn get_id_by_fd(fd: BorrowedFd<'_>) -> Result<u32> { 630 Self::id_from_fd(fd) 631 } 632 633 /// Returns program ID given a file descriptor. id_from_fd(fd: BorrowedFd<'_>) -> Result<u32>634 pub fn id_from_fd(fd: BorrowedFd<'_>) -> Result<u32> { 635 let mut prog_info = libbpf_sys::bpf_prog_info::default(); 636 let prog_info_ptr: *mut libbpf_sys::bpf_prog_info = &mut prog_info; 637 let mut len = size_of::<libbpf_sys::bpf_prog_info>() as u32; 638 let ret = unsafe { 639 libbpf_sys::bpf_obj_get_info_by_fd( 640 fd.as_raw_fd(), 641 prog_info_ptr as *mut c_void, 642 &mut len, 643 ) 644 }; 645 util::parse_ret(ret)?; 646 Ok(prog_info.id) 647 } 648 649 /// Returns fd of a previously pinned program 650 /// 651 /// Returns error, if the pinned path doesn't represent an eBPF program. fd_from_pinned_path<P: AsRef<Path>>(path: P) -> Result<OwnedFd>652 pub fn fd_from_pinned_path<P: AsRef<Path>>(path: P) -> Result<OwnedFd> { 653 let path_c = util::path_to_cstring(&path)?; 654 let path_ptr = path_c.as_ptr(); 655 656 let fd = unsafe { libbpf_sys::bpf_obj_get(path_ptr) }; 657 let fd = util::parse_ret_i32(fd).with_context(|| { 658 format!( 659 "failed to retrieve BPF object from pinned path `{}`", 660 path.as_ref().display() 661 ) 662 })?; 663 let fd = unsafe { OwnedFd::from_raw_fd(fd) }; 664 665 // A pinned path may represent an object of any kind, including map 666 // and link. This may cause unexpected behaviour for following functions, 667 // like bpf_*_get_info_by_fd(), which allow objects of any type. 668 let fd_type = util::object_type_from_fd(fd.as_fd())?; 669 match fd_type { 670 BpfObjectType::Program => Ok(fd), 671 other => Err(Error::with_invalid_data(format!( 672 "retrieved BPF fd is not a program fd: {:#?}", 673 other 674 ))), 675 } 676 } 677 678 /// Returns flags that have been set for the program. flags(&self) -> u32679 pub fn flags(&self) -> u32 { 680 unsafe { libbpf_sys::bpf_program__flags(self.ptr.as_ptr()) } 681 } 682 683 /// Retrieve the attach type of the program. attach_type(&self) -> ProgramAttachType684 pub fn attach_type(&self) -> ProgramAttachType { 685 ProgramAttachType::from(unsafe { 686 libbpf_sys::bpf_program__expected_attach_type(self.ptr.as_ptr()) 687 }) 688 } 689 690 /// Return `true` if the bpf program is set to autoload, `false` otherwise. autoload(&self) -> bool691 pub fn autoload(&self) -> bool { 692 unsafe { libbpf_sys::bpf_program__autoload(self.ptr.as_ptr()) } 693 } 694 695 /// Return the bpf program's log level. log_level(&self) -> u32696 pub fn log_level(&self) -> u32 { 697 unsafe { libbpf_sys::bpf_program__log_level(self.ptr.as_ptr()) } 698 } 699 700 /// Returns the number of instructions that form the program. 701 /// 702 /// Please see note in [`OpenProgram::insn_cnt`]. insn_cnt(&self) -> usize703 pub fn insn_cnt(&self) -> usize { 704 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize } 705 } 706 707 /// Gives read-only access to BPF program's underlying BPF instructions. 708 /// 709 /// Please see note in [`OpenProgram::insns`]. insns(&self) -> &[libbpf_sys::bpf_insn]710 pub fn insns(&self) -> &[libbpf_sys::bpf_insn] { 711 let count = self.insn_cnt(); 712 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) }; 713 unsafe { slice::from_raw_parts(ptr, count) } 714 } 715 } 716 717 impl<'obj> ProgramMut<'obj> { 718 /// Create a [`Program`] from a [`libbpf_sys::bpf_program`] new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self719 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self { 720 Self { 721 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) }, 722 _phantom: PhantomData, 723 } 724 } 725 726 /// [Pin](https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html#bpffs) 727 /// this program to bpffs. pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()>728 pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> { 729 let path_c = util::path_to_cstring(path)?; 730 let path_ptr = path_c.as_ptr(); 731 732 let ret = unsafe { libbpf_sys::bpf_program__pin(self.ptr.as_ptr(), path_ptr) }; 733 util::parse_ret(ret) 734 } 735 736 /// [Unpin](https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html#bpffs) 737 /// this program from bpffs unpin<P: AsRef<Path>>(&mut self, path: P) -> Result<()>738 pub fn unpin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> { 739 let path_c = util::path_to_cstring(path)?; 740 let path_ptr = path_c.as_ptr(); 741 742 let ret = unsafe { libbpf_sys::bpf_program__unpin(self.ptr.as_ptr(), path_ptr) }; 743 util::parse_ret(ret) 744 } 745 746 /// Auto-attach based on prog section attach(&self) -> Result<Link>747 pub fn attach(&self) -> Result<Link> { 748 let ptr = unsafe { libbpf_sys::bpf_program__attach(self.ptr.as_ptr()) }; 749 let ptr = validate_bpf_ret(ptr).context("failed to attach BPF program")?; 750 // SAFETY: the pointer came from libbpf and has been checked for errors. 751 let link = unsafe { Link::new(ptr) }; 752 Ok(link) 753 } 754 755 /// Attach this program to a 756 /// [cgroup](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html). attach_cgroup(&self, cgroup_fd: i32) -> Result<Link>757 pub fn attach_cgroup(&self, cgroup_fd: i32) -> Result<Link> { 758 let ptr = unsafe { libbpf_sys::bpf_program__attach_cgroup(self.ptr.as_ptr(), cgroup_fd) }; 759 let ptr = validate_bpf_ret(ptr).context("failed to attach cgroup")?; 760 // SAFETY: the pointer came from libbpf and has been checked for errors. 761 let link = unsafe { Link::new(ptr) }; 762 Ok(link) 763 } 764 765 /// Attach this program to a [perf event](https://linux.die.net/man/2/perf_event_open). attach_perf_event(&self, pfd: i32) -> Result<Link>766 pub fn attach_perf_event(&self, pfd: i32) -> Result<Link> { 767 let ptr = unsafe { libbpf_sys::bpf_program__attach_perf_event(self.ptr.as_ptr(), pfd) }; 768 let ptr = validate_bpf_ret(ptr).context("failed to attach perf event")?; 769 // SAFETY: the pointer came from libbpf and has been checked for errors. 770 let link = unsafe { Link::new(ptr) }; 771 Ok(link) 772 } 773 774 /// Attach this program to a [userspace 775 /// probe](https://www.kernel.org/doc/html/latest/trace/uprobetracer.html). attach_uprobe<T: AsRef<Path>>( &self, retprobe: bool, pid: i32, binary_path: T, func_offset: usize, ) -> Result<Link>776 pub fn attach_uprobe<T: AsRef<Path>>( 777 &self, 778 retprobe: bool, 779 pid: i32, 780 binary_path: T, 781 func_offset: usize, 782 ) -> Result<Link> { 783 let path = util::path_to_cstring(binary_path)?; 784 let path_ptr = path.as_ptr(); 785 let ptr = unsafe { 786 libbpf_sys::bpf_program__attach_uprobe( 787 self.ptr.as_ptr(), 788 retprobe, 789 pid, 790 path_ptr, 791 func_offset as libbpf_sys::size_t, 792 ) 793 }; 794 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?; 795 // SAFETY: the pointer came from libbpf and has been checked for errors. 796 let link = unsafe { Link::new(ptr) }; 797 Ok(link) 798 } 799 800 /// Attach this program to a [userspace 801 /// probe](https://www.kernel.org/doc/html/latest/trace/uprobetracer.html), 802 /// providing additional options. attach_uprobe_with_opts( &self, pid: i32, binary_path: impl AsRef<Path>, func_offset: usize, opts: UprobeOpts, ) -> Result<Link>803 pub fn attach_uprobe_with_opts( 804 &self, 805 pid: i32, 806 binary_path: impl AsRef<Path>, 807 func_offset: usize, 808 opts: UprobeOpts, 809 ) -> Result<Link> { 810 let path = util::path_to_cstring(binary_path)?; 811 let path_ptr = path.as_ptr(); 812 let UprobeOpts { 813 ref_ctr_offset, 814 cookie, 815 retprobe, 816 func_name, 817 _non_exhaustive, 818 } = opts; 819 820 let func_name = util::str_to_cstring(&func_name)?; 821 let opts = libbpf_sys::bpf_uprobe_opts { 822 sz: size_of::<libbpf_sys::bpf_uprobe_opts>() as _, 823 ref_ctr_offset: ref_ctr_offset as libbpf_sys::size_t, 824 bpf_cookie: cookie, 825 retprobe, 826 func_name: func_name.as_ptr(), 827 ..Default::default() 828 }; 829 830 let ptr = unsafe { 831 libbpf_sys::bpf_program__attach_uprobe_opts( 832 self.ptr.as_ptr(), 833 pid, 834 path_ptr, 835 func_offset as libbpf_sys::size_t, 836 &opts as *const _, 837 ) 838 }; 839 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?; 840 // SAFETY: the pointer came from libbpf and has been checked for errors. 841 let link = unsafe { Link::new(ptr) }; 842 Ok(link) 843 } 844 845 /// Attach this program to a [kernel 846 /// probe](https://www.kernel.org/doc/html/latest/trace/kprobetrace.html). attach_kprobe<T: AsRef<str>>(&self, retprobe: bool, func_name: T) -> Result<Link>847 pub fn attach_kprobe<T: AsRef<str>>(&self, retprobe: bool, func_name: T) -> Result<Link> { 848 let func_name = util::str_to_cstring(func_name.as_ref())?; 849 let func_name_ptr = func_name.as_ptr(); 850 let ptr = unsafe { 851 libbpf_sys::bpf_program__attach_kprobe(self.ptr.as_ptr(), retprobe, func_name_ptr) 852 }; 853 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe")?; 854 // SAFETY: the pointer came from libbpf and has been checked for errors. 855 let link = unsafe { Link::new(ptr) }; 856 Ok(link) 857 } 858 859 /// Attach this program to the specified syscall attach_ksyscall<T: AsRef<str>>(&self, retprobe: bool, syscall_name: T) -> Result<Link>860 pub fn attach_ksyscall<T: AsRef<str>>(&self, retprobe: bool, syscall_name: T) -> Result<Link> { 861 let opts = libbpf_sys::bpf_ksyscall_opts { 862 sz: size_of::<libbpf_sys::bpf_ksyscall_opts>() as _, 863 retprobe, 864 ..Default::default() 865 }; 866 867 let syscall_name = util::str_to_cstring(syscall_name.as_ref())?; 868 let syscall_name_ptr = syscall_name.as_ptr(); 869 let ptr = unsafe { 870 libbpf_sys::bpf_program__attach_ksyscall(self.ptr.as_ptr(), syscall_name_ptr, &opts) 871 }; 872 let ptr = validate_bpf_ret(ptr).context("failed to attach ksyscall")?; 873 // SAFETY: the pointer came from libbpf and has been checked for errors. 874 let link = unsafe { Link::new(ptr) }; 875 Ok(link) 876 } 877 attach_tracepoint_impl( &self, tp_category: &str, tp_name: &str, tp_opts: Option<TracepointOpts>, ) -> Result<Link>878 fn attach_tracepoint_impl( 879 &self, 880 tp_category: &str, 881 tp_name: &str, 882 tp_opts: Option<TracepointOpts>, 883 ) -> Result<Link> { 884 let tp_category = util::str_to_cstring(tp_category)?; 885 let tp_category_ptr = tp_category.as_ptr(); 886 let tp_name = util::str_to_cstring(tp_name)?; 887 let tp_name_ptr = tp_name.as_ptr(); 888 889 let ptr = if let Some(tp_opts) = tp_opts { 890 let tp_opts = libbpf_sys::bpf_tracepoint_opts::from(tp_opts); 891 unsafe { 892 libbpf_sys::bpf_program__attach_tracepoint_opts( 893 self.ptr.as_ptr(), 894 tp_category_ptr, 895 tp_name_ptr, 896 &tp_opts as *const _, 897 ) 898 } 899 } else { 900 unsafe { 901 libbpf_sys::bpf_program__attach_tracepoint( 902 self.ptr.as_ptr(), 903 tp_category_ptr, 904 tp_name_ptr, 905 ) 906 } 907 }; 908 909 let ptr = validate_bpf_ret(ptr).context("failed to attach tracepoint")?; 910 // SAFETY: the pointer came from libbpf and has been checked for errors. 911 let link = unsafe { Link::new(ptr) }; 912 Ok(link) 913 } 914 915 /// Attach this program to a [kernel 916 /// tracepoint](https://www.kernel.org/doc/html/latest/trace/tracepoints.html). attach_tracepoint( &self, tp_category: impl AsRef<str>, tp_name: impl AsRef<str>, ) -> Result<Link>917 pub fn attach_tracepoint( 918 &self, 919 tp_category: impl AsRef<str>, 920 tp_name: impl AsRef<str>, 921 ) -> Result<Link> { 922 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), None) 923 } 924 925 /// Attach this program to a [kernel 926 /// tracepoint](https://www.kernel.org/doc/html/latest/trace/tracepoints.html), 927 /// providing additional options. attach_tracepoint_with_opts( &self, tp_category: impl AsRef<str>, tp_name: impl AsRef<str>, tp_opts: TracepointOpts, ) -> Result<Link>928 pub fn attach_tracepoint_with_opts( 929 &self, 930 tp_category: impl AsRef<str>, 931 tp_name: impl AsRef<str>, 932 tp_opts: TracepointOpts, 933 ) -> Result<Link> { 934 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), Some(tp_opts)) 935 } 936 937 /// Attach this program to a [raw kernel 938 /// tracepoint](https://lwn.net/Articles/748352/). attach_raw_tracepoint<T: AsRef<str>>(&self, tp_name: T) -> Result<Link>939 pub fn attach_raw_tracepoint<T: AsRef<str>>(&self, tp_name: T) -> Result<Link> { 940 let tp_name = util::str_to_cstring(tp_name.as_ref())?; 941 let tp_name_ptr = tp_name.as_ptr(); 942 let ptr = unsafe { 943 libbpf_sys::bpf_program__attach_raw_tracepoint(self.ptr.as_ptr(), tp_name_ptr) 944 }; 945 let ptr = validate_bpf_ret(ptr).context("failed to attach raw tracepoint")?; 946 // SAFETY: the pointer came from libbpf and has been checked for errors. 947 let link = unsafe { Link::new(ptr) }; 948 Ok(link) 949 } 950 951 /// Attach to an [LSM](https://en.wikipedia.org/wiki/Linux_Security_Modules) hook attach_lsm(&self) -> Result<Link>952 pub fn attach_lsm(&self) -> Result<Link> { 953 let ptr = unsafe { libbpf_sys::bpf_program__attach_lsm(self.ptr.as_ptr()) }; 954 let ptr = validate_bpf_ret(ptr).context("failed to attach LSM")?; 955 // SAFETY: the pointer came from libbpf and has been checked for errors. 956 let link = unsafe { Link::new(ptr) }; 957 Ok(link) 958 } 959 960 /// Attach to a [fentry/fexit kernel probe](https://lwn.net/Articles/801479/) attach_trace(&self) -> Result<Link>961 pub fn attach_trace(&self) -> Result<Link> { 962 let ptr = unsafe { libbpf_sys::bpf_program__attach_trace(self.ptr.as_ptr()) }; 963 let ptr = validate_bpf_ret(ptr).context("failed to attach fentry/fexit kernel probe")?; 964 // SAFETY: the pointer came from libbpf and has been checked for errors. 965 let link = unsafe { Link::new(ptr) }; 966 Ok(link) 967 } 968 969 /// Attach a verdict/parser to a [sockmap/sockhash](https://lwn.net/Articles/731133/) attach_sockmap(&self, map_fd: i32) -> Result<()>970 pub fn attach_sockmap(&self, map_fd: i32) -> Result<()> { 971 let err = unsafe { 972 libbpf_sys::bpf_prog_attach( 973 self.as_fd().as_raw_fd(), 974 map_fd, 975 self.attach_type() as u32, 976 0, 977 ) 978 }; 979 util::parse_ret(err) 980 } 981 982 /// Attach this program to [XDP](https://lwn.net/Articles/825998/) attach_xdp(&self, ifindex: i32) -> Result<Link>983 pub fn attach_xdp(&self, ifindex: i32) -> Result<Link> { 984 let ptr = unsafe { libbpf_sys::bpf_program__attach_xdp(self.ptr.as_ptr(), ifindex) }; 985 let ptr = validate_bpf_ret(ptr).context("failed to attach XDP program")?; 986 // SAFETY: the pointer came from libbpf and has been checked for errors. 987 let link = unsafe { Link::new(ptr) }; 988 Ok(link) 989 } 990 991 /// Attach this program to [netns-based programs](https://lwn.net/Articles/819618/) attach_netns(&self, netns_fd: i32) -> Result<Link>992 pub fn attach_netns(&self, netns_fd: i32) -> Result<Link> { 993 let ptr = unsafe { libbpf_sys::bpf_program__attach_netns(self.ptr.as_ptr(), netns_fd) }; 994 let ptr = validate_bpf_ret(ptr).context("failed to attach network namespace program")?; 995 // SAFETY: the pointer came from libbpf and has been checked for errors. 996 let link = unsafe { Link::new(ptr) }; 997 Ok(link) 998 } 999 1000 /// Attach this program to [netfilter programs](https://lwn.net/Articles/925082/) attach_netfilter_with_opts( &self, netfilter_opt: netfilter::NetfilterOpts, ) -> Result<Link>1001 pub fn attach_netfilter_with_opts( 1002 &self, 1003 netfilter_opt: netfilter::NetfilterOpts, 1004 ) -> Result<Link> { 1005 let netfilter_opts = libbpf_sys::bpf_netfilter_opts::from(netfilter_opt); 1006 1007 let ptr = unsafe { 1008 libbpf_sys::bpf_program__attach_netfilter( 1009 self.ptr.as_ptr(), 1010 &netfilter_opts as *const _, 1011 ) 1012 }; 1013 1014 let ptr = validate_bpf_ret(ptr).context("failed to attach netfilter program")?; 1015 // SAFETY: the pointer came from libbpf and has been checked for errors. 1016 let link = unsafe { Link::new(ptr) }; 1017 Ok(link) 1018 } 1019 attach_usdt_impl( &self, pid: i32, binary_path: &Path, usdt_provider: &str, usdt_name: &str, usdt_opts: Option<UsdtOpts>, ) -> Result<Link>1020 fn attach_usdt_impl( 1021 &self, 1022 pid: i32, 1023 binary_path: &Path, 1024 usdt_provider: &str, 1025 usdt_name: &str, 1026 usdt_opts: Option<UsdtOpts>, 1027 ) -> Result<Link> { 1028 let path = util::path_to_cstring(binary_path)?; 1029 let path_ptr = path.as_ptr(); 1030 let usdt_provider = util::str_to_cstring(usdt_provider)?; 1031 let usdt_provider_ptr = usdt_provider.as_ptr(); 1032 let usdt_name = util::str_to_cstring(usdt_name)?; 1033 let usdt_name_ptr = usdt_name.as_ptr(); 1034 let usdt_opts = usdt_opts.map(libbpf_sys::bpf_usdt_opts::from); 1035 let usdt_opts_ptr = usdt_opts 1036 .as_ref() 1037 .map(|opts| opts as *const _) 1038 .unwrap_or_else(ptr::null); 1039 1040 let ptr = unsafe { 1041 libbpf_sys::bpf_program__attach_usdt( 1042 self.ptr.as_ptr(), 1043 pid, 1044 path_ptr, 1045 usdt_provider_ptr, 1046 usdt_name_ptr, 1047 usdt_opts_ptr, 1048 ) 1049 }; 1050 let ptr = validate_bpf_ret(ptr).context("failed to attach USDT")?; 1051 // SAFETY: the pointer came from libbpf and has been checked for errors. 1052 let link = unsafe { Link::new(ptr) }; 1053 Ok(link) 1054 } 1055 1056 /// Attach this program to a [USDT](https://lwn.net/Articles/753601/) probe 1057 /// point. The entry point of the program must be defined with 1058 /// `SEC("usdt")`. attach_usdt( &self, pid: i32, binary_path: impl AsRef<Path>, usdt_provider: impl AsRef<str>, usdt_name: impl AsRef<str>, ) -> Result<Link>1059 pub fn attach_usdt( 1060 &self, 1061 pid: i32, 1062 binary_path: impl AsRef<Path>, 1063 usdt_provider: impl AsRef<str>, 1064 usdt_name: impl AsRef<str>, 1065 ) -> Result<Link> { 1066 self.attach_usdt_impl( 1067 pid, 1068 binary_path.as_ref(), 1069 usdt_provider.as_ref(), 1070 usdt_name.as_ref(), 1071 None, 1072 ) 1073 } 1074 1075 /// Attach this program to a [USDT](https://lwn.net/Articles/753601/) probe 1076 /// point, providing additional options. The entry point of the program must 1077 /// be defined with `SEC("usdt")`. attach_usdt_with_opts( &self, pid: i32, binary_path: impl AsRef<Path>, usdt_provider: impl AsRef<str>, usdt_name: impl AsRef<str>, usdt_opts: UsdtOpts, ) -> Result<Link>1078 pub fn attach_usdt_with_opts( 1079 &self, 1080 pid: i32, 1081 binary_path: impl AsRef<Path>, 1082 usdt_provider: impl AsRef<str>, 1083 usdt_name: impl AsRef<str>, 1084 usdt_opts: UsdtOpts, 1085 ) -> Result<Link> { 1086 self.attach_usdt_impl( 1087 pid, 1088 binary_path.as_ref(), 1089 usdt_provider.as_ref(), 1090 usdt_name.as_ref(), 1091 Some(usdt_opts), 1092 ) 1093 } 1094 1095 /// Attach this program to a 1096 /// [BPF Iterator](https://www.kernel.org/doc/html/latest/bpf/bpf_iterators.html). 1097 /// The entry point of the program must be defined with `SEC("iter")` or `SEC("iter.s")`. attach_iter(&self, map_fd: BorrowedFd<'_>) -> Result<Link>1098 pub fn attach_iter(&self, map_fd: BorrowedFd<'_>) -> Result<Link> { 1099 let mut linkinfo = libbpf_sys::bpf_iter_link_info::default(); 1100 linkinfo.map.map_fd = map_fd.as_raw_fd() as _; 1101 let attach_opt = libbpf_sys::bpf_iter_attach_opts { 1102 link_info: &mut linkinfo as *mut libbpf_sys::bpf_iter_link_info, 1103 link_info_len: size_of::<libbpf_sys::bpf_iter_link_info>() as _, 1104 sz: size_of::<libbpf_sys::bpf_iter_attach_opts>() as _, 1105 ..Default::default() 1106 }; 1107 let ptr = unsafe { 1108 libbpf_sys::bpf_program__attach_iter( 1109 self.ptr.as_ptr(), 1110 &attach_opt as *const libbpf_sys::bpf_iter_attach_opts, 1111 ) 1112 }; 1113 1114 let ptr = validate_bpf_ret(ptr).context("failed to attach iterator")?; 1115 // SAFETY: the pointer came from libbpf and has been checked for errors. 1116 let link = unsafe { Link::new(ptr) }; 1117 Ok(link) 1118 } 1119 1120 /// Test run the program with the given input data. 1121 /// 1122 /// This function uses the 1123 /// [BPF_PROG_RUN](https://www.kernel.org/doc/html/latest/bpf/bpf_prog_run.html) 1124 /// facility. test_run<'dat>(&self, input: Input<'dat>) -> Result<Output<'dat>>1125 pub fn test_run<'dat>(&self, input: Input<'dat>) -> Result<Output<'dat>> { 1126 unsafe fn slice_from_array<'t, T>(items: *mut T, num_items: usize) -> Option<&'t mut [T]> { 1127 if items.is_null() { 1128 None 1129 } else { 1130 Some(unsafe { slice::from_raw_parts_mut(items, num_items) }) 1131 } 1132 } 1133 1134 let Input { 1135 context_in, 1136 mut context_out, 1137 data_in, 1138 mut data_out, 1139 cpu, 1140 flags, 1141 _non_exhaustive: (), 1142 } = input; 1143 1144 let mut opts = unsafe { mem::zeroed::<libbpf_sys::bpf_test_run_opts>() }; 1145 opts.sz = size_of_val(&opts) as _; 1146 opts.ctx_in = context_in 1147 .as_ref() 1148 .map(|data| data.as_ptr().cast()) 1149 .unwrap_or_else(ptr::null); 1150 opts.ctx_size_in = context_in.map(|data| data.len() as _).unwrap_or(0); 1151 opts.ctx_out = context_out 1152 .as_mut() 1153 .map(|data| data.as_mut_ptr().cast()) 1154 .unwrap_or_else(ptr::null_mut); 1155 opts.ctx_size_out = context_out.map(|data| data.len() as _).unwrap_or(0); 1156 opts.data_in = data_in 1157 .map(|data| data.as_ptr().cast()) 1158 .unwrap_or_else(ptr::null); 1159 opts.data_size_in = data_in.map(|data| data.len() as _).unwrap_or(0); 1160 opts.data_out = data_out 1161 .as_mut() 1162 .map(|data| data.as_mut_ptr().cast()) 1163 .unwrap_or_else(ptr::null_mut); 1164 opts.data_size_out = data_out.map(|data| data.len() as _).unwrap_or(0); 1165 opts.cpu = cpu; 1166 opts.flags = flags; 1167 1168 let rc = unsafe { libbpf_sys::bpf_prog_test_run_opts(self.as_fd().as_raw_fd(), &mut opts) }; 1169 let () = util::parse_ret(rc)?; 1170 let output = Output { 1171 return_value: opts.retval, 1172 context: unsafe { slice_from_array(opts.ctx_out.cast(), opts.ctx_size_out as _) }, 1173 data: unsafe { slice_from_array(opts.data_out.cast(), opts.data_size_out as _) }, 1174 _non_exhaustive: (), 1175 }; 1176 Ok(output) 1177 } 1178 } 1179 1180 impl<'obj> Deref for ProgramMut<'obj> { 1181 type Target = Program<'obj>; 1182 deref(&self) -> &Self::Target1183 fn deref(&self) -> &Self::Target { 1184 // SAFETY: `ProgramImpl` is `repr(transparent)` and so in-memory 1185 // representation of both types is the same. 1186 unsafe { transmute::<&ProgramMut<'obj>, &Program<'obj>>(self) } 1187 } 1188 } 1189 1190 impl<T> AsFd for ProgramImpl<'_, T> { as_fd(&self) -> BorrowedFd<'_>1191 fn as_fd(&self) -> BorrowedFd<'_> { 1192 let fd = unsafe { libbpf_sys::bpf_program__fd(self.ptr.as_ptr()) }; 1193 unsafe { BorrowedFd::borrow_raw(fd) } 1194 } 1195 } 1196 1197 impl<T> AsRawLibbpf for ProgramImpl<'_, T> { 1198 type LibbpfType = libbpf_sys::bpf_program; 1199 1200 /// Retrieve the underlying [`libbpf_sys::bpf_program`]. as_libbpf_object(&self) -> NonNull<Self::LibbpfType>1201 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> { 1202 self.ptr 1203 } 1204 } 1205 1206 #[cfg(test)] 1207 mod tests { 1208 use super::*; 1209 1210 use std::mem::discriminant; 1211 1212 #[test] program_type()1213 fn program_type() { 1214 use ProgramType::*; 1215 1216 for t in [ 1217 Unspec, 1218 SocketFilter, 1219 Kprobe, 1220 SchedCls, 1221 SchedAct, 1222 Tracepoint, 1223 Xdp, 1224 PerfEvent, 1225 CgroupSkb, 1226 CgroupSock, 1227 LwtIn, 1228 LwtOut, 1229 LwtXmit, 1230 SockOps, 1231 SkSkb, 1232 CgroupDevice, 1233 SkMsg, 1234 RawTracepoint, 1235 CgroupSockAddr, 1236 LwtSeg6local, 1237 LircMode2, 1238 SkReuseport, 1239 FlowDissector, 1240 CgroupSysctl, 1241 RawTracepointWritable, 1242 CgroupSockopt, 1243 Tracing, 1244 StructOps, 1245 Ext, 1246 Lsm, 1247 SkLookup, 1248 Syscall, 1249 Unknown, 1250 ] { 1251 // check if discriminants match after a roundtrip conversion 1252 assert_eq!(discriminant(&t), discriminant(&ProgramType::from(t as u32))); 1253 } 1254 } 1255 1256 #[test] program_attach_type()1257 fn program_attach_type() { 1258 use ProgramAttachType::*; 1259 1260 for t in [ 1261 CgroupInetIngress, 1262 CgroupInetEgress, 1263 CgroupInetSockCreate, 1264 CgroupSockOps, 1265 SkSkbStreamParser, 1266 SkSkbStreamVerdict, 1267 CgroupDevice, 1268 SkMsgVerdict, 1269 CgroupInet4Bind, 1270 CgroupInet6Bind, 1271 CgroupInet4Connect, 1272 CgroupInet6Connect, 1273 CgroupInet4PostBind, 1274 CgroupInet6PostBind, 1275 CgroupUdp4Sendmsg, 1276 CgroupUdp6Sendmsg, 1277 LircMode2, 1278 FlowDissector, 1279 CgroupSysctl, 1280 CgroupUdp4Recvmsg, 1281 CgroupUdp6Recvmsg, 1282 CgroupGetsockopt, 1283 CgroupSetsockopt, 1284 TraceRawTp, 1285 TraceFentry, 1286 TraceFexit, 1287 ModifyReturn, 1288 LsmMac, 1289 TraceIter, 1290 CgroupInet4Getpeername, 1291 CgroupInet6Getpeername, 1292 CgroupInet4Getsockname, 1293 CgroupInet6Getsockname, 1294 XdpDevmap, 1295 CgroupInetSockRelease, 1296 XdpCpumap, 1297 SkLookup, 1298 Xdp, 1299 SkSkbVerdict, 1300 SkReuseportSelect, 1301 SkReuseportSelectOrMigrate, 1302 PerfEvent, 1303 Unknown, 1304 ] { 1305 // check if discriminants match after a roundtrip conversion 1306 assert_eq!( 1307 discriminant(&t), 1308 discriminant(&ProgramAttachType::from(t as u32)) 1309 ); 1310 } 1311 } 1312 } 1313