Merge branch 'main' into aya-guru

pull/1085/head
Kursat Aktas committed by GitHub
commit bd451d447f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -695,23 +695,17 @@ impl<'a> EbpfLoader<'a> {
.collect();
let maps = maps
.drain()
.map(parse_map)
.map(|data| parse_map(data, *allow_unsupported_maps))
.collect::<Result<HashMap<String, Map>, EbpfError>>()?;
if !*allow_unsupported_maps {
maps.iter().try_for_each(|(_, x)| match x {
Map::Unsupported(map) => Err(EbpfError::MapError(MapError::Unsupported {
map_type: map.obj().map_type(),
})),
_ => Ok(()),
})?;
};
Ok(Ebpf { maps, programs })
}
}
fn parse_map(data: (String, MapData)) -> Result<(String, Map), EbpfError> {
fn parse_map(
data: (String, MapData),
allow_unsupported_maps: bool,
) -> Result<(String, Map), EbpfError> {
let (name, map) = data;
let map_type = bpf_map_type::try_from(map.obj().map_type()).map_err(MapError::from)?;
let map = match map_type {
@ -735,9 +729,15 @@ fn parse_map(data: (String, MapData)) -> Result<(String, Map), EbpfError> {
BPF_MAP_TYPE_DEVMAP => Map::DevMap(map),
BPF_MAP_TYPE_DEVMAP_HASH => Map::DevMapHash(map),
BPF_MAP_TYPE_XSKMAP => Map::XskMap(map),
m => {
warn!("The map {name} is of type {:#?} which is currently unsupported in Aya, use `allow_unsupported_maps()` to load it anyways", m);
Map::Unsupported(map)
m_type => {
if allow_unsupported_maps {
Map::Unsupported(map)
} else {
return Err(EbpfError::MapError(MapError::Unsupported {
name,
map_type: m_type,
}));
}
}
};

@ -195,10 +195,14 @@ pub enum MapError {
ProgIdNotSupported,
/// Unsupported Map type
#[error("Unsupported map type found {map_type}")]
#[error(
"type of {name} ({map_type:?}) is unsupported; see `EbpfLoader::allow_unsupported_maps`"
)]
Unsupported {
/// Map name
name: String,
/// The map type
map_type: u32,
map_type: bpf_map_type,
},
}

@ -9,7 +9,11 @@
//! helpers, but also expose bindings to the underlying helpers as a fall-back
//! in case of a missing implementation.
use core::mem::{self, MaybeUninit};
use core::{
cmp::Ordering,
ffi::CStr,
mem::{self, MaybeUninit},
};
pub use aya_ebpf_bindings::helpers as gen;
#[doc(hidden)]
@ -838,3 +842,23 @@ pub unsafe fn bpf_printk_impl<const FMT_LEN: usize, const NUM_ARGS: usize>(
_ => gen::bpf_trace_vprintk(fmt_ptr, fmt_size, args.as_ptr() as _, (NUM_ARGS * 8) as _),
}
}
/// Compares the given byte `s1` with a [`&CStr`](core::ffi::CStr) `s2`.
///
/// # Examples
///
/// ```no_run
/// # use aya_ebpf::helpers::bpf_strncmp;
/// # let data = b"something";
/// assert_ne!(bpf_strncmp(data, c"foo"), core::cmp::Ordering::Equal);
/// ```
#[inline]
pub fn bpf_strncmp<const N: usize>(s1: &[u8; N], s2: &CStr) -> Ordering {
// NB: s1 does not need to be null-terminated.
//
// See https://github.com/torvalds/linux/blob/adc218676/include/uapi/linux/bpf.h#L5391-L5393.
//
// NB: s1's size must be known at compile time to appease the verifier. This is also the typical
// usage of strncmp in C programs.
unsafe { gen::bpf_strncmp(s1.as_ptr() as *const _, N as u32, s2.as_ptr() as *const _) }.cmp(&0)
}

@ -17,6 +17,10 @@ network-types = "0.0.7"
which = { workspace = true }
xtask = { path = "../../xtask" }
[[bin]]
name = "bpf_probe_read"
path = "src/bpf_probe_read.rs"
[[bin]]
name = "log"
path = "src/log.rs"
@ -25,6 +29,10 @@ path = "src/log.rs"
name = "map_test"
path = "src/map_test.rs"
[[bin]]
name = "memmove_test"
path = "src/memmove_test.rs"
[[bin]]
name = "name_test"
path = "src/name_test.rs"
@ -34,41 +42,37 @@ name = "pass"
path = "src/pass.rs"
[[bin]]
name = "test"
path = "src/test.rs"
[[bin]]
name = "tcx"
path = "src/tcx.rs"
name = "redirect"
path = "src/redirect.rs"
[[bin]]
name = "relocations"
path = "src/relocations.rs"
[[bin]]
name = "bpf_probe_read"
path = "src/bpf_probe_read.rs"
name = "ring_buf"
path = "src/ring_buf.rs"
[[bin]]
name = "two_progs"
path = "src/two_progs.rs"
name = "simple_prog"
path = "src/simple_prog.rs"
[[bin]]
name = "redirect"
path = "src/redirect.rs"
name = "strncmp"
path = "src/strncmp.rs"
[[bin]]
name = "xdp_sec"
path = "src/xdp_sec.rs"
name = "tcx"
path = "src/tcx.rs"
[[bin]]
name = "ring_buf"
path = "src/ring_buf.rs"
name = "test"
path = "src/test.rs"
[[bin]]
name = "memmove_test"
path = "src/memmove_test.rs"
name = "two_progs"
path = "src/two_progs.rs"
[[bin]]
name = "simple_prog"
path = "src/simple_prog.rs"
name = "xdp_sec"
path = "src/xdp_sec.rs"

@ -0,0 +1,38 @@
#![no_std]
#![no_main]
use core::cmp::Ordering;
use aya_ebpf::{
cty::c_long,
helpers::{bpf_probe_read_user_str_bytes, bpf_strncmp},
macros::{map, uprobe},
maps::Array,
programs::ProbeContext,
};
#[repr(C)]
struct TestResult(Ordering);
#[map]
static RESULT: Array<TestResult> = Array::with_max_entries(1, 0);
#[uprobe]
pub fn test_bpf_strncmp(ctx: ProbeContext) -> Result<(), c_long> {
let s1: *const u8 = ctx.arg(0).ok_or(-1)?;
let mut b1 = [0u8; 3];
let _: &[u8] = unsafe { bpf_probe_read_user_str_bytes(s1, &mut b1) }?;
let ptr = RESULT.get_ptr_mut(0).ok_or(-1)?;
let dst = unsafe { ptr.as_mut() };
let TestResult(dst_res) = dst.ok_or(-1)?;
*dst_res = bpf_strncmp(&b1, c"ff");
Ok(())
}
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}

@ -12,21 +12,22 @@ pub const TEXT_64_64_RELOC: &[u8] =
pub const VARIABLES_RELOC: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/variables_reloc.bpf.o"));
pub const BPF_PROBE_READ: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/bpf_probe_read"));
pub const LOG: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/log"));
pub const MAP_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/map_test"));
pub const MEMMOVE_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/memmove_test"));
pub const NAME_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/name_test"));
pub const PASS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/pass"));
pub const REDIRECT: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/redirect"));
pub const RELOCATIONS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/relocations"));
pub const RING_BUF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/ring_buf"));
pub const SIMPLE_PROG: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/simple_prog"));
pub const STRNCMP: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/strncmp"));
pub const TCX: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/tcx"));
pub const TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/test"));
pub const RELOCATIONS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/relocations"));
pub const TWO_PROGS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/two_progs"));
pub const BPF_PROBE_READ: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/bpf_probe_read"));
pub const REDIRECT: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/redirect"));
pub const XDP_SEC: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/xdp_sec"));
pub const RING_BUF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/ring_buf"));
pub const MEMMOVE_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/memmove_test"));
pub const SIMPLE_PROG: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/simple_prog"));
#[cfg(test)]
mod tests;

@ -8,5 +8,6 @@ mod rbpf;
mod relocations;
mod ring_buf;
mod smoke;
mod strncmp;
mod tcx;
mod xdp;

@ -0,0 +1,55 @@
use std::{
cmp::Ordering,
ffi::{c_char, CStr},
};
use aya::{
maps::{Array, MapData},
programs::UProbe,
Ebpf,
};
#[derive(Copy, Clone)]
#[repr(C)]
struct TestResult(Ordering);
unsafe impl aya::Pod for TestResult {}
#[test]
fn bpf_strncmp() {
let mut bpf = Ebpf::load(crate::STRNCMP).unwrap();
{
let prog: &mut UProbe = bpf
.program_mut("test_bpf_strncmp")
.unwrap()
.try_into()
.unwrap();
prog.load().unwrap();
prog.attach(Some("trigger_bpf_strncmp"), 0, "/proc/self/exe", None)
.unwrap();
}
let array = Array::<_, TestResult>::try_from(bpf.map("RESULT").unwrap()).unwrap();
assert_eq!(do_bpf_strncmp(&array, c"ff"), Ordering::Equal);
// This is truncated in BPF; the buffer size is 3 including the null terminator.
assert_eq!(do_bpf_strncmp(&array, c"fff"), Ordering::Equal);
assert_eq!(do_bpf_strncmp(&array, c"aa"), Ordering::Less);
assert_eq!(do_bpf_strncmp(&array, c"zz"), Ordering::Greater);
}
fn do_bpf_strncmp(array: &Array<&MapData, TestResult>, s1: &CStr) -> Ordering {
trigger_bpf_strncmp(s1.as_ptr());
let TestResult(ord) = array.get(&0, 0).unwrap();
ord
}
#[no_mangle]
#[inline(never)]
pub extern "C" fn trigger_bpf_strncmp(s1: *const c_char) {
core::hint::black_box(s1);
}

@ -76,6 +76,7 @@ pub unsafe fn aya_ebpf::helpers::bpf_probe_read_user_buf(src: *const u8, dst: &m
pub unsafe fn aya_ebpf::helpers::bpf_probe_read_user_str(src: *const u8, dest: &mut [u8]) -> core::result::Result<usize, aya_ebpf_cty::od::c_long>
pub unsafe fn aya_ebpf::helpers::bpf_probe_read_user_str_bytes(src: *const u8, dest: &mut [u8]) -> core::result::Result<&[u8], aya_ebpf_cty::od::c_long>
pub unsafe fn aya_ebpf::helpers::bpf_probe_write_user<T>(dst: *mut T, src: *const T) -> core::result::Result<(), aya_ebpf_cty::od::c_long>
pub fn aya_ebpf::helpers::bpf_strncmp<const N: usize>(s1: &[u8; N], s2: &core::ffi::c_str::CStr) -> core::cmp::Ordering
pub mod aya_ebpf::maps
pub mod aya_ebpf::maps::array
#[repr(transparent)] pub struct aya_ebpf::maps::array::Array<T>

@ -1362,7 +1362,8 @@ pub aya::maps::MapError::ProgIdNotSupported
pub aya::maps::MapError::ProgramNotLoaded
pub aya::maps::MapError::SyscallError(aya::sys::SyscallError)
pub aya::maps::MapError::Unsupported
pub aya::maps::MapError::Unsupported::map_type: u32
pub aya::maps::MapError::Unsupported::map_type: aya_obj::generated::linux_bindings_x86_64::bpf_map_type
pub aya::maps::MapError::Unsupported::name: alloc::string::String
impl core::convert::From<aya::maps::MapError> for aya::EbpfError
pub fn aya::EbpfError::from(source: aya::maps::MapError) -> Self
impl core::convert::From<aya::maps::MapError> for aya::maps::xdp::XdpMapError

Loading…
Cancel
Save