bpf.rs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  1. use core::{ffi::c_int, mem, slice};
  2. use std::{
  3. borrow::{Cow, ToOwned},
  4. collections::{HashMap, HashSet},
  5. fs, io,
  6. os::fd::{AsFd, AsRawFd, OwnedFd},
  7. path::{Path, PathBuf},
  8. string::String,
  9. sync::Arc,
  10. vec::Vec,
  11. };
  12. use aya_obj::{
  13. btf::{Btf, BtfError, BtfFeatures, BtfRelocationError},
  14. generated::{bpf_map_type::*, *},
  15. maps::PinningType,
  16. relocation::EbpfRelocationError,
  17. EbpfSectionKind, Features, Object, ParseError, ProgramSection,
  18. };
  19. use log::{debug, warn};
  20. use thiserror::Error;
  21. use crate::{
  22. maps::{Map, MapData, MapError},
  23. programs::{
  24. extension::Extension, kprobe::KProbe, probe::ProbeKind, Program, ProgramData, ProgramError,
  25. },
  26. sys::*,
  27. util::{possible_cpus, POSSIBLE_CPUS},
  28. };
  29. pub(crate) const BPF_OBJ_NAME_LEN: usize = 16;
  30. pub(crate) const PERF_EVENT_IOC_ENABLE: c_int = AYA_PERF_EVENT_IOC_ENABLE;
  31. pub(crate) const PERF_EVENT_IOC_DISABLE: c_int = AYA_PERF_EVENT_IOC_DISABLE;
  32. pub(crate) const PERF_EVENT_IOC_SET_BPF: c_int = AYA_PERF_EVENT_IOC_SET_BPF;
  33. lazy_static::lazy_static! {
  34. pub(crate) static ref FEATURES: Features = detect_features();
  35. }
  36. fn detect_features() -> Features {
  37. let btf = if is_btf_supported() {
  38. Some(BtfFeatures::new(
  39. is_btf_func_supported(),
  40. is_btf_func_global_supported(),
  41. is_btf_datasec_supported(),
  42. is_btf_float_supported(),
  43. is_btf_decl_tag_supported(),
  44. is_btf_type_tag_supported(),
  45. is_btf_enum64_supported(),
  46. ))
  47. } else {
  48. None
  49. };
  50. let f = Features::new(
  51. is_prog_name_supported(),
  52. is_probe_read_kernel_supported(), // todo! kernel should support helper probe_read_kernel
  53. false,
  54. is_bpf_global_data_supported(),
  55. is_bpf_cookie_supported(), // todo! kernel should support helper bpf_get_attach_cookie
  56. is_prog_id_supported(BPF_MAP_TYPE_CPUMAP),
  57. is_prog_id_supported(BPF_MAP_TYPE_DEVMAP),
  58. btf,
  59. );
  60. info!("BPF Feature Detection: {:#?}", f);
  61. f
  62. }
  63. /// Returns a reference to the detected BPF features.
  64. pub fn features() -> &'static Features {
  65. &FEATURES
  66. }
  67. /// Builder style API for advanced loading of eBPF programs.
  68. ///
  69. /// Loading eBPF code involves a few steps, including loading maps and applying
  70. /// relocations. You can use `EbpfLoader` to customize some of the loading
  71. /// options.
  72. ///
  73. /// # Examples
  74. ///
  75. /// ```no_run
  76. /// use aya::{EbpfLoader, Btf};
  77. /// use std::fs;
  78. ///
  79. /// let bpf = EbpfLoader::new()
  80. /// // load the BTF data from /sys/kernel/btf/vmlinux
  81. /// .btf(Btf::from_sys_fs().ok().as_ref())
  82. /// // load pinned maps from /sys/fs/bpf/my-program
  83. /// .map_pin_path("/sys/fs/bpf/my-program")
  84. /// // finally load the code
  85. /// .load_file("file.o")?;
  86. /// # Ok::<(), aya::EbpfError>(())
  87. /// ```
  88. #[derive(Debug)]
  89. pub struct EbpfLoader<'a> {
  90. btf: Option<Cow<'a, Btf>>,
  91. map_pin_path: Option<PathBuf>,
  92. globals: std::collections::HashMap<&'a str, (&'a [u8], bool)>,
  93. max_entries: HashMap<&'a str, u32>,
  94. extensions: HashSet<&'a str>,
  95. verifier_log_level: VerifierLogLevel,
  96. allow_unsupported_maps: bool,
  97. }
  98. bitflags::bitflags! {
  99. /// Used to set the verifier log level flags in [EbpfLoader](EbpfLoader::verifier_log_level()).
  100. #[derive(Clone, Copy, Debug)]
  101. pub struct VerifierLogLevel: u32 {
  102. /// Sets no verifier logging.
  103. const DISABLE = 0;
  104. /// Enables debug verifier logging.
  105. const DEBUG = 1;
  106. /// Enables verbose verifier logging.
  107. const VERBOSE = 2 | Self::DEBUG.bits();
  108. /// Enables verifier stats.
  109. const STATS = 4;
  110. }
  111. }
  112. impl Default for VerifierLogLevel {
  113. fn default() -> Self {
  114. Self::DEBUG | Self::STATS
  115. }
  116. }
  117. impl<'a> Default for EbpfLoader<'a> {
  118. fn default() -> Self {
  119. Self::new()
  120. }
  121. }
  122. impl<'a> EbpfLoader<'a> {
  123. /// Creates a new loader instance.
  124. pub fn new() -> Self {
  125. Self {
  126. btf: None,
  127. map_pin_path: None,
  128. globals: std::collections::HashMap::new(),
  129. max_entries: HashMap::new(),
  130. extensions: HashSet::new(),
  131. verifier_log_level: VerifierLogLevel::default(),
  132. allow_unsupported_maps: false,
  133. }
  134. }
  135. /// Sets the target [BTF](Btf) info.
  136. ///
  137. /// The loader defaults to loading `BTF` info using [Btf::from_sys_fs].
  138. /// Use this method if you want to load `BTF` from a custom location or
  139. /// pass `None` to disable `BTF` relocations entirely.
  140. /// # Example
  141. ///
  142. /// ```no_run
  143. /// use aya::{EbpfLoader, Btf, Endianness};
  144. ///
  145. /// let bpf = EbpfLoader::new()
  146. /// // load the BTF data from a custom location
  147. /// .btf(Btf::parse_file("/custom_btf_file", Endianness::default()).ok().as_ref())
  148. /// .load_file("file.o")?;
  149. ///
  150. /// # Ok::<(), aya::EbpfError>(())
  151. /// ```
  152. pub fn btf(&mut self, btf: Option<&'a Btf>) -> &mut Self {
  153. self.btf = btf.map(Cow::Borrowed);
  154. self
  155. }
  156. /// Allows programs containing unsupported maps to be loaded.
  157. ///
  158. /// By default programs containing unsupported maps will fail to load. This
  159. /// method can be used to configure the loader so that unsupported maps will
  160. /// be loaded, but won't be accessible from userspace. Can be useful when
  161. /// using unsupported maps that are only accessed from eBPF code and don't
  162. /// require any userspace interaction.
  163. ///
  164. /// # Example
  165. ///
  166. /// ```no_run
  167. /// use aya::EbpfLoader;
  168. ///
  169. /// let bpf = EbpfLoader::new()
  170. /// .allow_unsupported_maps()
  171. /// .load_file("file.o")?;
  172. /// # Ok::<(), aya::EbpfError>(())
  173. /// ```
  174. ///
  175. pub fn allow_unsupported_maps(&mut self) -> &mut Self {
  176. self.allow_unsupported_maps = true;
  177. self
  178. }
  179. /// Sets the base directory path for pinned maps.
  180. ///
  181. /// Pinned maps will be loaded from `path/MAP_NAME`.
  182. /// The caller is responsible for ensuring the directory exists.
  183. ///
  184. /// # Example
  185. ///
  186. /// ```no_run
  187. /// use aya::EbpfLoader;
  188. ///
  189. /// let bpf = EbpfLoader::new()
  190. /// .map_pin_path("/sys/fs/bpf/my-program")
  191. /// .load_file("file.o")?;
  192. /// # Ok::<(), aya::EbpfError>(())
  193. /// ```
  194. ///
  195. pub fn map_pin_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
  196. self.map_pin_path = Some(path.as_ref().to_owned());
  197. self
  198. }
  199. /// Sets the value of a global variable.
  200. ///
  201. /// If the `must_exist` argument is `true`, [`EbpfLoader::load`] will fail with [`ParseError::SymbolNotFound`] if the loaded object code does not contain the variable.
  202. ///
  203. /// From Rust eBPF, a global variable can be defined as follows:
  204. ///
  205. /// ```no_run
  206. /// #[no_mangle]
  207. /// static VERSION: i32 = 0;
  208. /// ```
  209. ///
  210. /// Then it can be accessed using `core::ptr::read_volatile`:
  211. ///
  212. /// ```no_run
  213. /// # #[no_mangle]
  214. /// # static VERSION: i32 = 0;
  215. /// # unsafe fn try_test() {
  216. /// let version = core::ptr::read_volatile(&VERSION);
  217. /// # }
  218. /// ```
  219. ///
  220. /// The type of a global variable must be `Pod` (plain old data), for instance `u8`, `u32` and
  221. /// all other primitive types. You may use custom types as well, but you must ensure that those
  222. /// types are `#[repr(C)]` and only contain other `Pod` types.
  223. ///
  224. /// From C eBPF, you would annotate a global variable as `volatile const`.
  225. ///
  226. /// # Example
  227. ///
  228. /// ```no_run
  229. /// use aya::EbpfLoader;
  230. ///
  231. /// let bpf = EbpfLoader::new()
  232. /// .set_global("VERSION", &2, true)
  233. /// .set_global("PIDS", &[1234u16, 5678], true)
  234. /// .load_file("file.o")?;
  235. /// # Ok::<(), aya::EbpfError>(())
  236. /// ```
  237. ///
  238. pub fn set_global<T: Into<GlobalData<'a>>>(
  239. &mut self,
  240. name: &'a str,
  241. value: T,
  242. must_exist: bool,
  243. ) -> &mut Self {
  244. self.globals.insert(name, (value.into().bytes, must_exist));
  245. self
  246. }
  247. /// Set the max_entries for specified map.
  248. ///
  249. /// Overwrite the value of max_entries of the map that matches
  250. /// the provided name before the map is created.
  251. ///
  252. /// # Example
  253. ///
  254. /// ```no_run
  255. /// use aya::EbpfLoader;
  256. ///
  257. /// let bpf = EbpfLoader::new()
  258. /// .set_max_entries("map", 64)
  259. /// .load_file("file.o")?;
  260. /// # Ok::<(), aya::EbpfError>(())
  261. /// ```
  262. ///
  263. pub fn set_max_entries(&mut self, name: &'a str, size: u32) -> &mut Self {
  264. self.max_entries.insert(name, size);
  265. self
  266. }
  267. /// Treat the provided program as an [`Extension`]
  268. ///
  269. /// When attempting to load the program with the provided `name`
  270. /// the program type is forced to be ] [`Extension`] and is not
  271. /// inferred from the ELF section name.
  272. ///
  273. /// # Example
  274. ///
  275. /// ```no_run
  276. /// use aya::EbpfLoader;
  277. ///
  278. /// let bpf = EbpfLoader::new()
  279. /// .extension("myfunc")
  280. /// .load_file("file.o")?;
  281. /// # Ok::<(), aya::EbpfError>(())
  282. /// ```
  283. ///
  284. pub fn extension(&mut self, name: &'a str) -> &mut Self {
  285. self.extensions.insert(name);
  286. self
  287. }
  288. /// Sets BPF verifier log level.
  289. ///
  290. /// # Example
  291. ///
  292. /// ```no_run
  293. /// use aya::{EbpfLoader, VerifierLogLevel};
  294. ///
  295. /// let bpf = EbpfLoader::new()
  296. /// .verifier_log_level(VerifierLogLevel::VERBOSE | VerifierLogLevel::STATS)
  297. /// .load_file("file.o")?;
  298. /// # Ok::<(), aya::EbpfError>(())
  299. /// ```
  300. ///
  301. pub fn verifier_log_level(&mut self, level: VerifierLogLevel) -> &mut Self {
  302. self.verifier_log_level = level;
  303. self
  304. }
  305. /// Loads eBPF bytecode from a file.
  306. ///
  307. /// # Examples
  308. ///
  309. /// ```no_run
  310. /// use aya::EbpfLoader;
  311. ///
  312. /// let bpf = EbpfLoader::new().load_file("file.o")?;
  313. /// # Ok::<(), aya::EbpfError>(())
  314. /// ```
  315. pub fn load_file<P: AsRef<Path>>(&mut self, path: P) -> Result<Ebpf, EbpfError> {
  316. let path = path.as_ref();
  317. self.load(&fs::read(path).map_err(|error| EbpfError::FileError {
  318. path: path.to_owned(),
  319. error,
  320. })?)
  321. }
  322. /// Loads eBPF bytecode from a buffer.
  323. ///
  324. /// # Examples
  325. ///
  326. /// ```no_run
  327. /// use aya::EbpfLoader;
  328. /// use std::fs;
  329. ///
  330. /// let data = fs::read("file.o").unwrap();
  331. /// let bpf = EbpfLoader::new().load(&data)?;
  332. /// # Ok::<(), aya::EbpfError>(())
  333. /// ```
  334. pub fn load(&mut self, data: &[u8]) -> Result<Ebpf, EbpfError> {
  335. let Self {
  336. btf,
  337. map_pin_path: _,
  338. globals,
  339. max_entries,
  340. extensions,
  341. verifier_log_level,
  342. allow_unsupported_maps,
  343. } = self;
  344. let mut obj = Object::parse(data)?;
  345. obj.patch_map_data(globals.clone())?;
  346. let btf_fd = if let Some(features) = &FEATURES.btf() {
  347. if let Some(btf) = obj.fixup_and_sanitize_btf(features)? {
  348. match load_btf(btf.to_bytes(), *verifier_log_level) {
  349. Ok(btf_fd) => Some(Arc::new(btf_fd)),
  350. // Only report an error here if the BTF is truly needed, otherwise proceed without.
  351. Err(err) => {
  352. for program in obj.programs.values() {
  353. match program.section {
  354. ProgramSection::Extension
  355. | ProgramSection::FEntry { sleepable: _ }
  356. | ProgramSection::FExit { sleepable: _ }
  357. | ProgramSection::Lsm { sleepable: _ }
  358. | ProgramSection::BtfTracePoint => {
  359. return Err(EbpfError::BtfError(err))
  360. }
  361. ProgramSection::KRetProbe
  362. | ProgramSection::KProbe
  363. | ProgramSection::UProbe { sleepable: _ }
  364. | ProgramSection::URetProbe { sleepable: _ }
  365. | ProgramSection::TracePoint
  366. | ProgramSection::SocketFilter
  367. | ProgramSection::Xdp {
  368. frags: _,
  369. attach_type: _,
  370. }
  371. | ProgramSection::SkMsg
  372. | ProgramSection::SkSkbStreamParser
  373. | ProgramSection::SkSkbStreamVerdict
  374. | ProgramSection::SockOps
  375. | ProgramSection::SchedClassifier
  376. | ProgramSection::CgroupSkb
  377. | ProgramSection::CgroupSkbIngress
  378. | ProgramSection::CgroupSkbEgress
  379. | ProgramSection::CgroupSockAddr { attach_type: _ }
  380. | ProgramSection::CgroupSysctl
  381. | ProgramSection::CgroupSockopt { attach_type: _ }
  382. | ProgramSection::LircMode2
  383. | ProgramSection::PerfEvent
  384. | ProgramSection::RawTracePoint
  385. | ProgramSection::SkLookup
  386. | ProgramSection::CgroupSock { attach_type: _ }
  387. | ProgramSection::CgroupDevice => {}
  388. }
  389. }
  390. warn!("Object BTF couldn't be loaded in the kernel: {err}");
  391. None
  392. }
  393. }
  394. } else {
  395. None
  396. }
  397. } else {
  398. warn!("BTF is not supported in the kernel");
  399. None
  400. };
  401. if let Some(btf) = &btf {
  402. obj.relocate_btf(btf)?;
  403. }
  404. let mut maps = HashMap::new();
  405. for (name, mut obj) in obj.maps.drain() {
  406. if let (false, EbpfSectionKind::Bss | EbpfSectionKind::Data | EbpfSectionKind::Rodata) =
  407. (FEATURES.bpf_global_data(), obj.section_kind())
  408. {
  409. continue;
  410. }
  411. let num_cpus = || -> Result<u32, EbpfError> {
  412. Ok(possible_cpus()
  413. .map_err(|error| EbpfError::FileError {
  414. path: PathBuf::from(POSSIBLE_CPUS),
  415. error,
  416. })?
  417. .len() as u32)
  418. };
  419. let map_type: bpf_map_type = obj.map_type().try_into().map_err(MapError::from)?;
  420. // if user provided a max_entries override, use that, otherwise use the value from the object
  421. if let Some(max_entries) = max_entries_override(
  422. map_type,
  423. max_entries.get(name.as_str()).copied(),
  424. || obj.max_entries(),
  425. num_cpus,
  426. || page_size() as u32,
  427. )? {
  428. debug!("Overriding max_entries for map {name} to {max_entries}");
  429. obj.set_max_entries(max_entries)
  430. }
  431. match obj.map_type().try_into() {
  432. Ok(BPF_MAP_TYPE_CPUMAP) => {
  433. obj.set_value_size(if FEATURES.cpumap_prog_id() { 8 } else { 4 })
  434. }
  435. Ok(BPF_MAP_TYPE_DEVMAP | BPF_MAP_TYPE_DEVMAP_HASH) => {
  436. obj.set_value_size(if FEATURES.devmap_prog_id() { 8 } else { 4 })
  437. }
  438. _ => (),
  439. }
  440. let btf_fd = btf_fd.as_deref().map(|fd| fd.as_fd());
  441. let mut map = match obj.pinning() {
  442. PinningType::None => MapData::create(obj, &name, btf_fd)?,
  443. PinningType::ByName => {
  444. // pin maps in /sys/fs/bpf by default to align with libbpf
  445. // behavior https://github.com/libbpf/libbpf/blob/v1.2.2/src/libbpf.c#L2161.
  446. // let path = map_pin_path
  447. // .as_deref()
  448. // .unwrap_or_else(|| Path::new("/sys/fs/bpf"));
  449. //
  450. // MapData::create_pinned_by_name(path, obj, &name, btf_fd)?
  451. unimplemented!(
  452. "pin maps in /sys/fs/bpf by default to align with libbpf behavior"
  453. );
  454. }
  455. };
  456. map.finalize()?;
  457. maps.insert(name, map);
  458. }
  459. let text_sections = obj
  460. .functions
  461. .keys()
  462. .map(|(section_index, _)| *section_index)
  463. .collect();
  464. maps.iter()
  465. .map(|(s, data)| (s.as_str(), data.fd().as_fd().as_raw_fd(), data.obj()))
  466. .for_each(|(s, fd, obj)| {
  467. let x = obj.section_index();
  468. info!("section {s} fd {fd} section_index {x}");
  469. });
  470. obj.relocate_maps(
  471. maps.iter()
  472. .map(|(s, data)| (s.as_str(), data.fd().as_fd().as_raw_fd() as _, data.obj())),
  473. &text_sections,
  474. )?;
  475. obj.relocate_calls(&text_sections)?;
  476. obj.sanitize_functions(&FEATURES);
  477. let programs = obj
  478. .programs
  479. .drain()
  480. .map(|(name, prog_obj)| {
  481. let function_obj = obj.functions.get(&prog_obj.function_key()).unwrap().clone();
  482. let prog_name = if FEATURES.bpf_name() {
  483. Some(name.clone())
  484. } else {
  485. None
  486. };
  487. let section = prog_obj.section.clone();
  488. let obj = (prog_obj, function_obj);
  489. let btf_fd = btf_fd.clone();
  490. let program = if extensions.contains(name.as_str()) {
  491. Program::Extension(Extension {
  492. data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
  493. })
  494. } else {
  495. match &section {
  496. ProgramSection::KProbe => Program::KProbe(KProbe {
  497. data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
  498. kind: ProbeKind::KProbe,
  499. }),
  500. _ => {
  501. unimplemented!()
  502. }
  503. }
  504. };
  505. (name, program)
  506. })
  507. .collect();
  508. let maps = maps
  509. .drain()
  510. .map(parse_map)
  511. .collect::<Result<HashMap<String, Map>, EbpfError>>()?;
  512. if !*allow_unsupported_maps {
  513. maps.iter().try_for_each(|(_, x)| match x {
  514. Map::Unsupported(map) => Err(EbpfError::MapError(MapError::Unsupported {
  515. map_type: map.obj().map_type(),
  516. })),
  517. _ => Ok(()),
  518. })?;
  519. };
  520. Ok(Ebpf { maps, programs })
  521. }
  522. }
  523. fn parse_map(data: (String, MapData)) -> Result<(String, Map), EbpfError> {
  524. let (name, map) = data;
  525. let map_type = bpf_map_type::try_from(map.obj().map_type()).map_err(MapError::from)?;
  526. let map = match map_type {
  527. BPF_MAP_TYPE_ARRAY => Map::Array(map),
  528. BPF_MAP_TYPE_PERCPU_ARRAY => Map::PerCpuArray(map),
  529. BPF_MAP_TYPE_PROG_ARRAY => Map::ProgramArray(map),
  530. BPF_MAP_TYPE_HASH => Map::HashMap(map),
  531. BPF_MAP_TYPE_LRU_HASH => Map::LruHashMap(map),
  532. BPF_MAP_TYPE_PERCPU_HASH => Map::PerCpuHashMap(map),
  533. BPF_MAP_TYPE_LRU_PERCPU_HASH => Map::PerCpuLruHashMap(map),
  534. BPF_MAP_TYPE_PERF_EVENT_ARRAY => Map::PerfEventArray(map),
  535. BPF_MAP_TYPE_RINGBUF => Map::RingBuf(map),
  536. BPF_MAP_TYPE_SOCKHASH => Map::SockHash(map),
  537. BPF_MAP_TYPE_SOCKMAP => Map::SockMap(map),
  538. BPF_MAP_TYPE_BLOOM_FILTER => Map::BloomFilter(map),
  539. BPF_MAP_TYPE_LPM_TRIE => Map::LpmTrie(map),
  540. BPF_MAP_TYPE_STACK => Map::Stack(map),
  541. BPF_MAP_TYPE_STACK_TRACE => Map::StackTraceMap(map),
  542. BPF_MAP_TYPE_QUEUE => Map::Queue(map),
  543. BPF_MAP_TYPE_CPUMAP => Map::CpuMap(map),
  544. BPF_MAP_TYPE_DEVMAP => Map::DevMap(map),
  545. BPF_MAP_TYPE_DEVMAP_HASH => Map::DevMapHash(map),
  546. BPF_MAP_TYPE_XSKMAP => Map::XskMap(map),
  547. m => {
  548. warn!("The map {name} is of type {:#?} which is currently unsupported in Aya, use `allow_unsupported_maps()` to load it anyways", m);
  549. Map::Unsupported(map)
  550. }
  551. };
  552. Ok((name, map))
  553. }
  554. /// Computes the value which should be used to override the max_entries value of the map
  555. /// based on the user-provided override and the rules for that map type.
  556. fn max_entries_override(
  557. map_type: bpf_map_type,
  558. user_override: Option<u32>,
  559. current_value: impl Fn() -> u32,
  560. num_cpus: impl Fn() -> Result<u32, EbpfError>,
  561. page_size: impl Fn() -> u32,
  562. ) -> Result<Option<u32>, EbpfError> {
  563. let max_entries = || user_override.unwrap_or_else(&current_value);
  564. Ok(match map_type {
  565. BPF_MAP_TYPE_PERF_EVENT_ARRAY if max_entries() == 0 => Some(num_cpus()?),
  566. BPF_MAP_TYPE_RINGBUF => Some(adjust_to_page_size(max_entries(), page_size()))
  567. .filter(|adjusted| *adjusted != max_entries())
  568. .or(user_override),
  569. _ => user_override,
  570. })
  571. }
  572. // Adjusts the byte size of a RingBuf map to match a power-of-two multiple of the page size.
  573. //
  574. // This mirrors the logic used by libbpf.
  575. // See https://github.com/libbpf/libbpf/blob/ec6f716eda43/src/libbpf.c#L2461-L2463
  576. fn adjust_to_page_size(byte_size: u32, page_size: u32) -> u32 {
  577. // If the byte_size is zero, return zero and let the verifier reject the map
  578. // when it is loaded. This is the behavior of libbpf.
  579. if byte_size == 0 {
  580. return 0;
  581. }
  582. // TODO: Replace with primitive method when int_roundings (https://github.com/rust-lang/rust/issues/88581)
  583. // is stabilized.
  584. fn div_ceil(n: u32, rhs: u32) -> u32 {
  585. let d = n / rhs;
  586. let r = n % rhs;
  587. if r > 0 && rhs > 0 {
  588. d + 1
  589. } else {
  590. d
  591. }
  592. }
  593. let pages_needed = div_ceil(byte_size, page_size);
  594. page_size * pages_needed.next_power_of_two()
  595. }
  596. /// Try loading the BTF data into the kernel.
  597. ///
  598. /// The kernel will write error messages to the provided logger. User should provide enough capacity
  599. /// to store the error messages.
  600. fn load_btf(raw_btf: Vec<u8>, verifier_log_level: VerifierLogLevel) -> Result<OwnedFd, BtfError> {
  601. let (ret, verifier_log) = retry_with_verifier_logs(10, |logger| {
  602. bpf_load_btf(raw_btf.as_slice(), logger, verifier_log_level)
  603. });
  604. ret.map_err(|(_, io_error)| BtfError::LoadError {
  605. io_error,
  606. verifier_log,
  607. })
  608. }
  609. /// The main entry point into the library, used to work with eBPF programs and maps.
  610. #[derive(Debug)]
  611. pub struct Ebpf {
  612. maps: HashMap<String, Map>,
  613. programs: HashMap<String, Program>,
  614. }
  615. impl Ebpf {
  616. /// Loads eBPF bytecode from a file.
  617. ///
  618. /// Parses the given object code file and initializes the [maps](crate::maps) defined in it. If
  619. /// the kernel supports [BTF](Btf) debug info, it is automatically loaded from
  620. /// `/sys/kernel/btf/vmlinux`.
  621. ///
  622. /// For more loading options, see [EbpfLoader].
  623. ///
  624. /// # Examples
  625. ///
  626. /// ```no_run
  627. /// use aya::Ebpf;
  628. ///
  629. /// let bpf = Ebpf::load_file("file.o")?;
  630. /// # Ok::<(), aya::EbpfError>(())
  631. /// ```
  632. pub fn load_file<P: AsRef<str>>(path: P) -> Result<Self, EbpfError> {
  633. // EbpfLoader::new()
  634. // .btf(Btf::from_sys_fs().ok().as_ref())
  635. // .load_file(path)
  636. unimplemented!()
  637. }
  638. /// Loads eBPF bytecode from a buffer.
  639. ///
  640. /// Parses the object code contained in `data` and initializes the
  641. /// [maps](crate::maps) defined in it. If the kernel supports [BTF](Btf)
  642. /// debug info, it is automatically loaded from `/sys/kernel/btf/vmlinux`.
  643. ///
  644. /// For more loading options, see [EbpfLoader].
  645. ///
  646. /// # Examples
  647. ///
  648. /// ```no_run
  649. /// use aya::{Ebpf, Btf};
  650. /// use std::fs;
  651. ///
  652. /// let data = fs::read("file.o").unwrap();
  653. /// // load the BTF data from /sys/kernel/btf/vmlinux
  654. /// let bpf = Ebpf::load(&data)?;
  655. /// # Ok::<(), aya::EbpfError>(())
  656. /// ```
  657. pub fn load(data: &[u8]) -> Result<Self, EbpfError> {
  658. EbpfLoader::new()
  659. // .btf(Btf::from_sys_fs().ok().as_ref())
  660. .load(data)
  661. }
  662. /// Returns a reference to the map with the given name.
  663. ///
  664. /// The returned type is mostly opaque. In order to do anything useful with it you need to
  665. /// convert it to a [typed map](crate::maps).
  666. ///
  667. /// For more details and examples on maps and their usage, see the [maps module
  668. /// documentation][crate::maps].
  669. pub fn map(&self, name: &str) -> Option<&Map> {
  670. self.maps.get(name)
  671. }
  672. /// Returns a mutable reference to the map with the given name.
  673. ///
  674. /// The returned type is mostly opaque. In order to do anything useful with it you need to
  675. /// convert it to a [typed map](crate::maps).
  676. ///
  677. /// For more details and examples on maps and their usage, see the [maps module
  678. /// documentation][crate::maps].
  679. pub fn map_mut(&mut self, name: &str) -> Option<&mut Map> {
  680. self.maps.get_mut(name)
  681. }
  682. /// Takes ownership of a map with the given name.
  683. ///
  684. /// Use this when borrowing with [`map`](crate::Ebpf::map) or [`map_mut`](crate::Ebpf::map_mut)
  685. /// is not possible (eg when using the map from an async task). The returned
  686. /// map will be closed on `Drop`, therefore the caller is responsible for
  687. /// managing its lifetime.
  688. ///
  689. /// The returned type is mostly opaque. In order to do anything useful with it you need to
  690. /// convert it to a [typed map](crate::maps).
  691. ///
  692. /// For more details and examples on maps and their usage, see the [maps module
  693. /// documentation][crate::maps].
  694. pub fn take_map(&mut self, name: &str) -> Option<Map> {
  695. self.maps.remove(name)
  696. }
  697. /// An iterator over all the maps.
  698. ///
  699. /// # Examples
  700. /// ```no_run
  701. /// # let mut bpf = aya::Ebpf::load(&[])?;
  702. /// for (name, map) in bpf.maps() {
  703. /// println!(
  704. /// "found map `{}`",
  705. /// name,
  706. /// );
  707. /// }
  708. /// # Ok::<(), aya::EbpfError>(())
  709. /// ```
  710. pub fn maps(&self) -> impl Iterator<Item = (&str, &Map)> {
  711. self.maps.iter().map(|(name, map)| (name.as_str(), map))
  712. }
  713. /// A mutable iterator over all the maps.
  714. ///
  715. /// # Examples
  716. /// ```no_run
  717. /// # use std::path::Path;
  718. /// # #[derive(thiserror::Error, Debug)]
  719. /// # enum Error {
  720. /// # #[error(transparent)]
  721. /// # Ebpf(#[from] aya::EbpfError),
  722. /// # #[error(transparent)]
  723. /// # Pin(#[from] aya::pin::PinError)
  724. /// # }
  725. /// # let mut bpf = aya::Ebpf::load(&[])?;
  726. /// # let pin_path = Path::new("/tmp/pin_path");
  727. /// for (_, map) in bpf.maps_mut() {
  728. /// map.pin(pin_path)?;
  729. /// }
  730. /// # Ok::<(), Error>(())
  731. /// ```
  732. pub fn maps_mut(&mut self) -> impl Iterator<Item = (&str, &mut Map)> {
  733. self.maps.iter_mut().map(|(name, map)| (name.as_str(), map))
  734. }
  735. /// Returns a reference to the program with the given name.
  736. ///
  737. /// You can use this to inspect a program and its properties. To load and attach a program, use
  738. /// [program_mut](Self::program_mut) instead.
  739. ///
  740. /// For more details on programs and their usage, see the [programs module
  741. /// documentation](crate::programs).
  742. ///
  743. /// # Examples
  744. ///
  745. /// ```no_run
  746. /// # let bpf = aya::Ebpf::load(&[])?;
  747. /// let program = bpf.program("SSL_read").unwrap();
  748. /// println!("program SSL_read is of type {:?}", program.prog_type());
  749. /// # Ok::<(), aya::EbpfError>(())
  750. /// ```
  751. pub fn program(&self, name: &str) -> Option<&Program> {
  752. self.programs.get(name)
  753. }
  754. /// Returns a mutable reference to the program with the given name.
  755. ///
  756. /// Used to get a program before loading and attaching it. For more details on programs and
  757. /// their usage, see the [programs module documentation](crate::programs).
  758. ///
  759. /// # Examples
  760. ///
  761. /// ```no_run
  762. /// # let mut bpf = aya::Ebpf::load(&[])?;
  763. /// use aya::programs::UProbe;
  764. ///
  765. /// let program: &mut UProbe = bpf.program_mut("SSL_read").unwrap().try_into()?;
  766. /// program.load()?;
  767. /// program.attach(Some("SSL_read"), 0, "libssl", None)?;
  768. /// # Ok::<(), aya::EbpfError>(())
  769. /// ```
  770. pub fn program_mut(&mut self, name: &str) -> Option<&mut Program> {
  771. self.programs.get_mut(name)
  772. }
  773. /// An iterator over all the programs.
  774. ///
  775. /// # Examples
  776. /// ```no_run
  777. /// # let bpf = aya::Ebpf::load(&[])?;
  778. /// for (name, program) in bpf.programs() {
  779. /// println!(
  780. /// "found program `{}` of type `{:?}`",
  781. /// name,
  782. /// program.prog_type()
  783. /// );
  784. /// }
  785. /// # Ok::<(), aya::EbpfError>(())
  786. /// ```
  787. pub fn programs(&self) -> impl Iterator<Item = (&str, &Program)> {
  788. self.programs.iter().map(|(s, p)| (s.as_str(), p))
  789. }
  790. /// An iterator mutably referencing all of the programs.
  791. ///
  792. /// # Examples
  793. /// ```no_run
  794. /// # use std::path::Path;
  795. /// # #[derive(thiserror::Error, Debug)]
  796. /// # enum Error {
  797. /// # #[error(transparent)]
  798. /// # Ebpf(#[from] aya::EbpfError),
  799. /// # #[error(transparent)]
  800. /// # Pin(#[from] aya::pin::PinError)
  801. /// # }
  802. /// # let mut bpf = aya::Ebpf::load(&[])?;
  803. /// # let pin_path = Path::new("/tmp/pin_path");
  804. /// for (_, program) in bpf.programs_mut() {
  805. /// program.pin(pin_path)?;
  806. /// }
  807. /// # Ok::<(), Error>(())
  808. /// ```
  809. pub fn programs_mut(&mut self) -> impl Iterator<Item = (&str, &mut Program)> {
  810. self.programs.iter_mut().map(|(s, p)| (s.as_str(), p))
  811. }
  812. }
  813. /// The error type returned by [`Ebpf::load_file`] and [`Ebpf::load`].
  814. #[derive(Debug, Error)]
  815. pub enum EbpfError {
  816. /// Error loading file
  817. #[error("error loading {path}")]
  818. FileError {
  819. /// The file path
  820. path: PathBuf,
  821. #[source]
  822. /// The original io::Error
  823. error: io::Error,
  824. },
  825. /// Unexpected pinning type
  826. #[error("unexpected pinning type {name}")]
  827. UnexpectedPinningType {
  828. /// The value encountered
  829. name: u32,
  830. },
  831. /// Error parsing BPF object
  832. #[error("error parsing BPF object: {0}")]
  833. ParseError(#[from] ParseError),
  834. /// Error parsing BTF object
  835. #[error("BTF error: {0}")]
  836. BtfError(#[from] BtfError),
  837. /// Error performing relocations
  838. #[error("error relocating function")]
  839. RelocationError(#[from] EbpfRelocationError),
  840. /// Error performing relocations
  841. #[error("error relocating section")]
  842. BtfRelocationError(#[from] BtfRelocationError),
  843. /// No BTF parsed for object
  844. #[error("no BTF parsed for object")]
  845. NoBTF,
  846. #[error("map error: {0}")]
  847. /// A map error
  848. MapError(#[from] MapError),
  849. #[error("program error: {0}")]
  850. /// A program error
  851. ProgramError(#[from] ProgramError),
  852. }
  853. /// Marker trait for types that can safely be converted to and from byte slices.
  854. ///
  855. /// # Safety
  856. /// This trait is unsafe because it is up to the implementor to ensure that the type is safe to
  857. /// convert to and from a byte slice. The implementor must ensure that the type is a valid
  858. /// representation of the data in the byte slice.
  859. pub unsafe trait Pod: Copy + 'static {}
  860. macro_rules! unsafe_impl_pod {
  861. ($($struct_name:ident),+ $(,)?) => {
  862. $(
  863. unsafe impl Pod for $struct_name { }
  864. )+
  865. }
  866. }
  867. unsafe_impl_pod!(i8, u8, i16, u16, i32, u32, i64, u64, u128, i128);
  868. // It only makes sense that an array of POD types is itself POD
  869. unsafe impl<T: Pod, const N: usize> Pod for [T; N] {}
  870. /// Global data that can be exported to eBPF programs before they are loaded.
  871. ///
  872. /// Valid global data includes `Pod` types and slices of `Pod` types. See also
  873. /// [EbpfLoader::set_global].
  874. pub struct GlobalData<'a> {
  875. bytes: &'a [u8],
  876. }
  877. impl<'a, T: Pod> From<&'a [T]> for GlobalData<'a> {
  878. fn from(s: &'a [T]) -> Self {
  879. GlobalData {
  880. bytes: bytes_of_slice(s),
  881. }
  882. }
  883. }
  884. impl<'a, T: Pod> From<&'a T> for GlobalData<'a> {
  885. fn from(v: &'a T) -> Self {
  886. GlobalData {
  887. // Safety: v is Pod
  888. bytes: unsafe { bytes_of(v) },
  889. }
  890. }
  891. }
  892. pub(crate) fn page_size() -> usize {
  893. // Safety: libc
  894. 4096
  895. }
  896. // bytes_of converts a <T> to a byte slice
  897. pub(crate) unsafe fn bytes_of<T: Pod>(val: &T) -> &[u8] {
  898. let size = mem::size_of::<T>();
  899. slice::from_raw_parts(slice::from_ref(val).as_ptr().cast(), size)
  900. }
  901. pub(crate) fn bytes_of_slice<T: Pod>(val: &[T]) -> &[u8] {
  902. let size = val.len().wrapping_mul(mem::size_of::<T>());
  903. // Safety:
  904. // Any alignment is allowed.
  905. // The size is determined in this function.
  906. // The Pod trait ensures the type is valid to cast to bytes.
  907. unsafe { slice::from_raw_parts(val.as_ptr().cast(), size) }
  908. }