4
0

mod.rs 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  1. //! eBPF program types.
  2. //!
  3. //! eBPF programs are loaded inside the kernel and attached to one or more hook
  4. //! points. Whenever the hook points are reached, the programs are executed.
  5. //!
  6. //! # Loading and attaching programs
  7. //!
  8. //! When you call [`Ebpf::load_file`] or [`Ebpf::load`], all the programs included
  9. //! in the object code are parsed and relocated. Programs are not loaded
  10. //! automatically though, since often you will need to do some application
  11. //! specific setup before you can actually load them.
  12. //!
  13. //! In order to load and attach a program, you need to retrieve it using [`Ebpf::program_mut`],
  14. //! then call the `load()` and `attach()` methods, for example:
  15. //!
  16. //! ```no_run
  17. //! use aya::{Ebpf, programs::KProbe};
  18. //!
  19. //! let mut bpf = Ebpf::load_file("ebpf_programs.o")?;
  20. //! // intercept_wakeups is the name of the program we want to load
  21. //! let program: &mut KProbe = bpf.program_mut("intercept_wakeups").unwrap().try_into()?;
  22. //! program.load()?;
  23. //! // intercept_wakeups will be called every time try_to_wake_up() is called
  24. //! // inside the kernel
  25. //! program.attach("try_to_wake_up", 0)?;
  26. //! # Ok::<(), aya::EbpfError>(())
  27. //! ```
  28. //!
  29. //! The signature of the `attach()` method varies depending on what kind of
  30. //! program you're trying to attach.
  31. //!
  32. //! [`Ebpf::load_file`]: crate::Ebpf::load_file
  33. //! [`Ebpf::load`]: crate::Ebpf::load
  34. //! [`Ebpf::programs`]: crate::Ebpf::programs
  35. //! [`Ebpf::program`]: crate::Ebpf::program
  36. //! [`Ebpf::program_mut`]: crate::Ebpf::program_mut
  37. //! [`maps`]: crate::maps
  38. // modules we don't export
  39. mod info;
  40. mod probe;
  41. mod utils;
  42. // modules we explicitly export so their pub items (Links etc) get exported too
  43. pub mod cgroup_device;
  44. pub mod cgroup_skb;
  45. pub mod cgroup_sock;
  46. pub mod cgroup_sock_addr;
  47. pub mod cgroup_sockopt;
  48. pub mod cgroup_sysctl;
  49. pub mod extension;
  50. pub mod fentry;
  51. pub mod fexit;
  52. pub mod kprobe;
  53. pub mod links;
  54. pub mod lirc_mode2;
  55. pub mod lsm;
  56. pub mod perf_attach;
  57. pub mod perf_event;
  58. pub mod raw_trace_point;
  59. pub mod sk_lookup;
  60. pub mod sk_msg;
  61. pub mod sk_skb;
  62. pub mod sock_ops;
  63. pub mod socket_filter;
  64. pub mod tc;
  65. pub mod tp_btf;
  66. pub mod trace_point;
  67. pub mod uprobe;
  68. pub mod xdp;
  69. use std::{
  70. ffi::CString,
  71. io,
  72. os::fd::{AsFd, BorrowedFd},
  73. path::{Path, PathBuf},
  74. sync::Arc,
  75. };
  76. use info::impl_info;
  77. pub use info::{loaded_programs, ProgramInfo, ProgramType};
  78. use libc::ENOSPC;
  79. use tc::SchedClassifierLink;
  80. use thiserror::Error;
  81. // re-export the main items needed to load and attach
  82. pub use crate::programs::{
  83. cgroup_device::CgroupDevice,
  84. cgroup_skb::{CgroupSkb, CgroupSkbAttachType},
  85. cgroup_sock::{CgroupSock, CgroupSockAttachType},
  86. cgroup_sock_addr::{CgroupSockAddr, CgroupSockAddrAttachType},
  87. cgroup_sockopt::{CgroupSockopt, CgroupSockoptAttachType},
  88. cgroup_sysctl::CgroupSysctl,
  89. extension::{Extension, ExtensionError},
  90. fentry::FEntry,
  91. fexit::FExit,
  92. kprobe::{KProbe, KProbeError},
  93. links::{CgroupAttachMode, Link, LinkOrder},
  94. lirc_mode2::LircMode2,
  95. lsm::Lsm,
  96. perf_event::{PerfEvent, PerfEventScope, PerfTypeId, SamplePolicy},
  97. probe::ProbeKind,
  98. raw_trace_point::RawTracePoint,
  99. sk_lookup::SkLookup,
  100. sk_msg::SkMsg,
  101. sk_skb::{SkSkb, SkSkbKind},
  102. sock_ops::SockOps,
  103. socket_filter::{SocketFilter, SocketFilterError},
  104. tc::{SchedClassifier, TcAttachType, TcError},
  105. tp_btf::BtfTracePoint,
  106. trace_point::{TracePoint, TracePointError},
  107. uprobe::{UProbe, UProbeError},
  108. xdp::{Xdp, XdpError, XdpFlags},
  109. };
  110. use crate::{
  111. generated::{bpf_attach_type, bpf_link_info, bpf_prog_info, bpf_prog_type},
  112. maps::MapError,
  113. obj::{self, btf::BtfError, VerifierLog},
  114. pin::PinError,
  115. programs::{links::*, perf_attach::*},
  116. sys::{
  117. bpf_btf_get_fd_by_id, bpf_get_object, bpf_link_get_fd_by_id, bpf_link_get_info_by_fd,
  118. bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id, bpf_prog_query, iter_link_ids,
  119. retry_with_verifier_logs, EbpfLoadProgramAttrs, ProgQueryTarget, SyscallError,
  120. },
  121. util::KernelVersion,
  122. VerifierLogLevel,
  123. };
  124. /// Error type returned when working with programs.
  125. #[derive(Debug, Error)]
  126. pub enum ProgramError {
  127. /// The program is already loaded.
  128. #[error("the program is already loaded")]
  129. AlreadyLoaded,
  130. /// The program is not loaded.
  131. #[error("the program is not loaded")]
  132. NotLoaded,
  133. /// The program is already attached.
  134. #[error("the program was already attached")]
  135. AlreadyAttached,
  136. /// The program is not attached.
  137. #[error("the program is not attached")]
  138. NotAttached,
  139. /// Loading the program failed.
  140. #[error("the BPF_PROG_LOAD syscall failed. Verifier output: {verifier_log}")]
  141. LoadError {
  142. /// The [`io::Error`] returned by the `BPF_PROG_LOAD` syscall.
  143. #[source]
  144. io_error: io::Error,
  145. /// The error log produced by the kernel verifier.
  146. verifier_log: VerifierLog,
  147. },
  148. /// A syscall failed.
  149. #[error(transparent)]
  150. SyscallError(#[from] SyscallError),
  151. /// The network interface does not exist.
  152. #[error("unknown network interface {name}")]
  153. UnknownInterface {
  154. /// interface name
  155. name: String,
  156. },
  157. /// The program is not of the expected type.
  158. #[error("unexpected program type")]
  159. UnexpectedProgramType,
  160. /// A map error occurred while loading or attaching a program.
  161. #[error(transparent)]
  162. MapError(#[from] MapError),
  163. /// An error occurred while working with a [`KProbe`].
  164. #[error(transparent)]
  165. KProbeError(#[from] KProbeError),
  166. /// An error occurred while working with an [`UProbe`].
  167. #[error(transparent)]
  168. UProbeError(#[from] UProbeError),
  169. /// An error occurred while working with a [`TracePoint`].
  170. #[error(transparent)]
  171. TracePointError(#[from] TracePointError),
  172. /// An error occurred while working with a [`SocketFilter`].
  173. #[error(transparent)]
  174. SocketFilterError(#[from] SocketFilterError),
  175. /// An error occurred while working with an [`Xdp`] program.
  176. #[error(transparent)]
  177. XdpError(#[from] XdpError),
  178. /// An error occurred while working with a TC program.
  179. #[error(transparent)]
  180. TcError(#[from] TcError),
  181. /// An error occurred while working with an [`Extension`] program.
  182. #[error(transparent)]
  183. ExtensionError(#[from] ExtensionError),
  184. /// An error occurred while working with BTF.
  185. #[error(transparent)]
  186. Btf(#[from] BtfError),
  187. /// The program is not attached.
  188. #[error("the program name `{name}` is invalid")]
  189. InvalidName {
  190. /// program name
  191. name: String,
  192. },
  193. /// An error occurred while working with IO.
  194. #[error(transparent)]
  195. IOError(#[from] io::Error),
  196. }
  197. /// A [`Program`] file descriptor.
  198. #[derive(Debug)]
  199. pub struct ProgramFd(crate::MockableFd);
  200. impl ProgramFd {
  201. /// Creates a new instance that shares the same underlying file description as [`self`].
  202. pub fn try_clone(&self) -> io::Result<Self> {
  203. let Self(inner) = self;
  204. let inner = inner.try_clone()?;
  205. Ok(Self(inner))
  206. }
  207. }
  208. impl AsFd for ProgramFd {
  209. fn as_fd(&self) -> BorrowedFd<'_> {
  210. let Self(fd) = self;
  211. fd.as_fd()
  212. }
  213. }
  214. /// A [`Program`] identifier.
  215. pub struct ProgramId(u32);
  216. impl ProgramId {
  217. /// Create a new program id.
  218. ///
  219. /// This method is unsafe since it doesn't check that the given `id` is a
  220. /// valid program id.
  221. pub unsafe fn new(id: u32) -> Self {
  222. Self(id)
  223. }
  224. }
  225. /// eBPF program type.
  226. #[derive(Debug)]
  227. pub enum Program {
  228. /// A [`KProbe`] program
  229. KProbe(KProbe),
  230. /// A [`UProbe`] program
  231. UProbe(UProbe),
  232. /// A [`TracePoint`] program
  233. TracePoint(TracePoint),
  234. /// A [`SocketFilter`] program
  235. SocketFilter(SocketFilter),
  236. /// A [`Xdp`] program
  237. Xdp(Xdp),
  238. /// A [`SkMsg`] program
  239. SkMsg(SkMsg),
  240. /// A [`SkSkb`] program
  241. SkSkb(SkSkb),
  242. /// A [`CgroupSockAddr`] program
  243. CgroupSockAddr(CgroupSockAddr),
  244. /// A [`SockOps`] program
  245. SockOps(SockOps),
  246. /// A [`SchedClassifier`] program
  247. SchedClassifier(SchedClassifier),
  248. /// A [`CgroupSkb`] program
  249. CgroupSkb(CgroupSkb),
  250. /// A [`CgroupSysctl`] program
  251. CgroupSysctl(CgroupSysctl),
  252. /// A [`CgroupSockopt`] program
  253. CgroupSockopt(CgroupSockopt),
  254. /// A [`LircMode2`] program
  255. LircMode2(LircMode2),
  256. /// A [`PerfEvent`] program
  257. PerfEvent(PerfEvent),
  258. /// A [`RawTracePoint`] program
  259. RawTracePoint(RawTracePoint),
  260. /// A [`Lsm`] program
  261. Lsm(Lsm),
  262. /// A [`BtfTracePoint`] program
  263. BtfTracePoint(BtfTracePoint),
  264. /// A [`FEntry`] program
  265. FEntry(FEntry),
  266. /// A [`FExit`] program
  267. FExit(FExit),
  268. /// A [`Extension`] program
  269. Extension(Extension),
  270. /// A [`SkLookup`] program
  271. SkLookup(SkLookup),
  272. /// A [`CgroupSock`] program
  273. CgroupSock(CgroupSock),
  274. /// A [`CgroupDevice`] program
  275. CgroupDevice(CgroupDevice),
  276. }
  277. impl Program {
  278. /// Returns the program type.
  279. pub fn prog_type(&self) -> ProgramType {
  280. match self {
  281. Self::KProbe(_) | Self::UProbe(_) => ProgramType::KProbe,
  282. Self::TracePoint(_) => ProgramType::TracePoint,
  283. Self::SocketFilter(_) => ProgramType::SocketFilter,
  284. Self::Xdp(_) => ProgramType::Xdp,
  285. Self::SkMsg(_) => ProgramType::SkMsg,
  286. Self::SkSkb(_) => ProgramType::SkSkb,
  287. Self::SockOps(_) => ProgramType::SockOps,
  288. Self::SchedClassifier(_) => ProgramType::SchedClassifier,
  289. Self::CgroupSkb(_) => ProgramType::CgroupSkb,
  290. Self::CgroupSysctl(_) => ProgramType::CgroupSysctl,
  291. Self::CgroupSockopt(_) => ProgramType::CgroupSockopt,
  292. Self::LircMode2(_) => ProgramType::LircMode2,
  293. Self::PerfEvent(_) => ProgramType::PerfEvent,
  294. Self::RawTracePoint(_) => ProgramType::RawTracePoint,
  295. Self::Lsm(_) => ProgramType::Lsm,
  296. Self::BtfTracePoint(_) | Self::FEntry(_) | Self::FExit(_) => ProgramType::Tracing,
  297. Self::Extension(_) => ProgramType::Extension,
  298. Self::CgroupSockAddr(_) => ProgramType::CgroupSockAddr,
  299. Self::SkLookup(_) => ProgramType::SkLookup,
  300. Self::CgroupSock(_) => ProgramType::CgroupSock,
  301. Self::CgroupDevice(_) => ProgramType::CgroupDevice,
  302. }
  303. }
  304. /// Pin the program to the provided path
  305. pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<(), PinError> {
  306. match self {
  307. Self::KProbe(p) => p.pin(path),
  308. Self::UProbe(p) => p.pin(path),
  309. Self::TracePoint(p) => p.pin(path),
  310. Self::SocketFilter(p) => p.pin(path),
  311. Self::Xdp(p) => p.pin(path),
  312. Self::SkMsg(p) => p.pin(path),
  313. Self::SkSkb(p) => p.pin(path),
  314. Self::SockOps(p) => p.pin(path),
  315. Self::SchedClassifier(p) => p.pin(path),
  316. Self::CgroupSkb(p) => p.pin(path),
  317. Self::CgroupSysctl(p) => p.pin(path),
  318. Self::CgroupSockopt(p) => p.pin(path),
  319. Self::LircMode2(p) => p.pin(path),
  320. Self::PerfEvent(p) => p.pin(path),
  321. Self::RawTracePoint(p) => p.pin(path),
  322. Self::Lsm(p) => p.pin(path),
  323. Self::BtfTracePoint(p) => p.pin(path),
  324. Self::FEntry(p) => p.pin(path),
  325. Self::FExit(p) => p.pin(path),
  326. Self::Extension(p) => p.pin(path),
  327. Self::CgroupSockAddr(p) => p.pin(path),
  328. Self::SkLookup(p) => p.pin(path),
  329. Self::CgroupSock(p) => p.pin(path),
  330. Self::CgroupDevice(p) => p.pin(path),
  331. }
  332. }
  333. /// Unloads the program from the kernel.
  334. pub fn unload(self) -> Result<(), ProgramError> {
  335. match self {
  336. Self::KProbe(mut p) => p.unload(),
  337. Self::UProbe(mut p) => p.unload(),
  338. Self::TracePoint(mut p) => p.unload(),
  339. Self::SocketFilter(mut p) => p.unload(),
  340. Self::Xdp(mut p) => p.unload(),
  341. Self::SkMsg(mut p) => p.unload(),
  342. Self::SkSkb(mut p) => p.unload(),
  343. Self::SockOps(mut p) => p.unload(),
  344. Self::SchedClassifier(mut p) => p.unload(),
  345. Self::CgroupSkb(mut p) => p.unload(),
  346. Self::CgroupSysctl(mut p) => p.unload(),
  347. Self::CgroupSockopt(mut p) => p.unload(),
  348. Self::LircMode2(mut p) => p.unload(),
  349. Self::PerfEvent(mut p) => p.unload(),
  350. Self::RawTracePoint(mut p) => p.unload(),
  351. Self::Lsm(mut p) => p.unload(),
  352. Self::BtfTracePoint(mut p) => p.unload(),
  353. Self::FEntry(mut p) => p.unload(),
  354. Self::FExit(mut p) => p.unload(),
  355. Self::Extension(mut p) => p.unload(),
  356. Self::CgroupSockAddr(mut p) => p.unload(),
  357. Self::SkLookup(mut p) => p.unload(),
  358. Self::CgroupSock(mut p) => p.unload(),
  359. Self::CgroupDevice(mut p) => p.unload(),
  360. }
  361. }
  362. /// Returns the file descriptor of a program.
  363. ///
  364. /// Can be used to add a program to a [`crate::maps::ProgramArray`] or attach an [`Extension`] program.
  365. pub fn fd(&self) -> Result<&ProgramFd, ProgramError> {
  366. match self {
  367. Self::KProbe(p) => p.fd(),
  368. Self::UProbe(p) => p.fd(),
  369. Self::TracePoint(p) => p.fd(),
  370. Self::SocketFilter(p) => p.fd(),
  371. Self::Xdp(p) => p.fd(),
  372. Self::SkMsg(p) => p.fd(),
  373. Self::SkSkb(p) => p.fd(),
  374. Self::SockOps(p) => p.fd(),
  375. Self::SchedClassifier(p) => p.fd(),
  376. Self::CgroupSkb(p) => p.fd(),
  377. Self::CgroupSysctl(p) => p.fd(),
  378. Self::CgroupSockopt(p) => p.fd(),
  379. Self::LircMode2(p) => p.fd(),
  380. Self::PerfEvent(p) => p.fd(),
  381. Self::RawTracePoint(p) => p.fd(),
  382. Self::Lsm(p) => p.fd(),
  383. Self::BtfTracePoint(p) => p.fd(),
  384. Self::FEntry(p) => p.fd(),
  385. Self::FExit(p) => p.fd(),
  386. Self::Extension(p) => p.fd(),
  387. Self::CgroupSockAddr(p) => p.fd(),
  388. Self::SkLookup(p) => p.fd(),
  389. Self::CgroupSock(p) => p.fd(),
  390. Self::CgroupDevice(p) => p.fd(),
  391. }
  392. }
  393. /// Returns information about a loaded program with the [`ProgramInfo`] structure.
  394. ///
  395. /// This information is populated at load time by the kernel and can be used
  396. /// to get kernel details for a given [`Program`].
  397. pub fn info(&self) -> Result<ProgramInfo, ProgramError> {
  398. match self {
  399. Self::KProbe(p) => p.info(),
  400. Self::UProbe(p) => p.info(),
  401. Self::TracePoint(p) => p.info(),
  402. Self::SocketFilter(p) => p.info(),
  403. Self::Xdp(p) => p.info(),
  404. Self::SkMsg(p) => p.info(),
  405. Self::SkSkb(p) => p.info(),
  406. Self::SockOps(p) => p.info(),
  407. Self::SchedClassifier(p) => p.info(),
  408. Self::CgroupSkb(p) => p.info(),
  409. Self::CgroupSysctl(p) => p.info(),
  410. Self::CgroupSockopt(p) => p.info(),
  411. Self::LircMode2(p) => p.info(),
  412. Self::PerfEvent(p) => p.info(),
  413. Self::RawTracePoint(p) => p.info(),
  414. Self::Lsm(p) => p.info(),
  415. Self::BtfTracePoint(p) => p.info(),
  416. Self::FEntry(p) => p.info(),
  417. Self::FExit(p) => p.info(),
  418. Self::Extension(p) => p.info(),
  419. Self::CgroupSockAddr(p) => p.info(),
  420. Self::SkLookup(p) => p.info(),
  421. Self::CgroupSock(p) => p.info(),
  422. Self::CgroupDevice(p) => p.info(),
  423. }
  424. }
  425. }
  426. #[derive(Debug)]
  427. pub(crate) struct ProgramData<T: Link> {
  428. pub(crate) name: Option<String>,
  429. pub(crate) obj: Option<(obj::Program, obj::Function)>,
  430. pub(crate) fd: Option<ProgramFd>,
  431. pub(crate) links: LinkMap<T>,
  432. pub(crate) expected_attach_type: Option<bpf_attach_type>,
  433. pub(crate) attach_btf_obj_fd: Option<crate::MockableFd>,
  434. pub(crate) attach_btf_id: Option<u32>,
  435. pub(crate) attach_prog_fd: Option<ProgramFd>,
  436. pub(crate) btf_fd: Option<Arc<crate::MockableFd>>,
  437. pub(crate) verifier_log_level: VerifierLogLevel,
  438. pub(crate) path: Option<PathBuf>,
  439. pub(crate) flags: u32,
  440. }
  441. impl<T: Link> ProgramData<T> {
  442. pub(crate) fn new(
  443. name: Option<String>,
  444. obj: (obj::Program, obj::Function),
  445. btf_fd: Option<Arc<crate::MockableFd>>,
  446. verifier_log_level: VerifierLogLevel,
  447. ) -> Self {
  448. Self {
  449. name,
  450. obj: Some(obj),
  451. fd: None,
  452. links: LinkMap::new(),
  453. expected_attach_type: None,
  454. attach_btf_obj_fd: None,
  455. attach_btf_id: None,
  456. attach_prog_fd: None,
  457. btf_fd,
  458. verifier_log_level,
  459. path: None,
  460. flags: 0,
  461. }
  462. }
  463. pub(crate) fn from_bpf_prog_info(
  464. name: Option<String>,
  465. fd: crate::MockableFd,
  466. path: &Path,
  467. info: bpf_prog_info,
  468. verifier_log_level: VerifierLogLevel,
  469. ) -> Result<Self, ProgramError> {
  470. let attach_btf_id = if info.attach_btf_id > 0 {
  471. Some(info.attach_btf_id)
  472. } else {
  473. None
  474. };
  475. let attach_btf_obj_fd = (info.attach_btf_obj_id != 0)
  476. .then(|| bpf_btf_get_fd_by_id(info.attach_btf_obj_id))
  477. .transpose()?;
  478. Ok(Self {
  479. name,
  480. obj: None,
  481. fd: Some(ProgramFd(fd)),
  482. links: LinkMap::new(),
  483. expected_attach_type: None,
  484. attach_btf_obj_fd,
  485. attach_btf_id,
  486. attach_prog_fd: None,
  487. btf_fd: None,
  488. verifier_log_level,
  489. path: Some(path.to_path_buf()),
  490. flags: 0,
  491. })
  492. }
  493. pub(crate) fn from_pinned_path<P: AsRef<Path>>(
  494. path: P,
  495. verifier_log_level: VerifierLogLevel,
  496. ) -> Result<Self, ProgramError> {
  497. use std::os::unix::ffi::OsStrExt as _;
  498. // TODO: avoid this unwrap by adding a new error variant.
  499. let path_string = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();
  500. let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError {
  501. call: "bpf_obj_get",
  502. io_error,
  503. })?;
  504. let info = ProgramInfo::new_from_fd(fd.as_fd())?;
  505. let name = info.name_as_str().map(|s| s.to_string());
  506. Self::from_bpf_prog_info(name, fd, path.as_ref(), info.0, verifier_log_level)
  507. }
  508. }
  509. impl<T: Link> ProgramData<T> {
  510. fn fd(&self) -> Result<&ProgramFd, ProgramError> {
  511. self.fd.as_ref().ok_or(ProgramError::NotLoaded)
  512. }
  513. pub(crate) fn take_link(&mut self, link_id: T::Id) -> Result<T, ProgramError> {
  514. self.links.forget(link_id)
  515. }
  516. }
  517. fn unload_program<T: Link>(data: &mut ProgramData<T>) -> Result<(), ProgramError> {
  518. data.links.remove_all()?;
  519. data.fd
  520. .take()
  521. .ok_or(ProgramError::NotLoaded)
  522. .map(|ProgramFd { .. }| ())
  523. }
  524. fn pin_program<T: Link, P: AsRef<Path>>(data: &ProgramData<T>, path: P) -> Result<(), PinError> {
  525. use std::os::unix::ffi::OsStrExt as _;
  526. let fd = data.fd.as_ref().ok_or(PinError::NoFd {
  527. name: data
  528. .name
  529. .as_deref()
  530. .unwrap_or("<unknown program>")
  531. .to_string(),
  532. })?;
  533. let path = path.as_ref();
  534. let path_string =
  535. CString::new(path.as_os_str().as_bytes()).map_err(|error| PinError::InvalidPinPath {
  536. path: path.into(),
  537. error,
  538. })?;
  539. bpf_pin_object(fd.as_fd(), &path_string).map_err(|(_, io_error)| SyscallError {
  540. call: "BPF_OBJ_PIN",
  541. io_error,
  542. })?;
  543. Ok(())
  544. }
  545. fn load_program<T: Link>(
  546. prog_type: bpf_prog_type,
  547. data: &mut ProgramData<T>,
  548. ) -> Result<(), ProgramError> {
  549. let ProgramData {
  550. name,
  551. obj,
  552. fd,
  553. links: _,
  554. expected_attach_type,
  555. attach_btf_obj_fd,
  556. attach_btf_id,
  557. attach_prog_fd,
  558. btf_fd,
  559. verifier_log_level,
  560. path: _,
  561. flags,
  562. } = data;
  563. if fd.is_some() {
  564. return Err(ProgramError::AlreadyLoaded);
  565. }
  566. if obj.is_none() {
  567. // This program was loaded from a pin in bpffs
  568. return Err(ProgramError::AlreadyLoaded);
  569. }
  570. let obj = obj.as_ref().unwrap();
  571. let (
  572. obj::Program {
  573. license,
  574. kernel_version,
  575. ..
  576. },
  577. obj::Function {
  578. instructions,
  579. func_info,
  580. line_info,
  581. func_info_rec_size,
  582. line_info_rec_size,
  583. ..
  584. },
  585. ) = obj;
  586. let target_kernel_version =
  587. kernel_version.unwrap_or_else(|| KernelVersion::current().unwrap().code());
  588. let prog_name = if let Some(name) = name {
  589. let mut name = name.clone();
  590. if name.len() > 15 {
  591. name.truncate(15);
  592. }
  593. let prog_name = CString::new(name.clone())
  594. .map_err(|_| ProgramError::InvalidName { name: name.clone() })?;
  595. Some(prog_name)
  596. } else {
  597. None
  598. };
  599. let attr = EbpfLoadProgramAttrs {
  600. name: prog_name,
  601. ty: prog_type,
  602. insns: instructions,
  603. license,
  604. kernel_version: target_kernel_version,
  605. expected_attach_type: *expected_attach_type,
  606. prog_btf_fd: btf_fd.as_ref().map(|f| f.as_fd()),
  607. attach_btf_obj_fd: attach_btf_obj_fd.as_ref().map(|fd| fd.as_fd()),
  608. attach_btf_id: *attach_btf_id,
  609. attach_prog_fd: attach_prog_fd.as_ref().map(|fd| fd.as_fd()),
  610. func_info_rec_size: *func_info_rec_size,
  611. func_info: func_info.clone(),
  612. line_info_rec_size: *line_info_rec_size,
  613. line_info: line_info.clone(),
  614. flags: *flags,
  615. };
  616. let (ret, verifier_log) = retry_with_verifier_logs(10, |logger| {
  617. bpf_load_program(&attr, logger, *verifier_log_level)
  618. });
  619. match ret {
  620. Ok(prog_fd) => {
  621. *fd = Some(ProgramFd(prog_fd));
  622. Ok(())
  623. }
  624. Err((_, io_error)) => Err(ProgramError::LoadError {
  625. io_error,
  626. verifier_log,
  627. }),
  628. }
  629. }
  630. pub(crate) fn query(
  631. target: ProgQueryTarget<'_>,
  632. attach_type: bpf_attach_type,
  633. query_flags: u32,
  634. attach_flags: &mut Option<u32>,
  635. ) -> Result<(u64, Vec<u32>), ProgramError> {
  636. let mut prog_ids = vec![0u32; 64];
  637. let mut prog_cnt = prog_ids.len() as u32;
  638. let mut revision = 0;
  639. let mut retries = 0;
  640. loop {
  641. match bpf_prog_query(
  642. &target,
  643. attach_type,
  644. query_flags,
  645. attach_flags.as_mut(),
  646. &mut prog_ids,
  647. &mut prog_cnt,
  648. &mut revision,
  649. ) {
  650. Ok(_) => {
  651. prog_ids.resize(prog_cnt as usize, 0);
  652. return Ok((revision, prog_ids));
  653. }
  654. Err((_, io_error)) => {
  655. if retries == 0 && io_error.raw_os_error() == Some(ENOSPC) {
  656. prog_ids.resize(prog_cnt as usize, 0);
  657. retries += 1;
  658. } else {
  659. return Err(SyscallError {
  660. call: "bpf_prog_query",
  661. io_error,
  662. }
  663. .into());
  664. }
  665. }
  666. }
  667. }
  668. }
  669. macro_rules! impl_program_unload {
  670. ($($struct_name:ident),+ $(,)?) => {
  671. $(
  672. impl $struct_name {
  673. /// Unloads the program from the kernel.
  674. ///
  675. /// Links will be detached before unloading the program. Note
  676. /// that owned links obtained using `take_link()` will not be
  677. /// detached.
  678. pub fn unload(&mut self) -> Result<(), ProgramError> {
  679. unload_program(&mut self.data)
  680. }
  681. }
  682. impl Drop for $struct_name {
  683. fn drop(&mut self) {
  684. let _ = self.unload();
  685. }
  686. }
  687. )+
  688. }
  689. }
  690. impl_program_unload!(
  691. KProbe,
  692. UProbe,
  693. TracePoint,
  694. SocketFilter,
  695. Xdp,
  696. SkMsg,
  697. SkSkb,
  698. SchedClassifier,
  699. CgroupSkb,
  700. CgroupSysctl,
  701. CgroupSockopt,
  702. LircMode2,
  703. PerfEvent,
  704. Lsm,
  705. RawTracePoint,
  706. BtfTracePoint,
  707. FEntry,
  708. FExit,
  709. Extension,
  710. CgroupSockAddr,
  711. SkLookup,
  712. SockOps,
  713. CgroupSock,
  714. CgroupDevice,
  715. );
  716. macro_rules! impl_fd {
  717. ($($struct_name:ident),+ $(,)?) => {
  718. $(
  719. impl $struct_name {
  720. /// Returns the file descriptor of this Program.
  721. pub fn fd(&self) -> Result<&ProgramFd, ProgramError> {
  722. self.data.fd()
  723. }
  724. }
  725. )+
  726. }
  727. }
  728. impl_fd!(
  729. KProbe,
  730. UProbe,
  731. TracePoint,
  732. SocketFilter,
  733. Xdp,
  734. SkMsg,
  735. SkSkb,
  736. SchedClassifier,
  737. CgroupSkb,
  738. CgroupSysctl,
  739. CgroupSockopt,
  740. LircMode2,
  741. PerfEvent,
  742. Lsm,
  743. RawTracePoint,
  744. BtfTracePoint,
  745. FEntry,
  746. FExit,
  747. Extension,
  748. CgroupSockAddr,
  749. SkLookup,
  750. SockOps,
  751. CgroupSock,
  752. CgroupDevice,
  753. );
  754. /// Trait implemented by the [`Program`] types which support the kernel's
  755. /// [generic multi-prog API](https://github.com/torvalds/linux/commit/053c8e1f235dc3f69d13375b32f4209228e1cb96).
  756. ///
  757. /// # Minimum kernel version
  758. ///
  759. /// The minimum kernel version required to use this feature is 6.6.0.
  760. pub trait MultiProgram {
  761. /// Borrows the file descriptor.
  762. fn fd(&self) -> Result<BorrowedFd<'_>, ProgramError>;
  763. }
  764. macro_rules! impl_multiprog_fd {
  765. ($($struct_name:ident),+ $(,)?) => {
  766. $(
  767. impl MultiProgram for $struct_name {
  768. fn fd(&self) -> Result<BorrowedFd<'_>, ProgramError> {
  769. Ok(self.fd()?.as_fd())
  770. }
  771. }
  772. )+
  773. }
  774. }
  775. impl_multiprog_fd!(SchedClassifier);
  776. /// Trait implemented by the [`Link`] types which support the kernel's
  777. /// [generic multi-prog API](https://github.com/torvalds/linux/commit/053c8e1f235dc3f69d13375b32f4209228e1cb96).
  778. ///
  779. /// # Minimum kernel version
  780. ///
  781. /// The minimum kernel version required to use this feature is 6.6.0.
  782. pub trait MultiProgLink {
  783. /// Borrows the file descriptor.
  784. fn fd(&self) -> Result<BorrowedFd<'_>, LinkError>;
  785. }
  786. macro_rules! impl_multiproglink_fd {
  787. ($($struct_name:ident),+ $(,)?) => {
  788. $(
  789. impl MultiProgLink for $struct_name {
  790. fn fd(&self) -> Result<BorrowedFd<'_>, LinkError> {
  791. let link: &FdLink = self.try_into()?;
  792. Ok(link.fd.as_fd())
  793. }
  794. }
  795. )+
  796. }
  797. }
  798. impl_multiproglink_fd!(SchedClassifierLink);
  799. macro_rules! impl_program_pin{
  800. ($($struct_name:ident),+ $(,)?) => {
  801. $(
  802. impl $struct_name {
  803. /// Pins the program to a BPF filesystem.
  804. ///
  805. /// When a BPF object is pinned to a BPF filesystem it will remain loaded after
  806. /// Aya has unloaded the program.
  807. /// To remove the program, the file on the BPF filesystem must be removed.
  808. /// Any directories in the the path provided should have been created by the caller.
  809. pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<(), PinError> {
  810. self.data.path = Some(path.as_ref().to_path_buf());
  811. pin_program(&self.data, path)
  812. }
  813. /// Removes the pinned link from the filesystem.
  814. pub fn unpin(mut self) -> Result<(), io::Error> {
  815. if let Some(path) = self.data.path.take() {
  816. std::fs::remove_file(path)?;
  817. }
  818. Ok(())
  819. }
  820. }
  821. )+
  822. }
  823. }
  824. impl_program_pin!(
  825. KProbe,
  826. UProbe,
  827. TracePoint,
  828. SocketFilter,
  829. Xdp,
  830. SkMsg,
  831. SkSkb,
  832. SchedClassifier,
  833. CgroupSkb,
  834. CgroupSysctl,
  835. CgroupSockopt,
  836. LircMode2,
  837. PerfEvent,
  838. Lsm,
  839. RawTracePoint,
  840. BtfTracePoint,
  841. FEntry,
  842. FExit,
  843. Extension,
  844. CgroupSockAddr,
  845. SkLookup,
  846. SockOps,
  847. CgroupSock,
  848. CgroupDevice,
  849. );
  850. macro_rules! impl_from_pin {
  851. ($($struct_name:ident),+ $(,)?) => {
  852. $(
  853. impl $struct_name {
  854. /// Creates a program from a pinned entry on a bpffs.
  855. ///
  856. /// Existing links will not be populated. To work with existing links you should use [`crate::programs::links::PinnedLink`].
  857. ///
  858. /// On drop, any managed links are detached and the program is unloaded. This will not result in
  859. /// the program being unloaded from the kernel if it is still pinned.
  860. pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<Self, ProgramError> {
  861. let data = ProgramData::from_pinned_path(path, VerifierLogLevel::default())?;
  862. Ok(Self { data })
  863. }
  864. }
  865. )+
  866. }
  867. }
  868. // Use impl_from_pin if the program doesn't require additional data
  869. impl_from_pin!(
  870. TracePoint,
  871. SocketFilter,
  872. SkMsg,
  873. CgroupSysctl,
  874. LircMode2,
  875. PerfEvent,
  876. Lsm,
  877. RawTracePoint,
  878. BtfTracePoint,
  879. FEntry,
  880. FExit,
  881. Extension,
  882. SkLookup,
  883. SockOps,
  884. CgroupDevice,
  885. );
  886. macro_rules! impl_try_from_program {
  887. ($($ty:ident),+ $(,)?) => {
  888. $(
  889. impl<'a> TryFrom<&'a Program> for &'a $ty {
  890. type Error = ProgramError;
  891. fn try_from(program: &'a Program) -> Result<&'a $ty, ProgramError> {
  892. match program {
  893. Program::$ty(p) => Ok(p),
  894. _ => Err(ProgramError::UnexpectedProgramType),
  895. }
  896. }
  897. }
  898. impl<'a> TryFrom<&'a mut Program> for &'a mut $ty {
  899. type Error = ProgramError;
  900. fn try_from(program: &'a mut Program) -> Result<&'a mut $ty, ProgramError> {
  901. match program {
  902. Program::$ty(p) => Ok(p),
  903. _ => Err(ProgramError::UnexpectedProgramType),
  904. }
  905. }
  906. }
  907. )+
  908. }
  909. }
  910. impl_try_from_program!(
  911. KProbe,
  912. UProbe,
  913. TracePoint,
  914. SocketFilter,
  915. Xdp,
  916. SkMsg,
  917. SkSkb,
  918. SockOps,
  919. SchedClassifier,
  920. CgroupSkb,
  921. CgroupSysctl,
  922. CgroupSockopt,
  923. LircMode2,
  924. PerfEvent,
  925. Lsm,
  926. RawTracePoint,
  927. BtfTracePoint,
  928. FEntry,
  929. FExit,
  930. Extension,
  931. CgroupSockAddr,
  932. SkLookup,
  933. CgroupSock,
  934. CgroupDevice,
  935. );
  936. impl_info!(
  937. KProbe,
  938. UProbe,
  939. TracePoint,
  940. SocketFilter,
  941. Xdp,
  942. SkMsg,
  943. SkSkb,
  944. SchedClassifier,
  945. CgroupSkb,
  946. CgroupSysctl,
  947. CgroupSockopt,
  948. LircMode2,
  949. PerfEvent,
  950. Lsm,
  951. RawTracePoint,
  952. BtfTracePoint,
  953. FEntry,
  954. FExit,
  955. Extension,
  956. CgroupSockAddr,
  957. SkLookup,
  958. SockOps,
  959. CgroupSock,
  960. CgroupDevice,
  961. );
  962. // TODO(https://github.com/aya-rs/aya/issues/645): this API is currently used in tests. Stabilize
  963. // and remove doc(hidden).
  964. #[doc(hidden)]
  965. pub fn loaded_links() -> impl Iterator<Item = Result<bpf_link_info, ProgramError>> {
  966. iter_link_ids()
  967. .map(|id| {
  968. let id = id?;
  969. bpf_link_get_fd_by_id(id)
  970. })
  971. .map(|fd| {
  972. let fd = fd?;
  973. bpf_link_get_info_by_fd(fd.as_fd())
  974. })
  975. .map(|result| result.map_err(Into::into))
  976. }