Parcourir la source

btf: check array bounds while doing candidate matching

Alessandro Decina il y a 4 ans
Parent
commit
4b65da66ea
1 fichiers modifiés avec 24 ajouts et 2 suppressions
  1. 24 2
      src/obj/btf/relocation.rs

+ 24 - 2
src/obj/btf/relocation.rs

@@ -364,7 +364,7 @@ fn match_candidate<'target>(
         | RelocationKind::FieldLShift64
         | RelocationKind::FieldRShift64 => {
             let mut target_id = candidate.type_id;
-            for accessor in &local_spec.accessors {
+            for (i, accessor) in local_spec.accessors.iter().enumerate() {
                 target_id = candidate.btf.resolve_type(target_id)?;
 
                 if accessor.name.is_some() {
@@ -381,7 +381,29 @@ fn match_candidate<'target>(
                         return Ok(None);
                     }
                 } else {
-                    // array access
+                    // i = 0 is the base struct. for i > 0, we need to potentially do bounds checking
+                    if i > 0 {
+                        let target_ty = candidate.btf.type_by_id(target_id)?;
+                        let array = match target_ty {
+                            BtfType::Array(_, array) => array,
+                            _ => return Ok(None),
+                        };
+
+                        let var_len = array.nelems == 0 && {
+                            // an array is potentially variable length if it's the last field
+                            // of the parent struct and has 0 elements
+                            let parent = target_spec.accessors.last().unwrap();
+                            let parent_ty = candidate.btf.type_by_id(parent.type_id)?;
+                            match parent_ty {
+                                BtfType::Struct(_, members) => parent.index == members.len() - 1,
+                                _ => false,
+                            }
+                        };
+                        if !var_len && accessor.index >= array.nelems as usize {
+                            return Ok(None);
+                        }
+                        target_id = candidate.btf.resolve_type(array.type_)?;
+                    }
 
                     if target_spec.parts.len() == MAX_SPEC_LEN {
                         return Err(BtfRelocationError::MaximumNestingLevelReached {