diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index cf593b2a..2d71d88c 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -35,8 +35,8 @@ use crate::{ sys::{ bpf_load_btf, bpf_map_freeze, bpf_map_update_elem_ptr, is_btf_datasec_supported, is_btf_decl_tag_supported, is_btf_float_supported, is_btf_func_global_supported, - is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_prog_name_supported, - retry_with_verifier_logs, + is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, + is_prog_name_supported, retry_with_verifier_logs, }, util::{bytes_of, possible_cpus, VerifierLog, POSSIBLE_CPUS}, }; @@ -73,6 +73,7 @@ lazy_static! { #[derive(Default, Debug)] pub(crate) struct Features { pub bpf_name: bool, + pub bpf_perf_link: bool, pub btf: Option, } @@ -92,6 +93,7 @@ impl Features { }; let f = Features { bpf_name: is_prog_name_supported(), + bpf_perf_link: is_perf_link_supported(), btf, }; @@ -107,8 +109,10 @@ impl std::fmt::Display for Features { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!( "[FEAT PROBE] BPF program name support: {}\n\ + [FEAT PROBE] bpf_link support for kprobe/uprobe/tracepoint: {}\n\ [FEAT PROBE] BTF support: {}", self.bpf_name, + self.bpf_perf_link, self.btf.is_some() )) } @@ -358,7 +362,7 @@ impl<'a> BpfLoader<'a> { let mut obj = Object::parse(data)?; obj.patch_map_data(self.globals.clone())?; - let btf_fd = if let Some(ref features) = FEATURES.btf { + let btf_fd = if let Some(features) = &FEATURES.btf { if let Some(btf) = obj.fixup_and_sanitize_btf(features)? { // load btf to the kernel Some(load_btf(btf.to_bytes())?) diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index ec3890d0..20a88f26 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -599,6 +599,37 @@ pub(crate) fn is_prog_name_supported() -> bool { } } +pub(crate) fn is_perf_link_supported() -> bool { + let mut attr = unsafe { mem::zeroed::() }; + let u = unsafe { &mut attr.__bindgen_anon_3 }; + + let prog: &[u8] = &[ + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0 + 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit + ]; + + let gpl = b"GPL\0"; + u.license = gpl.as_ptr() as u64; + + let insns = copy_instructions(prog).unwrap(); + u.insn_cnt = insns.len() as u32; + u.insns = insns.as_ptr() as u64; + u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; + + if let Ok(fd) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { + if let Err((code, _)) = + // Uses an invalid target FD so we get EBADF if supported. + bpf_link_create(fd as i32, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0) + { + // Returns EINVAL if unsupported. EBADF if supported. + let res = code == (-libc::EBADF).into(); + unsafe { libc::close(fd as i32) }; + return res; + } + } + false +} + pub(crate) fn is_btf_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string());