From bc07089191fa995ba2ae1f9cec18f3397fda561a Mon Sep 17 00:00:00 2001 From: qjerome Date: Tue, 26 Nov 2024 17:27:15 +0100 Subject: [PATCH 1/2] =?UTF-8?q?add:=C2=A0f=5Fflags=20and=20f=5Fmode=20if?= =?UTF-8?q?=20file=20struct=20shim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kunai-common/src/co_re/c/shim.c | 4 ++++ kunai-common/src/co_re/core_fs.rs | 2 ++ kunai-common/src/co_re/gen.rs | 20 ++++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/kunai-common/src/co_re/c/shim.c b/kunai-common/src/co_re/c/shim.c index f53a671..8d72b0a 100644 --- a/kunai-common/src/co_re/c/shim.c +++ b/kunai-common/src/co_re/c/shim.c @@ -242,11 +242,15 @@ struct file struct inode *f_inode; struct path f_path; void *private_data; + unsigned int f_flags; + unsigned int f_mode; } __attribute__((preserve_access_index)); SHIM_REF(file, f_path); SHIM(file, f_inode); SHIM(file, private_data); +SHIM(file, f_flags); +SHIM(file, f_mode); struct fd { diff --git a/kunai-common/src/co_re/core_fs.rs b/kunai-common/src/co_re/core_fs.rs index b4711e9..e82d4ba 100644 --- a/kunai-common/src/co_re/core_fs.rs +++ b/kunai-common/src/co_re/core_fs.rs @@ -56,6 +56,8 @@ pub type file = CoRe; impl file { rust_shim_kernel_impl!(pub, file, f_path, path); rust_shim_kernel_impl!(pub, file, f_inode, inode); + rust_shim_kernel_impl!(pub, file, f_flags, u32); + rust_shim_kernel_impl!(pub, file, f_mode, u32); #[inline(always)] pub unsafe fn is_file(&self) -> Option { diff --git a/kunai-common/src/co_re/gen.rs b/kunai-common/src/co_re/gen.rs index 7f87030..3e7d265 100644 --- a/kunai-common/src/co_re/gen.rs +++ b/kunai-common/src/co_re/gen.rs @@ -366,6 +366,8 @@ pub struct file { pub f_inode: *mut inode, pub f_path: path, pub private_data: *mut ::core::ffi::c_void, + pub f_flags: ::core::ffi::c_uint, + pub f_mode: ::core::ffi::c_uint, } extern "C" { pub fn shim_file_f_path(file: *mut file) -> *mut path; @@ -394,6 +396,24 @@ extern "C" { extern "C" { pub fn shim_file_private_data_exists(file: *mut file) -> bool; } +extern "C" { + pub fn shim_file_f_flags(file: *mut file) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn shim_file_f_flags_user(file: *mut file) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn shim_file_f_flags_exists(file: *mut file) -> bool; +} +extern "C" { + pub fn shim_file_f_mode(file: *mut file) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn shim_file_f_mode_user(file: *mut file) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn shim_file_f_mode_exists(file: *mut file) -> bool; +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct fd { From eabc7a7703dae405a2fd79f28652c6edbc06295a Mon Sep 17 00:00:00 2001 From: qjerome Date: Tue, 26 Nov 2024 17:30:04 +0100 Subject: [PATCH 2/2] =?UTF-8?q?feat:=C2=A0file=5Fcreate=20event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kunai-common/src/bpf_events.rs | 2 ++ kunai-common/src/bpf_events/events.rs | 9 ++++-- kunai-ebpf/src/probes/fs.rs | 42 +++++++++++++++++++++++++++ kunai/src/bin/main.rs | 22 ++++++++------ 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/kunai-common/src/bpf_events.rs b/kunai-common/src/bpf_events.rs index 57596f1..e405164 100644 --- a/kunai-common/src/bpf_events.rs +++ b/kunai-common/src/bpf_events.rs @@ -115,6 +115,8 @@ pub enum Type { FileUnlink, #[str("write_close")] WriteClose, + #[str("file_create")] + FileCreate, // specific userland events // those should never be used in eBPF diff --git a/kunai-common/src/bpf_events/events.rs b/kunai-common/src/bpf_events/events.rs index cf7540c..b47f71a 100644 --- a/kunai-common/src/bpf_events/events.rs +++ b/kunai-common/src/bpf_events/events.rs @@ -77,9 +77,12 @@ const fn max_bpf_event_size() -> usize { Type::Connect => ConnectEvent::size_of(), Type::DnsQuery => DnsQueryEvent::size_of(), Type::SendData => SendEntropyEvent::size_of(), - Type::Read | Type::ReadConfig | Type::Write | Type::WriteConfig | Type::WriteClose => { - FileEvent::size_of() - } + Type::Read + | Type::ReadConfig + | Type::Write + | Type::WriteConfig + | Type::WriteClose + | Type::FileCreate => FileEvent::size_of(), Type::FileRename => FileRenameEvent::size_of(), Type::FileUnlink => UnlinkEvent::size_of(), Type::Error => ErrorEvent::size_of(), diff --git a/kunai-ebpf/src/probes/fs.rs b/kunai-ebpf/src/probes/fs.rs index a6df71e..d79b018 100644 --- a/kunai-ebpf/src/probes/fs.rs +++ b/kunai-ebpf/src/probes/fs.rs @@ -447,3 +447,45 @@ unsafe fn try_enter_fput(ctx: &ProbeContext) -> ProbeResult<()> { // and re-write the file file_unset_flag(&file, CLOSE_AFTER_WRITE) } + +const FMODE_CREATED: u32 = 0x100000; + +// this probe aims at catching file creation event +#[kprobe(function = "security_file_open")] +pub fn fs_security_file_open(ctx: ProbeContext) -> u32 { + if is_current_loader_task() { + return 0; + } + + match unsafe { try_security_file_open(&ctx) } { + Ok(_) => errors::BPF_PROG_SUCCESS, + Err(s) => { + error!(&ctx, s); + errors::BPF_PROG_FAILURE + } + } +} + +unsafe fn try_security_file_open(ctx: &ProbeContext) -> ProbeResult<()> { + // if event is disabled we return + if_disabled_return!(Type::FileCreate, ()); + + let file = co_re::file::from_ptr(kprobe_arg!(ctx, 0)?); + + // if not FMODE_CREATED we return + if !file.f_mode().unwrap_or_default() & FMODE_CREATED == FMODE_CREATED { + return Ok(()); + } + + alloc::init()?; + let e = alloc::alloc_zero::()?; + + e.init_from_current_task(Type::FileCreate)?; + + e.data.path.core_resolve_file(&file, MAX_PATH_DEPTH)?; + + // we send event + pipe_event(ctx, e); + + Ok(()) +} diff --git a/kunai/src/bin/main.rs b/kunai/src/bin/main.rs index de16382..9a03156 100644 --- a/kunai/src/bin/main.rs +++ b/kunai/src/bin/main.rs @@ -1901,15 +1901,18 @@ impl<'s> EventConsumer<'s> { Err(e) => error!("failed to decode {} event: {:?}", etype, e), }, - Type::WriteConfig | Type::Write | Type::ReadConfig | Type::Read | Type::WriteClose => { - match event!(enc_event, bpf_events::FileEvent) { - Ok(e) => { - let mut e = self.file_event(std_info, e); - self.scan_and_print(&mut e); - } - Err(e) => error!("failed to decode {} event: {:?}", etype, e), + Type::WriteConfig + | Type::Write + | Type::ReadConfig + | Type::Read + | Type::WriteClose + | Type::FileCreate => match event!(enc_event, bpf_events::FileEvent) { + Ok(e) => { + let mut e = self.file_event(std_info, e); + self.scan_and_print(&mut e); } - } + Err(e) => error!("failed to decode {} event: {:?}", etype, e), + }, Type::FileUnlink => match event!(enc_event, bpf_events::UnlinkEvent) { Ok(e) => { @@ -2714,7 +2717,8 @@ impl Command { | Type::Write | Type::ReadConfig | Type::Read - | Type::WriteClose => { + | Type::WriteClose + | Type::FileCreate => { scan_event!(p, FileData) } Type::FileUnlink => scan_event!(p, UnlinkData),