pull/1251/merge
Tamir Duberstein 1 week ago committed by GitHub
commit 69692548dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -300,13 +300,11 @@ jobs:
- name: Download debian kernels
if: runner.arch == 'ARM64'
# TODO: enable tests on kernels before 6.0.
run: .github/scripts/download_kernel_images.sh test/.tmp/debian-kernels/arm64 arm64 6.1 6.12
run: .github/scripts/download_kernel_images.sh test/.tmp/debian-kernels/arm64 arm64 5.10 6.1 6.12
- name: Download debian kernels
if: runner.arch == 'X64'
# TODO: enable tests on kernels before 6.0.
run: .github/scripts/download_kernel_images.sh test/.tmp/debian-kernels/amd64 amd64 6.1 6.12
run: .github/scripts/download_kernel_images.sh test/.tmp/debian-kernels/amd64 amd64 5.10 6.1 6.12
- name: Cleanup stale kernels and modules
run: |

@ -96,21 +96,21 @@ pub enum BtfError {
},
/// unknown BTF type id
#[error("Unknown BTF type id `{type_id}`")]
#[error("unknown BTF type id `{type_id}`")]
UnknownBtfType {
/// type id
type_id: u32,
},
/// unexpected btf type id
#[error("Unexpected BTF type id `{type_id}`")]
#[error("unexpected BTF type id `{type_id}`")]
UnexpectedBtfType {
/// type id
type_id: u32,
},
/// unknown BTF type
#[error("Unknown BTF type `{type_name}`")]
#[error("unknown BTF type `{type_name}`")]
UnknownBtfTypeName {
/// type name
type_name: String,
@ -125,7 +125,7 @@ pub enum BtfError {
#[cfg(feature = "std")]
/// Loading the btf failed
#[error("the BPF_BTF_LOAD syscall failed. Verifier output: {verifier_log}")]
#[error("the BPF_BTF_LOAD syscall returned {io_error}. Verifier output: {verifier_log}")]
LoadError {
/// The [`std::io::Error`] returned by the `BPF_BTF_LOAD` syscall.
#[source]

@ -50,7 +50,7 @@
use std::{
borrow::Borrow,
ffi::CString,
fmt, io,
io,
marker::PhantomData,
mem,
ops::Deref,
@ -60,8 +60,6 @@ use std::{
};
use aya_obj::{EbpfSectionKind, InvalidTypeBinding, generated::bpf_map_type, parse_map_info};
use libc::{RLIM_INFINITY, RLIMIT_MEMLOCK, getrlimit, rlim_t, rlimit};
use log::warn;
use thiserror::Error;
use crate::{
@ -71,7 +69,7 @@ use crate::{
SyscallError, bpf_create_map, bpf_get_object, bpf_map_freeze, bpf_map_get_fd_by_id,
bpf_map_get_next_key, bpf_map_update_elem_ptr, bpf_pin_object,
},
util::{KernelVersion, nr_cpus},
util::nr_cpus,
};
pub mod array;
@ -235,40 +233,6 @@ impl AsFd for MapFd {
}
}
/// Raises a warning about rlimit. Should be used only if creating a map was not
/// successful.
fn maybe_warn_rlimit() {
let mut limit = mem::MaybeUninit::<rlimit>::uninit();
let ret = unsafe { getrlimit(RLIMIT_MEMLOCK, limit.as_mut_ptr()) };
if ret == 0 {
let limit = unsafe { limit.assume_init() };
if limit.rlim_cur == RLIM_INFINITY {
return;
}
struct HumanSize(rlim_t);
impl fmt::Display for HumanSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let &Self(size) = self;
if size < 1024 {
write!(f, "{size} bytes")
} else if size < 1024 * 1024 {
write!(f, "{} KiB", size / 1024)
} else {
write!(f, "{} MiB", size / 1024 / 1024)
}
}
}
warn!(
"RLIMIT_MEMLOCK value is {}, not RLIM_INFINITY; if experiencing problems with creating \
maps, try raising RLIMIT_MEMLOCK either to RLIM_INFINITY or to a higher value sufficient \
for the size of your maps",
HumanSize(limit.rlim_cur)
);
}
}
/// eBPF map types.
#[derive(Debug)]
pub enum Map {
@ -576,16 +540,11 @@ impl MapData {
}
};
let fd = bpf_create_map(&c_name, &obj, btf_fd).map_err(|io_error| {
if !KernelVersion::at_least(5, 11, 0) {
maybe_warn_rlimit();
}
MapError::CreateError {
let fd =
bpf_create_map(&c_name, &obj, btf_fd).map_err(|io_error| MapError::CreateError {
name: name.into(),
io_error,
}
})?;
})?;
Ok(Self {
obj,
fd: MapFd::from_fd(fd),

@ -156,7 +156,7 @@ pub enum ProgramError {
NotAttached,
/// Loading the program failed.
#[error("the BPF_PROG_LOAD syscall failed. Verifier output: {verifier_log}")]
#[error("the BPF_PROG_LOAD syscall returned {io_error}. Verifier output: {verifier_log}")]
LoadError {
/// The [`io::Error`] returned by the `BPF_PROG_LOAD` syscall.
#[source]

@ -1,7 +1,7 @@
use std::{
cmp,
ffi::{CStr, CString, c_char},
io, iter,
fmt, io, iter,
mem::{self, MaybeUninit},
os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, FromRawFd as _, RawFd},
};
@ -22,7 +22,11 @@ use aya_obj::{
},
maps::{LegacyMap, bpf_map_def},
};
use libc::{ENOENT, ENOSPC};
use libc::{
EBADF, ENOENT, ENOSPC, EPERM, RLIM_INFINITY, RLIMIT_MEMLOCK, getrlimit, rlim_t, rlimit,
setrlimit,
};
use log::warn;
use crate::{
Btf, Pod, VerifierLogLevel,
@ -99,8 +103,7 @@ pub(crate) fn bpf_create_map(
.copy_from_slice(unsafe { mem::transmute::<&[u8], &[c_char]>(&name_bytes[..len]) });
}
// SAFETY: BPF_MAP_CREATE returns a new file descriptor.
unsafe { fd_sys_bpf(bpf_cmd::BPF_MAP_CREATE, &mut attr) }
bpf_map_create(&mut attr)
}
pub(crate) fn bpf_pin_object(fd: BorrowedFd<'_>, path: &CStr) -> io::Result<()> {
@ -695,6 +698,65 @@ pub(super) unsafe fn fd_sys_bpf(
Ok(unsafe { crate::MockableFd::from_raw_fd(fd) })
}
static RAISE_MEMLIMIT: std::sync::Once = std::sync::Once::new();
fn with_raised_rlimit_retry<T, F: FnMut() -> io::Result<T>>(mut op: F) -> io::Result<T> {
let mut result = op();
if matches!(result.as_ref(), Err(err) if err.raw_os_error() == Some(EPERM)) {
RAISE_MEMLIMIT.call_once(|| {
if KernelVersion::at_least(5, 11, 0) {
return;
}
let mut limit = mem::MaybeUninit::<rlimit>::uninit();
let ret = unsafe { getrlimit(RLIMIT_MEMLOCK, limit.as_mut_ptr()) };
if ret != 0 {
warn!("getrlimit(RLIMIT_MEMLOCK) failed: {ret}");
return;
}
let rlimit {
rlim_cur,
rlim_max: _,
} = unsafe { limit.assume_init() };
if rlim_cur == RLIM_INFINITY {
return;
}
let limit = rlimit {
rlim_cur: RLIM_INFINITY,
rlim_max: RLIM_INFINITY,
};
let ret = unsafe { setrlimit(RLIMIT_MEMLOCK, &limit) };
if ret != 0 {
struct HumanSize(rlim_t);
impl fmt::Display for HumanSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let &Self(size) = self;
if size < 1024 {
write!(f, "{size} bytes")
} else if size < 1024 * 1024 {
write!(f, "{} KiB", size / 1024)
} else {
write!(f, "{} MiB", size / 1024 / 1024)
}
}
}
warn!(
"setrlimit(RLIMIT_MEMLOCK, RLIM_INFINITIY) failed: {ret}; current value is {}",
HumanSize(rlim_cur)
);
}
});
// Retry after raising the limit.
result = op();
}
result
}
pub(super) fn bpf_map_create(attr: &mut bpf_attr) -> io::Result<crate::MockableFd> {
// SAFETY: BPF_MAP_CREATE returns a new file descriptor.
with_raised_rlimit_retry(|| unsafe { fd_sys_bpf(bpf_cmd::BPF_MAP_CREATE, attr) })
}
pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> Result<crate::MockableFd, SyscallError> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
attr.__bindgen_anon_6.__bindgen_anon_1.btf_id = id;
@ -849,7 +911,7 @@ pub(crate) fn is_perf_link_supported() -> bool {
None,
);
// Returns EINVAL if unsupported. EBADF if supported.
matches!(link, Err(err) if err.raw_os_error() == Some(libc::EBADF))
matches!(link, Err(err) if err.raw_os_error() == Some(EBADF))
} else {
false
}
@ -944,9 +1006,7 @@ pub(crate) fn is_prog_id_supported(map_type: bpf_map_type) -> bool {
u.max_entries = 1;
u.map_flags = 0;
// SAFETY: BPF_MAP_CREATE returns a new file descriptor.
let fd = unsafe { fd_sys_bpf(bpf_cmd::BPF_MAP_CREATE, &mut attr) };
fd.is_ok()
bpf_map_create(&mut attr).is_ok()
}
pub(crate) fn is_btf_supported() -> bool {
@ -1107,7 +1167,7 @@ pub(crate) fn is_btf_type_tag_supported() -> bool {
pub(super) fn bpf_prog_load(attr: &mut bpf_attr) -> io::Result<crate::MockableFd> {
// SAFETY: BPF_PROG_LOAD returns a new file descriptor.
unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, attr) }
with_raised_rlimit_retry(|| unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, attr) })
}
fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> io::Result<i64> {
@ -1225,7 +1285,7 @@ pub(crate) fn retry_with_verifier_logs<T>(
#[cfg(test)]
mod tests {
use libc::{EBADF, EINVAL};
use libc::EINVAL;
use super::*;
use crate::sys::override_syscall;

@ -10,7 +10,7 @@ use aya_obj::{
};
use libc::{E2BIG, EBADF, EINVAL};
use super::{SyscallError, bpf_prog_load, fd_sys_bpf, unit_sys_bpf, with_trivial_prog};
use super::{SyscallError, bpf_map_create, bpf_prog_load, unit_sys_bpf, with_trivial_prog};
use crate::{
MockableFd,
maps::MapType,
@ -278,13 +278,10 @@ pub fn is_map_supported(map_type: MapType) -> Result<bool, SyscallError> {
u_map.key_size = 1;
u_map.value_size = 1;
u_map.max_entries = 1;
// SAFETY: BPF_MAP_CREATE returns a new file descriptor.
inner_map_fd = unsafe { fd_sys_bpf(bpf_cmd::BPF_MAP_CREATE, &mut attr_map) }.map_err(
|io_error| SyscallError {
call: "bpf_map_create",
io_error,
},
)?;
inner_map_fd = bpf_map_create(&mut attr_map).map_err(|io_error| SyscallError {
call: "bpf_map_create",
io_error,
})?;
u.inner_map_fd = inner_map_fd.as_raw_fd() as u32;
}
@ -299,8 +296,8 @@ pub fn is_map_supported(map_type: MapType) -> Result<bool, SyscallError> {
}
// SAFETY: BPF_MAP_CREATE returns a new file descriptor.
let io_error = match unsafe { fd_sys_bpf(bpf_cmd::BPF_MAP_CREATE, &mut attr) } {
Ok(_) => return Ok(true),
let io_error = match bpf_map_create(&mut attr) {
Ok(_fd) => return Ok(true),
Err(io_error) => io_error,
};

@ -134,11 +134,12 @@ fn run() -> anyhow::Result<()> {
.map(|entry| {
let entry = entry.context("read_dir(/bin) failed")?;
let path = entry.path();
let status = std::process::Command::new(&path)
let mut cmd = std::process::Command::new(&path);
let status = cmd
.args(&args)
.env("RUST_LOG", "debug")
.status()
.with_context(|| format!("failed to execute {}", path.display()))?;
.with_context(|| format!("failed to execute {cmd:?}"))?;
if status.code() == Some(0) {
Ok(())

@ -1,8 +1,15 @@
use aya::{EbpfLoader, maps::ring_buf::RingBuf, programs::UProbe};
use aya::{EbpfLoader, maps::ring_buf::RingBuf, programs::UProbe, util::KernelVersion};
use test_log::test;
#[test]
fn test_uprobe_cookie() {
let kernel_version = KernelVersion::current().unwrap();
if kernel_version < KernelVersion::new(5, 15, 0) {
eprintln!(
"skipping test on kernel {kernel_version:?}, bpf_get_attach_cookie was added in 5.15"
);
return;
}
const RING_BUF_BYTE_SIZE: u32 = 512; // arbitrary, but big enough
let mut bpf = EbpfLoader::new()

Loading…
Cancel
Save