Skip to content

Commit

Permalink
fix: attempt execve rare error (#167)
Browse files Browse the repository at this point in the history
* fix: attempt execve rare error
This PR attempts at fixing a rare error happening in `execve` probe (see #159)

The occurence of this error seems pretty random, so it is impossible to replicate (so far).

Thus some code review has been done on the probe and we fix possible cause of this error:
- the probe uses two maps of different sizes, that may cause data to be missing in one of them -> fix: put the same size for both the maps

* add: bpf lru hashmap cleanup + comments

* change: execve probe
- offload work from execve_event to try_security_bprm_check
- changed MAP_SIZE to 2048 instead of 4096
  • Loading branch information
qjerome authored Jan 17, 2025
1 parent 729f4ec commit 29e3bb1
Showing 1 changed file with 21 additions and 18 deletions.
39 changes: 21 additions & 18 deletions kunai-ebpf/src/probes/execve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ use aya_ebpf::EbpfContext;
use co_re::task_struct;
use kunai_common::syscalls::SysExitArgs;

const MAP_SIZE: u32 = 2048;

#[map]
static mut EXECVE_TRACKING: LruHashMap<u128, ExecveEvent> = LruHashMap::with_max_entries(4096, 0);
static mut EXECVE_TRACKING: LruHashMap<u128, ExecveEvent> =
LruHashMap::with_max_entries(MAP_SIZE, 0);

// this guy gives us the real executable path (i.e. a script for instance)
// we need to hook at another point in order to get the interpreter. For
Expand All @@ -30,8 +33,8 @@ pub fn execve_security_bprm_check(ctx: ProbeContext) -> u32 {

unsafe fn try_security_bprm_check(ctx: &ProbeContext) -> ProbeResult<()> {
let linux_binprm = co_re::linux_binprm::from_ptr(ctx.arg(0).unwrap_or(core::ptr::null()));
let ts = co_re::task_struct::current();
let task_uuid = ts.uuid();
let current = co_re::task_struct::current();
let task_uuid = current.uuid();

if EXECVE_TRACKING.get_ptr_mut(&task_uuid).is_some() {
// security_bprm_check is running in a loop
Expand All @@ -54,6 +57,13 @@ unsafe fn try_security_bprm_check(ctx: &ProbeContext) -> ProbeResult<()> {
.core_resolve_file(&file, MAX_PATH_DEPTH)?;
}

// read uts nodename and store it in event
// it was put here to offload a bit from execve_event
event.data.nodename.read_kernel_at(
core_read_kernel!(current, nsproxy, uts_ns, name, nodename)?,
event.data.nodename.cap() as u32,
)?;

EXECVE_TRACKING
.insert(&task_uuid, event, 0)
.map_err(|_| MapError::InsertFailure)?;
Expand All @@ -63,7 +73,7 @@ unsafe fn try_security_bprm_check(ctx: &ProbeContext) -> ProbeResult<()> {

#[map]
static mut BPRM_EXECVE_ARGS: LruHashMap<u64, co_re::linux_binprm> =
LruHashMap::with_max_entries(1024, 0);
LruHashMap::with_max_entries(MAP_SIZE, 0);

// for kernel < 5.9 bprm_execve does not exists, we must replace the hook
// by __do_execve_file (done in program loader)
Expand All @@ -89,24 +99,16 @@ unsafe fn execve_event<C: EbpfContext>(ctx: &C, rc: i32) -> ProbeResult<()> {
.get(&bpf_task_tracking_id())
.ok_or(MapError::GetFailure)?;

let ts = task_struct::current();
let current = task_struct::current();

let task_uuid = ts.uuid();
let task_uuid = current.uuid();

let event = EXECVE_TRACKING
.get_ptr_mut(&task_uuid)
.ok_or(MapError::GetFailure)?;

let event = &mut (*event);

let current = task_struct::current();

// getting nodename first as we need the current task struct
event.data.nodename.read_kernel_at(
core_read_kernel!(current, nsproxy, uts_ns, name, nodename)?,
event.data.nodename.cap() as u32,
)?;

// initializing event
event.init_from_task(Type::Execve, current)?;

Expand All @@ -121,8 +123,8 @@ unsafe fn execve_event<C: EbpfContext>(ctx: &C, rc: i32) -> ProbeResult<()> {

event.data.rc = rc;

let arg_start = core_read_kernel!(ts, mm, arg_start)?;
let arg_len = core_read_kernel!(ts, mm, arg_len)?;
let arg_start = core_read_kernel!(current, mm, arg_start)?;
let arg_len = core_read_kernel!(current, mm, arg_len)?;

// parsing argv
if event
Expand All @@ -135,14 +137,15 @@ unsafe fn execve_event<C: EbpfContext>(ctx: &C, rc: i32) -> ProbeResult<()> {
}

// cgroup parsing
let cgroup = core_read_kernel!(ts, sched_task_group, css, cgroup)?;
let cgroup = core_read_kernel!(current, sched_task_group, css, cgroup)?;
// we do not raise any error on cgroup parsing, we let a chance to userland to solve it
ignore_result!(event.data.cgroup.resolve(cgroup));

pipe_event(ctx, event);

// we use a LruHashMap so we can safely ignore result
// we use LruHashMap so we can safely ignore results
ignore_result!(EXECVE_TRACKING.remove(&task_uuid));
ignore_result!(BPRM_EXECVE_ARGS.remove(&bpf_task_tracking_id()));

Ok(())
}
Expand Down

0 comments on commit 29e3bb1

Please sign in to comment.