Skip to content

Commit

Permalink
implemented task clone probe and event
Browse files Browse the repository at this point in the history
Signed-off-by: Quentin JEROME <[email protected]>
  • Loading branch information
qjerome committed Sep 22, 2023
1 parent aa61c4c commit b8d2705
Show file tree
Hide file tree
Showing 13 changed files with 218 additions and 37 deletions.
5 changes: 4 additions & 1 deletion kunai-common/src/co_re.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
#[allow(dead_code)]
// made public for debug
// todo: remove pub
pub mod gen;

mod core_task_struct;
Expand Down Expand Up @@ -44,6 +44,9 @@ pub use core_cgroup::*;
mod core_kernfs;
pub use core_kernfs::*;

mod core_clone_args;
pub use core_clone_args::*;

#[derive(Clone, Copy)]
pub struct CoRe<P> {
ptr: *const P,
Expand Down
25 changes: 13 additions & 12 deletions kunai-common/src/co_re/c/shim.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,7 @@ struct task_struct
pid_t pid;
__u64 start_time;
// attempt to make compatible with older kernels
union
{
union {
__u64 start_boottime;
__u64 real_start_time;
};
Expand Down Expand Up @@ -455,8 +454,7 @@ typedef __u32 __portpair;

struct in6_addr
{
union
{
union {
__u8 u6_addr8[16];
__be16 u6_addr16[8];
__be32 u6_addr32[4];
Expand Down Expand Up @@ -507,13 +505,11 @@ SHIM_REF(sockaddr_in6, sin6_addr);

struct sock_common
{
union
{
union {
__addrpair skc_addrpair;
};

union
{
union {
__portpair skc_portpair;
};

Expand Down Expand Up @@ -596,13 +592,11 @@ SHIM(iovec, iov_len);
struct iov_iter
{
size_t count;
union
{
union {
struct iovec *iov;
};

union
{
union {
unsigned long nr_segs;
};
} __attribute__((preserve_access_index));
Expand Down Expand Up @@ -630,3 +624,10 @@ SHIM(user_msghdr, msg_name);
SHIM(user_msghdr, msg_namelen);
SHIM(user_msghdr, msg_iov);
SHIM(user_msghdr, msg_iovlen);

struct kernel_clone_args
{
u64 flags;
} __attribute__((preserve_access_index));

SHIM(kernel_clone_args, flags);
9 changes: 9 additions & 0 deletions kunai-common/src/co_re/core_clone_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use super::gen::{self, *};
use super::{rust_shim_kernel_impl, CoRe};

#[allow(non_camel_case_types)]
pub type kernel_clone_args = CoRe<gen::kernel_clone_args>;

impl kernel_clone_args {
rust_shim_kernel_impl!(kernel_clone_args, flags, u64);
}
19 changes: 19 additions & 0 deletions kunai-common/src/co_re/gen.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* automatically generated by rust-bindgen 0.66.1 */

pub type __u64 = ::core::ffi::c_ulonglong;
pub type u64_ = __u64;
pub type __u32 = ::core::ffi::c_uint;
pub type __u16 = ::core::ffi::c_ushort;
pub type u16_ = __u16;
Expand Down Expand Up @@ -1432,3 +1433,21 @@ extern "C" {
extern "C" {
pub fn shim_user_msghdr_msg_iovlen_exists(user_msghdr: *mut user_msghdr) -> bool;
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct kernel_clone_args {
pub flags: u64_,
}
extern "C" {
pub fn shim_kernel_clone_args_flags(
kernel_clone_args: *mut kernel_clone_args,
) -> ::core::ffi::c_ulonglong;
}
extern "C" {
pub fn shim_kernel_clone_args_flags_user(
kernel_clone_args: *mut kernel_clone_args,
) -> ::core::ffi::c_ulonglong;
}
extern "C" {
pub fn shim_kernel_clone_args_flags_exists(kernel_clone_args: *mut kernel_clone_args) -> bool;
}
24 changes: 16 additions & 8 deletions kunai-common/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ bpf_target_code! {
use crate::co_re::core_read_kernel;
use crate::co_re::task_struct;
use aya_bpf::helpers::{bpf_get_current_task, bpf_ktime_get_ns};
use aya_bpf::cty::{c_void};
use kunai_macros::BpfError;
}

Expand All @@ -22,6 +21,8 @@ mod connect;
pub use connect::*;
mod execve;
pub use execve::*;
mod clone;
pub use clone::*;
mod mmap;
use kunai_macros::StrEnum;
pub use mmap::*;
Expand Down Expand Up @@ -71,6 +72,8 @@ pub enum Type {
Exit,
#[str("exit_group")]
ExitGroup,
#[str("clone")]
Clone,

// stuff loaded in kernel
#[str("init_module")]
Expand Down Expand Up @@ -220,7 +223,7 @@ bpf_target_code! {
/// # Safety
/// * task must be a pointer to a valid task_struct
#[inline(always)]
pub(crate) unsafe fn from_task(&mut self, task: &task_struct) -> Result<(), Error> {
pub unsafe fn from_task(&mut self, task: task_struct) -> Result<(), Error> {
// process start time
self.start_time = task.start_boottime().ok_or(Error::BootTimeMissing)?;
self.tgid = task.tgid().ok_or(Error::TgidFieldMissing)?;
Expand Down Expand Up @@ -279,17 +282,17 @@ impl EventInfo {
#[cfg(target_arch = "bpf")]
impl EventInfo {
#[inline(always)]
pub(crate) unsafe fn init(&mut self, t: Type, task: *const c_void) -> Result<(), Error> {
pub(crate) unsafe fn init(&mut self, t: Type, task: task_struct) -> Result<(), Error> {
self.etype = t;

// create a new Uuid for event
self.uuid = Uuid::new_random();

if !task.is_null() {
let task = task_struct::from_ptr(task as *const _);
self.process.from_task(&task)?;
//let task = task_struct::from_ptr(task as *const _);
self.process.from_task(task)?;
self.parent
.from_task(&task.real_parent().ok_or(Error::RealParentFieldMissing)?)?;
.from_task(task.real_parent().ok_or(Error::RealParentFieldMissing)?)?;
}

//self.timestamp = bpf_ktime_get_boot_ns();
Expand Down Expand Up @@ -346,8 +349,12 @@ bpf_target_code! {
impl<T> Event<T> {
#[inline(always)]
pub unsafe fn init_from_current_task(&mut self, ty: Type) -> Result<(), Error> {
let t = bpf_get_current_task() as *const c_void;
self.info.init(ty, t)?;
self.init_from_task(ty, task_struct::from_ptr(bpf_get_current_task() as *const _))
}

#[inline(always)]
pub unsafe fn init_from_task(&mut self, ty: Type, ts: task_struct) -> Result<(), Error> {
self.info.init(ty, ts)?;
Ok(())
}
}
Expand Down Expand Up @@ -467,6 +474,7 @@ macro_rules! max {

pub const MAX_EVENT_SIZE: usize = max!(
core::mem::size_of::<ExecveEvent>(),
core::mem::size_of::<CloneEvent>(),
core::mem::size_of::<BpfProgLoadEvent>(),
core::mem::size_of::<BpfSocketFilterEvent>(),
core::mem::size_of::<ConnectEvent>(),
Expand Down
13 changes: 13 additions & 0 deletions kunai-common/src/events/clone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use crate::{buffer::Buffer, cgroup::Cgroup, path::Path};

use super::{Event, MAX_ARGV_SIZE};

pub type CloneEvent = Event<CloneData>;

#[repr(C)]
pub struct CloneData {
pub flags: u64,
pub executable: Path,
pub argv: Buffer<MAX_ARGV_SIZE>,
pub cgroup: Cgroup,
}
21 changes: 16 additions & 5 deletions kunai-common/src/events/correlation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@


use super::{MmapExecEvent, ScheduleEvent};
use super::{CloneEvent, MmapExecEvent, ScheduleEvent};
use crate::path::Path;
use crate::{buffer::Buffer, cgroup::Cgroup};

Expand Down Expand Up @@ -32,7 +30,6 @@ impl From<&ExecveEvent> for CorrelationEvent {
Self {
info: value.info,
data: CorrelationData {
//origin: value.info.etype,
argv: value.data.argv,
exe: value.data.executable,
paths: [Some(value.data.interpreter)],
Expand All @@ -43,12 +40,26 @@ impl From<&ExecveEvent> for CorrelationEvent {
}
}

impl From<&CloneEvent> for CorrelationEvent {
fn from(value: &CloneEvent) -> Self {
Self {
info: value.info,
data: CorrelationData {
argv: value.data.argv,
exe: value.data.executable,
paths: [None],
cgroup: value.data.cgroup,
},
}
.switch_type(Type::Correlation)
}
}

impl From<&ScheduleEvent> for CorrelationEvent {
fn from(value: &ScheduleEvent) -> Self {
Self {
info: value.info,
data: CorrelationData {
//origin: value.info.etype,
argv: value.data.argv,
exe: value.data.exe,
paths: [None],
Expand Down
11 changes: 5 additions & 6 deletions kunai-ebpf/src/probes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ use kunai_common::{
syscalls::*,
};

#[cfg(debug)]
#[cfg(feature = "debug")]
mod debug;

mod bpf;
mod bpf_socket;
mod clone;
mod connect;
mod dns;
mod execve;
Expand All @@ -35,11 +36,9 @@ mod schedule;
mod send_data;

macro_rules! ignore_result {
($res:expr) => {
match $res {
Ok(_) | Err(_) => {}
}
};
($res:expr) => {{
let _ = $res;
}};
}

use ignore_result;
Expand Down
75 changes: 75 additions & 0 deletions kunai-ebpf/src/probes/clone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use aya_bpf::programs::ProbeContext;
use kunai_common::co_re::{kernel_clone_args, task_struct};

use super::*;

#[kprobe(name = "enter.wake_up_new_task")]
pub fn enter_wake_up_new_task(ctx: ProbeContext) -> u32 {
match unsafe { try_enter_wake_up_new_task(&ctx) } {
Ok(_) => error::BPF_PROG_SUCCESS,
Err(s) => {
log_err!(&ctx, s);
error::BPF_PROG_FAILURE
}
}
}

unsafe fn try_enter_wake_up_new_task(ctx: &ProbeContext) -> ProbeResult<()> {
// makes sure we are inside kernel_clone
if let Ok(entry_ctx) = restore_entry_ctx(ProbeFn::kernel_clone)
.ok_or(ProbeError::KProbeCtxRestoreFailure)
.and_then(|c| Ok(c.restore()))
{
let clone_args = kernel_clone_args::from_ptr(kprobe_arg!(&entry_ctx, 0)?);
let new_task = task_struct::from_ptr(kprobe_arg!(ctx, 0)?);
alloc::init()?;

let event = alloc::alloc_zero::<CloneEvent>()?;

// initializing task
event.init_from_task(Type::Clone, new_task)?;

// setting clone flags
event.data.flags = core_read_kernel!(clone_args, flags)?;

let mm = core_read_kernel!(new_task, mm)?;

if mm.is_null() {
return Ok(());
}

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

// parsing executable
let exe_file = core_read_kernel!(mm, exe_file)?;
inspect_err!(
event
.data
.executable
.core_resolve_file(&exe_file, MAX_PATH_DEPTH),
|e: path::Error| error!(ctx, "failed to resolve exe: {}", e.description())
);

// we check that arg_start is not a null pointer
if arg_start != 0 && arg_len != 0 {
inspect_err!(
event
.data
.argv
.read_user_at(arg_start as *const u8, arg_len as u32),
|_| error!(ctx, "failed to read argv")
);
}

// cgroup parsing
let cgroup = core_read_kernel!(new_task, sched_task_group, css, cgroup)?;
if let Err(e) = event.data.cgroup.resolve(cgroup) {
error!(ctx, "failed to resolve cgroup: {}", e.description());
}

pipe_event(ctx, event)
}

Ok(())
}
3 changes: 1 addition & 2 deletions kunai-ebpf/src/probes/execve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ unsafe fn try_security_bprm_check(ctx: &ProbeContext) -> ProbeResult<()> {
return Ok(());
}

// TEST
// we keep track of linux_binprm
if !linux_binprm.is_null() {
ignore_result!(BPRM_EXECVE_ARGS.insert(&bpf_task_tracking_id(), &linux_binprm, 0))
}
// END test

alloc::init()?;
let event = alloc::alloc_zero::<ExecveEvent>()?;
Expand Down
12 changes: 12 additions & 0 deletions kunai-ebpf/src/probes/save.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,15 @@ pub fn enter_reuseport_attach_prog(ctx: ProbeContext) -> u32 {
}
0
}

#[kprobe(name = "kprobe.enter.kernel_clone")]
pub fn enter_kernel_clone(ctx: ProbeContext) -> u32 {
unsafe {
ignore_result!(save_context(
ProbeFn::kernel_clone,
bpf_ktime_get_ns(),
&ctx
));
}
0
}
Loading

0 comments on commit b8d2705

Please sign in to comment.