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)
}
/// 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]
pub fn id_by_type_name_kind(&self, name: &str, kind: BtfKind) -> Result<u32, BtfError> {
for (type_id, ty) in self.types().enumerate() {

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

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

@ -3,7 +3,7 @@ use std::{
collections::{HashMap, HashSet},
fs, io,
os::{
fd::{AsFd as _, AsRawFd as _, OwnedFd},
fd::{AsFd as _, AsRawFd as _, FromRawFd, OwnedFd},
raw::c_int,
},
path::{Path, PathBuf},
@ -21,10 +21,10 @@ use thiserror::Error;
use crate::{
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,
},
maps::{Map, MapData, MapError},
maps::{Map, MapData, MapError, MapFd},
obj::{
btf::{Btf, BtfError},
Object, ParseError, ProgramSection,
@ -137,6 +137,7 @@ pub struct EbpfLoader<'a> {
extensions: HashSet<&'a str>,
verifier_log_level: VerifierLogLevel,
allow_unsupported_maps: bool,
deactivate_maps: HashSet<bpf_map_type>,
}
/// Builder style API for advanced loading of eBPF programs.
@ -175,6 +176,7 @@ impl<'a> EbpfLoader<'a> {
extensions: HashSet::new(),
verifier_log_level: VerifierLogLevel::default(),
allow_unsupported_maps: false,
deactivate_maps: HashSet::new(),
}
}
@ -224,6 +226,12 @@ impl<'a> EbpfLoader<'a> {
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.
///
/// Pinned maps will be loaded from `path/MAP_NAME`.
@ -394,9 +402,9 @@ impl<'a> EbpfLoader<'a> {
extensions,
verifier_log_level,
allow_unsupported_maps,
deactivate_maps,
} = self;
let mut obj = Object::parse(data)?;
obj.patch_map_data(globals.clone())?;
let btf_fd = if let Some(features) = &FEATURES.btf() {
if let Some(btf) = obj.fixup_and_sanitize_btf(features)? {
@ -459,12 +467,20 @@ impl<'a> EbpfLoader<'a> {
obj.relocate_btf(btf)?;
}
let mut maps = HashMap::new();
let mut ignored_maps = HashMap::new();
for (name, mut obj) in obj.maps.drain() {
if let (false, EbpfSectionKind::Bss | EbpfSectionKind::Data | EbpfSectionKind::Rodata) =
(FEATURES.bpf_global_data(), obj.section_kind())
{
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> {
Ok(possible_cpus()
.map_err(|error| EbpfError::FileError {
@ -498,7 +514,7 @@ impl<'a> EbpfLoader<'a> {
PinningType::ByName => {
// 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.
let path = map_pin_path
let path: &Path = map_pin_path
.as_deref()
.unwrap_or_else(|| Path::new("/sys/fs/bpf"));
@ -508,7 +524,6 @@ impl<'a> EbpfLoader<'a> {
map.finalize()?;
maps.insert(name, map);
}
let text_sections = obj
.functions
.keys()
@ -519,6 +534,7 @@ impl<'a> EbpfLoader<'a> {
maps.iter()
.map(|(s, data)| (s.as_str(), data.fd().as_fd().as_raw_fd(), data.obj())),
&text_sections,
&ignored_maps,
)?;
obj.relocate_calls(&text_sections)?;
obj.sanitize_functions(&FEATURES);

Loading…
Cancel
Save