aya: Add sanitize code for kernels without bpf_probe_read_kernel

Required for kernel before 5.5.

Also move Features to aya-obj.
pull/582/head
Mary 2 years ago
parent edd9928314
commit 1132b6e01b

@ -15,6 +15,8 @@ use object::{
};
use crate::{
btf::BtfFeatures,
generated::{BPF_CALL, BPF_JMP, BPF_K},
maps::{BtfMap, LegacyMap, Map, MINIMUM_MAP_SIZE},
relocation::*,
thiserror::{self, Error},
@ -33,6 +35,16 @@ use crate::btf::{Array, DataSecEntry, FuncSecInfo, LineSecInfo};
const KERNEL_VERSION_ANY: u32 = 0xFFFF_FFFE;
/// Features implements BPF and BTF feature detection
#[derive(Default, Debug)]
#[allow(missing_docs)]
pub struct Features {
pub bpf_name: bool,
pub bpf_probe_read_kernel: bool,
pub bpf_perf_link: bool,
pub btf: Option<BtfFeatures>,
}
/// The loaded object file representation
#[derive(Clone)]
pub struct Object {
@ -878,6 +890,52 @@ impl Object {
Ok(())
}
/// Sanitize BPF programs.
pub fn sanitize_programs(&mut self, features: &Features) {
for program in self.programs.values_mut() {
program.sanitize(features);
}
}
}
fn insn_is_helper_call(ins: &bpf_insn) -> bool {
let klass = (ins.code & 0x07) as u32;
let op = (ins.code & 0xF0) as u32;
let src = (ins.code & 0x08) as u32;
klass == BPF_JMP && op == BPF_CALL && src == BPF_K && ins.src_reg() == 0 && ins.dst_reg() == 0
}
const BPF_FUNC_PROBE_READ: i32 = 4;
const BPF_FUNC_PROBE_READ_STR: i32 = 45;
const BPF_FUNC_PROBE_READ_USER: i32 = 112;
const BPF_FUNC_PROBE_READ_KERNEL: i32 = 113;
const BPF_FUNC_PROBE_READ_USER_STR: i32 = 114;
const BPF_FUNC_PROBE_READ_KERNEL_STR: i32 = 115;
impl Program {
fn sanitize(&mut self, features: &Features) {
for inst in &mut self.function.instructions {
if !insn_is_helper_call(inst) {
continue;
}
match inst.imm {
BPF_FUNC_PROBE_READ_USER | BPF_FUNC_PROBE_READ_KERNEL
if !features.bpf_probe_read_kernel =>
{
inst.imm = BPF_FUNC_PROBE_READ;
}
BPF_FUNC_PROBE_READ_USER_STR | BPF_FUNC_PROBE_READ_KERNEL_STR
if !features.bpf_probe_read_kernel =>
{
inst.imm = BPF_FUNC_PROBE_READ_STR;
}
_ => {}
}
}
}
}
// Parses multiple map definition contained in a single `maps` section (which is

@ -11,7 +11,7 @@ use aya_obj::{
btf::{BtfFeatures, BtfRelocationError},
generated::BPF_F_XDP_HAS_FRAGS,
relocation::BpfRelocationError,
BpfSectionKind,
BpfSectionKind, Features,
};
use log::debug;
use thiserror::Error;
@ -36,7 +36,7 @@ use crate::{
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_prog_name_supported, retry_with_verifier_logs,
is_probe_read_kernel_supported, is_prog_name_supported, retry_with_verifier_logs,
},
util::{bytes_of, bytes_of_slice, possible_cpus, VerifierLog, POSSIBLE_CPUS},
};
@ -66,39 +66,30 @@ unsafe impl<T: Pod, const N: usize> Pod for [T; N] {}
pub use aya_obj::maps::{bpf_map_def, PinningType};
lazy_static! {
pub(crate) static ref FEATURES: Features = Features::new();
pub(crate) static ref FEATURES: Features = detect_features();
}
// Features implements BPF and BTF feature detection
#[derive(Default, Debug)]
pub(crate) struct Features {
pub bpf_name: bool,
pub bpf_perf_link: bool,
pub btf: Option<BtfFeatures>,
}
impl Features {
fn new() -> Self {
let btf = if is_btf_supported() {
Some(BtfFeatures {
btf_func: is_btf_func_supported(),
btf_func_global: is_btf_func_global_supported(),
btf_datasec: is_btf_datasec_supported(),
btf_float: is_btf_float_supported(),
btf_decl_tag: is_btf_decl_tag_supported(),
btf_type_tag: is_btf_type_tag_supported(),
})
} else {
None
};
let f = Features {
bpf_name: is_prog_name_supported(),
bpf_perf_link: is_perf_link_supported(),
btf,
};
debug!("BPF Feature Detection: {:#?}", f);
f
}
fn detect_features() -> Features {
let btf = if is_btf_supported() {
Some(BtfFeatures {
btf_func: is_btf_func_supported(),
btf_func_global: is_btf_func_global_supported(),
btf_datasec: is_btf_datasec_supported(),
btf_float: is_btf_float_supported(),
btf_decl_tag: is_btf_decl_tag_supported(),
btf_type_tag: is_btf_type_tag_supported(),
})
} else {
None
};
let f = Features {
bpf_name: is_prog_name_supported(),
bpf_probe_read_kernel: is_probe_read_kernel_supported(),
bpf_perf_link: is_perf_link_supported(),
btf,
};
debug!("BPF Feature Detection: {:#?}", f);
f
}
/// Builder style API for advanced loading of eBPF programs.
@ -443,6 +434,7 @@ impl<'a> BpfLoader<'a> {
&text_sections,
)?;
obj.relocate_calls(&text_sections)?;
obj.sanitize_programs(&FEATURES);
let programs = obj
.programs

@ -599,6 +599,37 @@ pub(crate) fn is_prog_name_supported() -> bool {
}
}
pub(crate) fn is_probe_read_kernel_supported() -> bool {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
let u = unsafe { &mut attr.__bindgen_anon_3 };
let prog: &[u8] = &[
0xbf, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r1 = r10
0x07, 0x01, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, // r1 -= 8
0xb7, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // r2 = 8
0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r3 = 0
0x85, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, // call 113
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
];
let gpl = b"GPL\0";
u.license = gpl.as_ptr() as u64;
let insns = copy_instructions(prog).unwrap();
u.insn_cnt = insns.len() as u32;
u.insns = insns.as_ptr() as u64;
u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32;
match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) {
Ok(v) => {
let fd = v as RawFd;
unsafe { close(fd) };
true
}
Err(_) => false,
}
}
pub(crate) fn is_perf_link_supported() -> bool {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
let u = unsafe { &mut attr.__bindgen_anon_3 };

Loading…
Cancel
Save