From 591e21267a9bc9adca9818095de5a695cee7ee9b Mon Sep 17 00:00:00 2001 From: Mary Date: Wed, 10 May 2023 15:52:35 +0200 Subject: [PATCH] aya: Do not create data maps on kernel without global data support Fix map creation failure when a BPF have a data section on older kernel. (< 5.2) If the BPF uses that section, relocation will fail accordingly and report an error. --- aya-obj/src/obj.rs | 1 + aya/src/bpf.rs | 16 +++++++++---- aya/src/sys/bpf.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/aya-obj/src/obj.rs b/aya-obj/src/obj.rs index db1c50d9..3f0effdc 100644 --- a/aya-obj/src/obj.rs +++ b/aya-obj/src/obj.rs @@ -44,6 +44,7 @@ pub struct Features { pub bpf_name: bool, pub bpf_probe_read_kernel: bool, pub bpf_perf_link: bool, + pub bpf_global_data: bool, pub btf: Option, } diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 84026a4b..938629d0 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -33,10 +33,11 @@ use crate::{ SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp, }, 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_perf_link_supported, - is_probe_read_kernel_supported, is_prog_name_supported, retry_with_verifier_logs, + bpf_load_btf, bpf_map_freeze, bpf_map_update_elem_ptr, is_bpf_global_data_supported, + 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_perf_link_supported, is_probe_read_kernel_supported, + is_prog_name_supported, retry_with_verifier_logs, }, util::{bytes_of, bytes_of_slice, possible_cpus, VerifierLog, POSSIBLE_CPUS}, }; @@ -86,6 +87,7 @@ fn detect_features() -> Features { bpf_name: is_prog_name_supported(), bpf_probe_read_kernel: is_probe_read_kernel_supported(), bpf_perf_link: is_perf_link_supported(), + bpf_global_data: is_bpf_global_data_supported(), btf, }; debug!("BPF Feature Detection: {:#?}", f); @@ -358,6 +360,12 @@ impl<'a> BpfLoader<'a> { } let mut maps = HashMap::new(); for (name, mut obj) in obj.maps.drain() { + if let (false, BpfSectionKind::Bss | BpfSectionKind::Data | BpfSectionKind::Rodata) = + (FEATURES.bpf_global_data, obj.section_kind()) + { + continue; + } + match self.max_entries.get(name.as_str()) { Some(size) => obj.set_max_entries(*size), None => { diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 39b1eb48..368ef4a4 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -8,13 +8,17 @@ use std::{ }; use libc::{c_char, c_long, close, ENOENT, ENOSPC}; +use obj::{ + maps::{bpf_map_def, LegacyMap}, + BpfSectionKind, +}; use crate::{ generated::{ bpf_attach_type, bpf_attr, bpf_btf_info, bpf_cmd, bpf_insn, bpf_link_info, bpf_map_info, bpf_map_type, bpf_prog_info, bpf_prog_type, BPF_F_REPLACE, }, - maps::PerCpuValues, + maps::{MapData, PerCpuValues}, obj::{ self, btf::{ @@ -661,6 +665,60 @@ pub(crate) fn is_perf_link_supported() -> bool { false } +pub(crate) fn is_bpf_global_data_supported() -> bool { + let mut attr = unsafe { mem::zeroed::() }; + let u = unsafe { &mut attr.__bindgen_anon_3 }; + + let prog: &[u8] = &[ + 0x18, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ld_pseudo r1, 0x2, 0x0 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // + 0x7a, 0x01, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, // stdw [r1 + 0x0], 0x2a + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0 + 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit + ]; + + let mut insns = copy_instructions(prog).unwrap(); + + let mut map_data = MapData { + obj: obj::Map::Legacy(LegacyMap { + def: bpf_map_def { + map_type: bpf_map_type::BPF_MAP_TYPE_ARRAY as u32, + key_size: 4, + value_size: 32, + max_entries: 1, + ..Default::default() + }, + section_index: 0, + section_kind: BpfSectionKind::Maps, + symbol_index: None, + data: Vec::new(), + }), + fd: None, + pinned: false, + btf_fd: None, + }; + + if let Ok(map_fd) = map_data.create("aya_global") { + insns[0].imm = map_fd; + + let gpl = b"GPL\0"; + u.license = gpl.as_ptr() as u64; + u.insn_cnt = insns.len() as u32; + u.insns = insns.as_ptr() as u64; + u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; + + if let Ok(v) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { + let fd = v as RawFd; + + unsafe { close(fd) }; + + return true; + } + } + + false +} + pub(crate) fn is_btf_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string());