diff --git a/Cargo.toml b/Cargo.toml index f765597f..f3cee151 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "aya-log-parser", "aya-obj", "aya-tool", + "ebpf-panic", "test-distro", "test/integration-common", "test/integration-test", @@ -33,6 +34,7 @@ default-members = [ "aya-log-parser", "aya-obj", "aya-tool", + "ebpf-panic", "test-distro", "test/integration-common", # test/integration-test is omitted; including it in this list causes `cargo test` to run its diff --git a/clippy.sh b/clippy.sh index b690f988..62de2bb5 100755 --- a/clippy.sh +++ b/clippy.sh @@ -2,11 +2,6 @@ set -eux -# We cannot run clippy over the whole workspace at once due to feature unification. Since both -# integration-test and integration-ebpf depend on integration-common and integration-test activates -# integration-common's aya dependency, we end up trying to compile the panic handler twice: once -# from the bpf program, and again from std via aya. -# # `-C panic=abort` because "unwinding panics are not supported without std"; integration-ebpf # contains `#[no_std]` binaries. # @@ -16,5 +11,4 @@ set -eux # unwinding behavior. # # `+nightly` because "the option `Z` is only accepted on the nightly compiler". -cargo +nightly hack clippy "$@" --exclude integration-ebpf --all-targets --feature-powerset --workspace -- --deny warnings -cargo +nightly hack clippy "$@" --package integration-ebpf --all-targets --feature-powerset -- --deny warnings -C panic=abort -Zpanic_abort_tests +cargo +nightly hack clippy "$@" --all-targets --feature-powerset -- --deny warnings -C panic=abort -Zpanic_abort_tests diff --git a/ebpf-panic/Cargo.toml b/ebpf-panic/Cargo.toml new file mode 100644 index 00000000..eb78e6f2 --- /dev/null +++ b/ebpf-panic/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "ebpf-panic" +publish = false +version = "1.0.0" + +authors.workspace = true +edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true diff --git a/ebpf-panic/src/lib.rs b/ebpf-panic/src/lib.rs new file mode 100644 index 00000000..4b4d86e2 --- /dev/null +++ b/ebpf-panic/src/lib.rs @@ -0,0 +1,33 @@ +//! A panic handler for eBPF rust targets. +//! +//! Panics are not supported in the eBPF rust targets however since crates for +//! the eBPF targets are no_std they must provide a panic handler. This crate +//! provides a panic handler that loops forever. Such a function, if called, +//! will cause the program to be rejected by the eBPF verifier with an error +//! message similar to: +//! +//! ```text +//! last insn is not an exit or jmp +//! ``` +//! +//! # Example +//! +//! ```ignore +//! #![no_std] +//! +//! use aya_ebpf::{macros::tracepoint, programs::TracePointContext}; +//! #[cfg(not(test))] +//! extern crate ebpf_panic; +//! +//! #[tracepoint] +//! pub fn test_tracepoint_one(_ctx: TracePointContext) -> u32 { +//! 0 +//! } +//! ``` +#![no_std] + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/test/integration-ebpf/Cargo.toml b/test/integration-ebpf/Cargo.toml index ed16b476..8f3eb3de 100644 --- a/test/integration-ebpf/Cargo.toml +++ b/test/integration-ebpf/Cargo.toml @@ -16,6 +16,7 @@ workspace = true [dependencies] aya-ebpf = { path = "../../ebpf/aya-ebpf" } aya-log-ebpf = { path = "../../ebpf/aya-log-ebpf" } +ebpf-panic = { path = "../../ebpf-panic" } integration-common = { path = "../integration-common" } network-types = { workspace = true } diff --git a/test/integration-ebpf/src/bpf_probe_read.rs b/test/integration-ebpf/src/bpf_probe_read.rs index a721163c..2a622a25 100644 --- a/test/integration-ebpf/src/bpf_probe_read.rs +++ b/test/integration-ebpf/src/bpf_probe_read.rs @@ -8,6 +8,8 @@ use aya_ebpf::{ programs::ProbeContext, }; use integration_common::bpf_probe_read::{RESULT_BUF_LEN, TestResult}; +#[cfg(not(test))] +extern crate ebpf_panic; fn read_str_bytes( fun: unsafe fn(*const u8, &mut [u8]) -> Result<&[u8], i64>, @@ -71,9 +73,3 @@ pub fn test_bpf_probe_read_kernel_str_bytes(ctx: ProbeContext) { ctx.arg::<usize>(0), ); } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/log.rs b/test/integration-ebpf/src/log.rs index b6471f3f..67228b53 100644 --- a/test/integration-ebpf/src/log.rs +++ b/test/integration-ebpf/src/log.rs @@ -5,6 +5,8 @@ use core::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use aya_ebpf::{macros::uprobe, programs::ProbeContext}; use aya_log_ebpf::{debug, error, info, trace, warn}; +#[cfg(not(test))] +extern crate ebpf_panic; #[uprobe] pub fn test_log(ctx: ProbeContext) { @@ -81,9 +83,3 @@ pub fn test_log(ctx: ProbeContext) { debug!(&ctx, "{:x}", no_copy.consume()); } } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/map_test.rs b/test/integration-ebpf/src/map_test.rs index e53b2f85..6eaf4123 100644 --- a/test/integration-ebpf/src/map_test.rs +++ b/test/integration-ebpf/src/map_test.rs @@ -9,6 +9,8 @@ use aya_ebpf::{ maps::{Array, HashMap}, programs::SkBuffContext, }; +#[cfg(not(test))] +extern crate ebpf_panic; // Introduced in kernel v3.19. #[map] @@ -35,9 +37,3 @@ pub fn simple_prog(_ctx: SkBuffContext) -> i64 { 0 } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/memmove_test.rs b/test/integration-ebpf/src/memmove_test.rs index f9002131..afadfc09 100644 --- a/test/integration-ebpf/src/memmove_test.rs +++ b/test/integration-ebpf/src/memmove_test.rs @@ -9,6 +9,8 @@ use aya_ebpf::{ maps::HashMap, programs::XdpContext, }; +#[cfg(not(test))] +extern crate ebpf_panic; use network_types::{ eth::{EthHdr, EtherType}, ip::Ipv6Hdr, @@ -53,9 +55,3 @@ fn try_do_dnat(ctx: XdpContext) -> Result<u32, ()> { } Ok(xdp_action::XDP_PASS) } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/name_test.rs b/test/integration-ebpf/src/name_test.rs index d1b48950..12d0d3f2 100644 --- a/test/integration-ebpf/src/name_test.rs +++ b/test/integration-ebpf/src/name_test.rs @@ -2,6 +2,8 @@ #![no_main] use aya_ebpf::{bindings::xdp_action, macros::xdp, programs::XdpContext}; +#[cfg(not(test))] +extern crate ebpf_panic; #[xdp] pub fn ihaveaverylongname(ctx: XdpContext) -> u32 { @@ -14,9 +16,3 @@ pub fn ihaveaverylongname(ctx: XdpContext) -> u32 { unsafe fn try_pass(_ctx: XdpContext) -> Result<u32, u32> { Ok(xdp_action::XDP_PASS) } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/pass.rs b/test/integration-ebpf/src/pass.rs index 795d82b0..63afc45d 100644 --- a/test/integration-ebpf/src/pass.rs +++ b/test/integration-ebpf/src/pass.rs @@ -2,6 +2,8 @@ #![no_main] use aya_ebpf::{bindings::xdp_action, macros::xdp, programs::XdpContext}; +#[cfg(not(test))] +extern crate ebpf_panic; // Note: the `frags` attribute causes this probe to be incompatible with kernel versions < 5.18.0. // See https://github.com/torvalds/linux/commit/c2f2cdb. @@ -16,9 +18,3 @@ pub fn pass(ctx: XdpContext) -> u32 { unsafe fn try_pass(_ctx: XdpContext) -> Result<u32, u32> { Ok(xdp_action::XDP_PASS) } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/raw_tracepoint.rs b/test/integration-ebpf/src/raw_tracepoint.rs index 1db9a21b..513d4ab5 100644 --- a/test/integration-ebpf/src/raw_tracepoint.rs +++ b/test/integration-ebpf/src/raw_tracepoint.rs @@ -6,6 +6,8 @@ use aya_ebpf::{ maps::Array, programs::RawTracePointContext, }; +#[cfg(not(test))] +extern crate ebpf_panic; use integration_common::raw_tracepoint::SysEnterEvent; #[map] @@ -25,9 +27,3 @@ pub fn sys_enter(ctx: RawTracePointContext) -> i32 { 0 } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/redirect.rs b/test/integration-ebpf/src/redirect.rs index eb32f999..b559c06d 100644 --- a/test/integration-ebpf/src/redirect.rs +++ b/test/integration-ebpf/src/redirect.rs @@ -7,6 +7,8 @@ use aya_ebpf::{ maps::{Array, CpuMap, DevMap, DevMapHash, XskMap}, programs::XdpContext, }; +#[cfg(not(test))] +extern crate ebpf_panic; #[map] static SOCKS: XskMap = XskMap::with_max_entries(1, 0); @@ -74,9 +76,3 @@ fn inc_hit(index: u32) { unsafe { *hit += 1 }; } } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/relocations.rs b/test/integration-ebpf/src/relocations.rs index dc9e71ca..03b0d342 100644 --- a/test/integration-ebpf/src/relocations.rs +++ b/test/integration-ebpf/src/relocations.rs @@ -8,6 +8,8 @@ use aya_ebpf::{ maps::Array, programs::ProbeContext, }; +#[cfg(not(test))] +extern crate ebpf_panic; #[map] static RESULTS: Array<u64> = Array::with_max_entries(3, 0); @@ -38,9 +40,3 @@ fn set_result(index: u32, value: u64) { fn set_result_backward(index: u32, value: u64) { set_result(index, value); } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/ring_buf.rs b/test/integration-ebpf/src/ring_buf.rs index 6674f5e6..e8825a8c 100644 --- a/test/integration-ebpf/src/ring_buf.rs +++ b/test/integration-ebpf/src/ring_buf.rs @@ -7,6 +7,8 @@ use aya_ebpf::{ programs::ProbeContext, }; use integration_common::ring_buf::Registers; +#[cfg(not(test))] +extern crate ebpf_panic; #[map] static RING_BUF: RingBuf = RingBuf::with_byte_size(0, 0); @@ -45,9 +47,3 @@ pub fn ring_buf_test(ctx: ProbeContext) { entry.discard(0); } } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/simple_prog.rs b/test/integration-ebpf/src/simple_prog.rs index 98725dce..ccb2e24e 100644 --- a/test/integration-ebpf/src/simple_prog.rs +++ b/test/integration-ebpf/src/simple_prog.rs @@ -5,15 +5,11 @@ #![no_main] use aya_ebpf::{macros::socket_filter, programs::SkBuffContext}; +#[cfg(not(test))] +extern crate ebpf_panic; // Introduced in kernel v3.19. #[socket_filter] pub fn simple_prog(_ctx: SkBuffContext) -> i64 { 0 } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/strncmp.rs b/test/integration-ebpf/src/strncmp.rs index a19b10d2..9b831157 100644 --- a/test/integration-ebpf/src/strncmp.rs +++ b/test/integration-ebpf/src/strncmp.rs @@ -9,6 +9,8 @@ use aya_ebpf::{ programs::ProbeContext, }; use integration_common::strncmp::TestResult; +#[cfg(not(test))] +extern crate ebpf_panic; #[map] static RESULT: Array<TestResult> = Array::with_max_entries(1, 0); @@ -26,9 +28,3 @@ pub fn test_bpf_strncmp(ctx: ProbeContext) -> Result<(), c_long> { Ok(()) } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/tcx.rs b/test/integration-ebpf/src/tcx.rs index 5ed3c211..0d173cd5 100644 --- a/test/integration-ebpf/src/tcx.rs +++ b/test/integration-ebpf/src/tcx.rs @@ -2,14 +2,10 @@ #![no_main] use aya_ebpf::{bindings::tcx_action_base::TCX_NEXT, macros::classifier, programs::TcContext}; +#[cfg(not(test))] +extern crate ebpf_panic; #[classifier] pub fn tcx_next(_ctx: TcContext) -> i32 { TCX_NEXT } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/test.rs b/test/integration-ebpf/src/test.rs index 417da0de..2dc736d3 100644 --- a/test/integration-ebpf/src/test.rs +++ b/test/integration-ebpf/src/test.rs @@ -8,6 +8,8 @@ use aya_ebpf::{ FlowDissectorContext, ProbeContext, RetProbeContext, TracePointContext, XdpContext, }, }; +#[cfg(not(test))] +extern crate ebpf_panic; #[xdp] pub fn pass(ctx: XdpContext) -> u32 { @@ -52,9 +54,3 @@ pub fn test_flow(_ctx: FlowDissectorContext) -> u32 { // Linux kernel for inspiration. bpf_ret_code::BPF_FLOW_DISSECTOR_CONTINUE } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/two_progs.rs b/test/integration-ebpf/src/two_progs.rs index 17d08168..98da3fce 100644 --- a/test/integration-ebpf/src/two_progs.rs +++ b/test/integration-ebpf/src/two_progs.rs @@ -4,6 +4,8 @@ #![no_main] use aya_ebpf::{macros::tracepoint, programs::TracePointContext}; +#[cfg(not(test))] +extern crate ebpf_panic; #[tracepoint] pub fn test_tracepoint_one(_ctx: TracePointContext) -> u32 { @@ -13,9 +15,3 @@ pub fn test_tracepoint_one(_ctx: TracePointContext) -> u32 { pub fn test_tracepoint_two(_ctx: TracePointContext) -> u32 { 0 } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/uprobe_cookie.rs b/test/integration-ebpf/src/uprobe_cookie.rs index 19713f85..56961aff 100644 --- a/test/integration-ebpf/src/uprobe_cookie.rs +++ b/test/integration-ebpf/src/uprobe_cookie.rs @@ -7,6 +7,8 @@ use aya_ebpf::{ maps::RingBuf, programs::ProbeContext, }; +#[cfg(not(test))] +extern crate ebpf_panic; #[map] static RING_BUF: RingBuf = RingBuf::with_byte_size(0, 0); @@ -17,9 +19,3 @@ pub fn uprobe_cookie(ctx: ProbeContext) { let cookie_bytes = cookie.to_le_bytes(); let _res = RING_BUF.output(&cookie_bytes, 0); } - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/test/integration-ebpf/src/xdp_sec.rs b/test/integration-ebpf/src/xdp_sec.rs index c9eed920..56fd586f 100644 --- a/test/integration-ebpf/src/xdp_sec.rs +++ b/test/integration-ebpf/src/xdp_sec.rs @@ -2,6 +2,8 @@ #![no_main] use aya_ebpf::{bindings::xdp_action::XDP_PASS, macros::xdp, programs::XdpContext}; +#[cfg(not(test))] +extern crate ebpf_panic; macro_rules! probe { ($name:ident, ($($arg:ident $(= $value:literal)?),*) ) => { @@ -18,9 +20,3 @@ probe!(xdp_cpumap, (map = "cpumap")); probe!(xdp_devmap, (map = "devmap")); probe!(xdp_frags_cpumap, (frags, map = "cpumap")); probe!(xdp_frags_devmap, (frags, map = "devmap")); - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -}