Browse Source

Merge pull request #605 from marysaka/fix/global-data-reloc-ancient-kernels

aya: Do not create data maps on kernel without global data support
Alessandro Decina 1 year ago
parent
commit
9c437aa
3 changed files with 72 additions and 5 deletions
  1. 1 0
      aya-obj/src/obj.rs
  2. 12 4
      aya/src/bpf.rs
  3. 59 1
      aya/src/sys/bpf.rs

+ 1 - 0
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<BtfFeatures>,
 }
 

+ 12 - 4
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 => {

+ 59 - 1
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::<bpf_attr>() };
+    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());