Ignore relocation of maps that should be ignored.

This makes it possible to have bytecode with unsupported map types such as BPF_MAP_TYPE_RINGBUF on a target kernel that doesn't have that map type
pull/968/head
martinsoees 3 months ago
parent bf20a8c892
commit 74f5acf419

@ -416,6 +416,20 @@ impl Btf {
self.string_at(ty.name_offset()).ok().map(String::from) self.string_at(ty.name_offset()).ok().map(String::from)
} }
/// Returns a type id matching the type name
pub fn id_by_type_name(&self, name: &str) -> Result<u32, BtfError> {
for (type_id, ty) in self.types().enumerate() {
if self.type_name(ty)? == name {
return Ok(type_id as u32);
}
continue;
}
Err(BtfError::UnknownBtfTypeName {
type_name: name.to_owned(),
})
}
/// Returns a type id matching the type name and [BtfKind] /// Returns a type id matching the type name and [BtfKind]
pub fn id_by_type_name_kind(&self, name: &str, kind: BtfKind) -> Result<u32, BtfError> { pub fn id_by_type_name_kind(&self, name: &str, kind: BtfKind) -> Result<u32, BtfError> {
for (type_id, ty) in self.types().enumerate() { for (type_id, ty) in self.types().enumerate() {

@ -8,6 +8,7 @@ use alloc::{
vec::Vec, vec::Vec,
}; };
use core::{ffi::CStr, mem, ptr, slice::from_raw_parts_mut, str::FromStr}; use core::{ffi::CStr, mem, ptr, slice::from_raw_parts_mut, str::FromStr};
use std::println;
use log::debug; use log::debug;
use object::{ use object::{

@ -2,6 +2,7 @@
use alloc::{borrow::ToOwned, collections::BTreeMap, string::String}; use alloc::{borrow::ToOwned, collections::BTreeMap, string::String};
use core::mem; use core::mem;
use std::println;
use log::debug; use log::debug;
use object::{SectionIndex, SymbolKind}; use object::{SectionIndex, SymbolKind};
@ -108,9 +109,20 @@ impl Object {
&mut self, &mut self,
maps: I, maps: I,
text_sections: &HashSet<usize>, text_sections: &HashSet<usize>,
ignored_maps: &HashMap<String, Map>,
) -> Result<(), EbpfRelocationError> { ) -> Result<(), EbpfRelocationError> {
let mut maps_by_section = HashMap::new(); let mut maps_by_section = HashMap::new();
let mut maps_by_symbol = HashMap::new(); let mut maps_by_symbol = HashMap::new();
let mut ignored_by_section = HashSet::new();
let mut ignored_by_symbol = HashSet::new();
for (name, map) in ignored_maps {
ignored_by_section.insert(map.section_index());
if let Some(index) = map.symbol_index() {
ignored_by_symbol.insert(index);
}
}
for (name, fd, map) in maps { for (name, fd, map) in maps {
maps_by_section.insert(map.section_index(), (name, fd, map)); maps_by_section.insert(map.section_index(), (name, fd, map));
if let Some(index) = map.symbol_index() { if let Some(index) = map.symbol_index() {
@ -127,6 +139,8 @@ impl Object {
&maps_by_symbol, &maps_by_symbol,
&self.symbol_table, &self.symbol_table,
text_sections, text_sections,
&ignored_by_section,
&ignored_by_symbol,
) )
.map_err(|error| EbpfRelocationError { .map_err(|error| EbpfRelocationError {
function: function.name.clone(), function: function.name.clone(),
@ -176,6 +190,7 @@ impl Object {
} }
} }
#[allow(clippy::too_many_arguments)]
fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>( fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
fun: &mut Function, fun: &mut Function,
relocations: I, relocations: I,
@ -183,6 +198,8 @@ fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
maps_by_symbol: &HashMap<usize, (&str, std::os::fd::RawFd, &Map)>, maps_by_symbol: &HashMap<usize, (&str, std::os::fd::RawFd, &Map)>,
symbol_table: &HashMap<usize, Symbol>, symbol_table: &HashMap<usize, Symbol>,
text_sections: &HashSet<usize>, text_sections: &HashSet<usize>,
ignored_by_section: &HashSet<usize>,
ignored_by_symbol: &HashSet<usize>,
) -> Result<(), RelocationError> { ) -> Result<(), RelocationError> {
let section_offset = fun.section_offset; let section_offset = fun.section_offset;
let instructions = &mut fun.instructions; let instructions = &mut fun.instructions;
@ -212,6 +229,7 @@ fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
index: rel.symbol_index, index: rel.symbol_index,
})?; })?;
let Some(section_index) = sym.section_index else { let Some(section_index) = sym.section_index else {
// this is not a map relocation // this is not a map relocation
continue; continue;
@ -222,7 +240,9 @@ fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
continue; continue;
} }
let (_name, fd, map) = if let Some(m) = maps_by_symbol.get(&rel.symbol_index) { let (_name, fd, map) = if ignored_by_symbol.contains(&rel.symbol_index) {
continue
} else if let Some(m) = maps_by_symbol.get(&rel.symbol_index) {
let map = &m.2; let map = &m.2;
debug!( debug!(
"relocating map by symbol index {:?}, kind {:?} at insn {ins_index} in section {}", "relocating map by symbol index {:?}, kind {:?} at insn {ins_index} in section {}",
@ -232,6 +252,8 @@ fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
); );
debug_assert_eq!(map.symbol_index().unwrap(), rel.symbol_index); debug_assert_eq!(map.symbol_index().unwrap(), rel.symbol_index);
m m
} else if ignored_by_section.contains(&section_index) {
continue
} else { } else {
let Some(m) = maps_by_section.get(&section_index) else { let Some(m) = maps_by_section.get(&section_index) else {
debug!("failed relocating map by section index {}", section_index); debug!("failed relocating map by section index {}", section_index);
@ -580,6 +602,8 @@ mod test {
&maps_by_symbol, &maps_by_symbol,
&symbol_table, &symbol_table,
&HashSet::new(), &HashSet::new(),
&HashSet::new(),
&HashSet::new(),
) )
.unwrap(); .unwrap();
@ -636,6 +660,8 @@ mod test {
&maps_by_symbol, &maps_by_symbol,
&symbol_table, &symbol_table,
&HashSet::new(), &HashSet::new(),
&HashSet::new(),
&HashSet::new(),
) )
.unwrap(); .unwrap();
@ -675,6 +701,8 @@ mod test {
&maps_by_symbol, &maps_by_symbol,
&symbol_table, &symbol_table,
&HashSet::new(), &HashSet::new(),
&HashSet::new(),
&HashSet::new(),
) )
.unwrap(); .unwrap();
@ -731,6 +759,8 @@ mod test {
&maps_by_symbol, &maps_by_symbol,
&symbol_table, &symbol_table,
&HashSet::new(), &HashSet::new(),
&HashSet::new(),
&HashSet::new(),
) )
.unwrap(); .unwrap();

@ -3,7 +3,7 @@ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fs, io, fs, io,
os::{ os::{
fd::{AsFd as _, AsRawFd as _, OwnedFd}, fd::{AsFd as _, AsRawFd as _, FromRawFd, OwnedFd},
raw::c_int, raw::c_int,
}, },
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -21,10 +21,10 @@ use thiserror::Error;
use crate::{ use crate::{
generated::{ generated::{
bpf_map_type, bpf_map_type::*, AYA_PERF_EVENT_IOC_DISABLE, AYA_PERF_EVENT_IOC_ENABLE, bpf_map_type::{self, *}, AYA_PERF_EVENT_IOC_DISABLE, AYA_PERF_EVENT_IOC_ENABLE,
AYA_PERF_EVENT_IOC_SET_BPF, AYA_PERF_EVENT_IOC_SET_BPF,
}, },
maps::{Map, MapData, MapError}, maps::{Map, MapData, MapError, MapFd},
obj::{ obj::{
btf::{Btf, BtfError}, btf::{Btf, BtfError},
Object, ParseError, ProgramSection, Object, ParseError, ProgramSection,
@ -137,6 +137,7 @@ pub struct EbpfLoader<'a> {
extensions: HashSet<&'a str>, extensions: HashSet<&'a str>,
verifier_log_level: VerifierLogLevel, verifier_log_level: VerifierLogLevel,
allow_unsupported_maps: bool, allow_unsupported_maps: bool,
deactivate_maps: HashSet<bpf_map_type>,
} }
/// Builder style API for advanced loading of eBPF programs. /// Builder style API for advanced loading of eBPF programs.
@ -175,6 +176,7 @@ impl<'a> EbpfLoader<'a> {
extensions: HashSet::new(), extensions: HashSet::new(),
verifier_log_level: VerifierLogLevel::default(), verifier_log_level: VerifierLogLevel::default(),
allow_unsupported_maps: false, allow_unsupported_maps: false,
deactivate_maps: HashSet::new(),
} }
} }
@ -224,6 +226,12 @@ impl<'a> EbpfLoader<'a> {
self self
} }
/// Documentaaaaaaaaaaaaation
pub fn deactivate_maps(&mut self, set: HashSet<bpf_map_type>) -> &mut Self {
self.deactivate_maps = set;
self
}
/// Sets the base directory path for pinned maps. /// Sets the base directory path for pinned maps.
/// ///
/// Pinned maps will be loaded from `path/MAP_NAME`. /// Pinned maps will be loaded from `path/MAP_NAME`.
@ -394,9 +402,9 @@ impl<'a> EbpfLoader<'a> {
extensions, extensions,
verifier_log_level, verifier_log_level,
allow_unsupported_maps, allow_unsupported_maps,
deactivate_maps,
} = self; } = self;
let mut obj = Object::parse(data)?; let mut obj = Object::parse(data)?;
obj.patch_map_data(globals.clone())?;
let btf_fd = if let Some(features) = &FEATURES.btf() { let btf_fd = if let Some(features) = &FEATURES.btf() {
if let Some(btf) = obj.fixup_and_sanitize_btf(features)? { if let Some(btf) = obj.fixup_and_sanitize_btf(features)? {
@ -459,12 +467,20 @@ impl<'a> EbpfLoader<'a> {
obj.relocate_btf(btf)?; obj.relocate_btf(btf)?;
} }
let mut maps = HashMap::new(); let mut maps = HashMap::new();
let mut ignored_maps = HashMap::new();
for (name, mut obj) in obj.maps.drain() { for (name, mut obj) in obj.maps.drain() {
if let (false, EbpfSectionKind::Bss | EbpfSectionKind::Data | EbpfSectionKind::Rodata) = if let (false, EbpfSectionKind::Bss | EbpfSectionKind::Data | EbpfSectionKind::Rodata) =
(FEATURES.bpf_global_data(), obj.section_kind()) (FEATURES.bpf_global_data(), obj.section_kind())
{ {
continue; continue;
} }
if deactivate_maps.contains(&obj.map_type().try_into().map_err(|_| EbpfError::MapError(MapError::InvalidMapType { map_type: obj.map_type() }))?) {
ignored_maps.insert(name, obj);
continue;
}
let num_cpus = || -> Result<u32, EbpfError> { let num_cpus = || -> Result<u32, EbpfError> {
Ok(possible_cpus() Ok(possible_cpus()
.map_err(|error| EbpfError::FileError { .map_err(|error| EbpfError::FileError {
@ -498,17 +514,16 @@ impl<'a> EbpfLoader<'a> {
PinningType::ByName => { PinningType::ByName => {
// pin maps in /sys/fs/bpf by default to align with libbpf // pin maps in /sys/fs/bpf by default to align with libbpf
// behavior https://github.com/libbpf/libbpf/blob/v1.2.2/src/libbpf.c#L2161. // behavior https://github.com/libbpf/libbpf/blob/v1.2.2/src/libbpf.c#L2161.
let path = map_pin_path let path: &Path = map_pin_path
.as_deref() .as_deref()
.unwrap_or_else(|| Path::new("/sys/fs/bpf")); .unwrap_or_else(|| Path::new("/sys/fs/bpf"));
MapData::create_pinned_by_name(path, obj, &name, btf_fd)? MapData::create_pinned_by_name(path, obj, &name, btf_fd)?
} }
}; };
map.finalize()?; map.finalize()?;
maps.insert(name, map); maps.insert(name, map);
} }
let text_sections = obj let text_sections = obj
.functions .functions
.keys() .keys()
@ -519,6 +534,7 @@ impl<'a> EbpfLoader<'a> {
maps.iter() maps.iter()
.map(|(s, data)| (s.as_str(), data.fd().as_fd().as_raw_fd(), data.obj())), .map(|(s, data)| (s.as_str(), data.fd().as_fd().as_raw_fd(), data.obj())),
&text_sections, &text_sections,
&ignored_maps,
)?; )?;
obj.relocate_calls(&text_sections)?; obj.relocate_calls(&text_sections)?;
obj.sanitize_functions(&FEATURES); obj.sanitize_functions(&FEATURES);

Loading…
Cancel
Save