Browse Source

Merge pull request #563 from marysaka/fix/reloc-less-strict

aya-obj: Make relocations less strict
Mary 1 year ago
parent
commit
85ad0197e0
2 changed files with 81 additions and 17 deletions
  1. 52 17
      aya-obj/src/btf/relocation.rs
  2. 29 0
      test/integration-test/src/tests/btf_relocations.rs

+ 52 - 17
aya-obj/src/btf/relocation.rs

@@ -16,8 +16,8 @@ use crate::{
         IntEncoding, Struct, Union, MAX_SPEC_LEN,
     },
     generated::{
-        bpf_core_relo, bpf_core_relo_kind::*, bpf_insn, BPF_ALU, BPF_ALU64, BPF_B, BPF_DW, BPF_H,
-        BPF_K, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, BPF_W, BTF_INT_SIGNED,
+        bpf_core_relo, bpf_core_relo_kind::*, bpf_insn, BPF_ALU, BPF_ALU64, BPF_B, BPF_CALL,
+        BPF_DW, BPF_H, BPF_JMP, BPF_K, BPF_LD, BPF_LDX, BPF_ST, BPF_STX, BPF_W, BTF_INT_SIGNED,
     },
     util::HashMap,
     Function, Object,
@@ -360,13 +360,18 @@ fn relocate_btf_functions<'target>(
             // same value, else the relocation is ambiguous and can't be applied
             let conflicts = matches
                 .filter_map(|(cand_name, cand_spec, cand_comp_rel)| {
-                    if cand_spec.bit_offset != target_spec.bit_offset
-                        || cand_comp_rel.target.value != target_comp_rel.target.value
-                    {
-                        Some(cand_name)
-                    } else {
-                        None
+                    if cand_spec.bit_offset != target_spec.bit_offset {
+                        return Some(cand_name);
+                    } else if let (Some(cand_comp_rel_target), Some(target_comp_rel_target)) = (
+                        cand_comp_rel.target.as_ref(),
+                        target_comp_rel.target.as_ref(),
+                    ) {
+                        if cand_comp_rel_target.value != target_comp_rel_target.value {
+                            return Some(cand_name);
+                        }
                     }
+
+                    None
                 })
                 .collect::<Vec<_>>();
             if !conflicts.is_empty() {
@@ -857,7 +862,7 @@ struct Candidate<'a> {
 #[derive(Debug)]
 struct ComputedRelocation {
     local: ComputedRelocationValue,
-    target: ComputedRelocationValue,
+    target: Option<ComputedRelocationValue>,
 }
 
 #[derive(Debug)]
@@ -867,6 +872,14 @@ struct ComputedRelocationValue {
     type_id: Option<u32>,
 }
 
+fn poison_insn(ins: &mut bpf_insn) {
+    ins.code = (BPF_JMP | BPF_CALL) as u8;
+    ins.set_dst_reg(0);
+    ins.set_src_reg(0);
+    ins.off = 0;
+    ins.imm = 0xBAD2310;
+}
+
 impl ComputedRelocation {
     fn new(
         rel: &Relocation,
@@ -878,15 +891,15 @@ impl ComputedRelocation {
             FieldByteOffset | FieldByteSize | FieldExists | FieldSigned | FieldLShift64
             | FieldRShift64 => ComputedRelocation {
                 local: Self::compute_field_relocation(rel, Some(local_spec))?,
-                target: Self::compute_field_relocation(rel, target_spec)?,
+                target: Self::compute_field_relocation(rel, target_spec).ok(),
             },
             TypeIdLocal | TypeIdTarget | TypeExists | TypeSize => ComputedRelocation {
                 local: Self::compute_type_relocation(rel, local_spec, target_spec)?,
-                target: Self::compute_type_relocation(rel, local_spec, target_spec)?,
+                target: Self::compute_type_relocation(rel, local_spec, target_spec).ok(),
             },
             EnumVariantExists | EnumVariantValue => ComputedRelocation {
                 local: Self::compute_enum_relocation(rel, Some(local_spec))?,
-                target: Self::compute_enum_relocation(rel, target_spec)?,
+                target: Self::compute_enum_relocation(rel, target_spec).ok(),
             },
         };
 
@@ -912,9 +925,31 @@ impl ComputedRelocation {
                     relocation_number: rel.number,
                 })?;
 
+        let target = if let Some(target) = self.target.as_ref() {
+            target
+        } else {
+            let is_ld_imm64 = ins.code == (BPF_LD | BPF_DW) as u8;
+
+            poison_insn(ins);
+
+            if is_ld_imm64 {
+                let next_ins = instructions.get_mut(ins_index + 1).ok_or(
+                    RelocationError::InvalidInstructionIndex {
+                        index: (ins_index + 1) * mem::size_of::<bpf_insn>(),
+                        num_instructions,
+                        relocation_number: rel.number,
+                    },
+                )?;
+
+                poison_insn(next_ins);
+            }
+
+            return Ok(());
+        };
+
         let class = (ins.code & 0x07) as u32;
 
-        let target_value = self.target.value;
+        let target_value = target.value;
 
         match class {
             BPF_ALU | BPF_ALU64 => {
@@ -940,9 +975,9 @@ impl ComputedRelocation {
 
                 ins.off = target_value as i16;
 
-                if self.local.size != self.target.size {
+                if self.local.size != target.size {
                     let local_ty = local_btf.type_by_id(self.local.type_id.unwrap())?;
-                    let target_ty = target_btf.type_by_id(self.target.type_id.unwrap())?;
+                    let target_ty = target_btf.type_by_id(target.type_id.unwrap())?;
                     let unsigned = |info: u32| ((info >> 24) & 0x0F) & BTF_INT_SIGNED == 0;
                     use BtfType::*;
                     match (local_ty, target_ty) {
@@ -958,13 +993,13 @@ impl ComputedRelocation {
                                     err_type_name(&local_btf.err_type_name(local_ty)),
                                     self.local.size,
                                     err_type_name(&target_btf.err_type_name(target_ty)),
-                                    self.target.size,
+                                    target.size,
                                 ),
                             })
                         }
                     }
 
-                    let size = match self.target.size {
+                    let size = match target.size {
                         8 => BPF_DW,
                         4 => BPF_W,
                         2 => BPF_H,

+ 29 - 0
test/integration-test/src/tests/btf_relocations.rs

@@ -143,6 +143,35 @@ fn relocate_pointer() {
     assert_eq!(test.run_no_btf().unwrap(), 42);
 }
 
+#[integration_test]
+fn relocate_struct_flavors() {
+    let definition = r#"
+        struct foo {};
+        struct bar { struct foo *f; };
+        struct bar___cafe { struct foo *e; struct foo *f; };
+    "#;
+
+    let relocation_code = r#"
+        __u8 memory[] = {42, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0};
+        struct bar* ptr = (struct bar *) &memory;
+
+        if (__builtin_preserve_field_info((((typeof(struct bar___cafe) *)0)->e), 2)) {
+            value = (__u64) __builtin_preserve_access_index(((struct bar___cafe *)ptr)->e);
+        } else {
+            value = (__u64) __builtin_preserve_access_index(ptr->f);
+        }
+    "#;
+
+    let test_no_flavor = RelocationTest {
+        local_definition: definition,
+        target_btf: definition,
+        relocation_code,
+    }
+    .build()
+    .unwrap();
+    assert_eq!(test_no_flavor.run_no_btf().unwrap(), 42);
+}
+
 /// Utility code for running relocation tests:
 /// - Generates the eBPF program using probided local definition and relocation code
 /// - Generates the BTF from the target btf code