Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fact-ebpf/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ fn generate_bindings(out_dir: &Path) -> anyhow::Result<()> {
let bindings = bindgen::Builder::default()
.header("src/bpf/types.h")
.derive_default(true)
.impl_debug(true)
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.default_enum_style(bindgen::EnumVariation::NewType {
is_bitfield: false,
Expand Down
71 changes: 60 additions & 11 deletions fact-ebpf/src/bpf/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,12 @@
#include <bpf/bpf_helpers.h>
// clang-format on

__always_inline static void submit_event(struct metrics_by_hook_t* m,
file_activity_type_t event_type,
const char filename[PATH_MAX],
inode_key_t* inode,
bool use_bpf_d_path) {
struct event_t* event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0);
if (event == NULL) {
m->ringbuffer_full++;
return;
}

__always_inline static void __submit_event(struct event_t* event,
struct metrics_by_hook_t* m,
file_activity_type_t event_type,
const char filename[PATH_MAX],
inode_key_t* inode,
bool use_bpf_d_path) {
event->type = event_type;
event->timestamp = bpf_ktime_get_boot_ns();
inode_copy_or_reset(&event->inode, inode);
Expand All @@ -46,3 +41,57 @@ __always_inline static void submit_event(struct metrics_by_hook_t* m,
m->error++;
bpf_ringbuf_discard(event, 0);
}

__always_inline static void submit_event(struct metrics_by_hook_t* m,
file_activity_type_t event_type,
const char filename[PATH_MAX],
inode_key_t* inode,
bool use_bpf_d_path) {
struct event_t* event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0);
if (event == NULL) {
m->ringbuffer_full++;
return;
}

__submit_event(event, m, event_type, filename, inode, use_bpf_d_path);
}

__always_inline static void submit_mode_event(struct metrics_by_hook_t* m,
const char filename[PATH_MAX],
inode_key_t* inode,
umode_t mode,
umode_t old_mode,
bool use_bpf_d_path) {
struct event_t* event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0);
if (event == NULL) {
m->ringbuffer_full++;
return;
}

event->chmod.new = mode;
event->chmod.old = old_mode;

__submit_event(event, m, FILE_ACTIVITY_CHMOD, filename, inode, use_bpf_d_path);
}

__always_inline static void submit_owner_event(struct metrics_by_hook_t* m,
const char filename[PATH_MAX],
inode_key_t* inode,
unsigned long long uid,
unsigned long long gid,
unsigned long long old_uid,
unsigned long long old_gid,
bool use_bpf_d_path) {
struct event_t* event = bpf_ringbuf_reserve(&rb, sizeof(struct event_t), 0);
if (event == NULL) {
m->ringbuffer_full++;
return;
}

event->chown.new.uid = uid;
event->chown.new.gid = gid;
event->chown.old.uid = old_uid;
event->chown.old.gid = old_gid;

__submit_event(event, m, FILE_ACTIVITY_CHOWN, filename, inode, use_bpf_d_path);
}
80 changes: 80 additions & 0 deletions fact-ebpf/src/bpf/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "maps.h"
#include "events.h"
#include "bound_path.h"
#include "vmlinux/x86_64.h"

#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
Expand Down Expand Up @@ -125,3 +126,82 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) {
m->path_unlink.error++;
return 0;
}

SEC("lsm/path_chmod")
int BPF_PROG(trace_path_chmod, struct path* path, umode_t mode) {
struct metrics_t* m = get_metrics();
if (m == NULL) {
return 0;
}

m->path_chmod.total++;

struct bound_path_t* bound_path = path_read(path);
if (bound_path == NULL) {
bpf_printk("Failed to read path");
m->path_chmod.error++;
return 0;
}

inode_key_t inode_key = inode_to_key(path->dentry->d_inode);
const inode_value_t* inode = inode_get(&inode_key);

switch (inode_is_monitored(inode)) {
case NOT_MONITORED:
if (!is_monitored(bound_path)) {
m->path_chmod.ignored++;
return 0;
}
break;

case MONITORED:
break;
}

umode_t old_mode = BPF_CORE_READ(path, dentry, d_inode, i_mode);
submit_mode_event(&m->path_chmod, bound_path->path, &inode_key, mode, old_mode, false);

return 0;
}

SEC("lsm/path_chown")
int BPF_PROG(trace_path_chown, struct path* path, unsigned long long uid, unsigned long long gid) {
struct metrics_t* m = get_metrics();
if (m == NULL) {
return 0;
}

m->path_chown.total++;

struct bound_path_t* bound_path = path_read(path);
if (bound_path == NULL) {
bpf_printk("Failed to read path");
m->path_chown.error++;
return 0;
}

inode_key_t inode_key = inode_to_key(path->dentry->d_inode);
const inode_value_t* inode = inode_get(&inode_key);

switch (inode_is_monitored(inode)) {
case NOT_MONITORED:
if (!is_monitored(bound_path)) {
m->path_chmod.ignored++;
return 0;
}
break;

case MONITORED:
break;
}

struct dentry* d = BPF_CORE_READ(path, dentry);
kuid_t kuid = BPF_CORE_READ(d, d_inode, i_uid);
kgid_t kgid = BPF_CORE_READ(d, d_inode, i_gid);
unsigned long long old_uid = BPF_CORE_READ(&kuid, val);
unsigned long long old_gid = BPF_CORE_READ(&kgid, val);

submit_owner_event(&m->path_chown, bound_path->path, &inode_key, uid, gid, old_uid, old_gid, true);

return 0;
}
16 changes: 16 additions & 0 deletions fact-ebpf/src/bpf/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ typedef enum file_activity_type_t {
FILE_ACTIVITY_OPEN = 0,
FILE_ACTIVITY_CREATION,
FILE_ACTIVITY_UNLINK,
FILE_ACTIVITY_CHMOD,
FILE_ACTIVITY_CHOWN,
} file_activity_type_t;

struct event_t {
Expand All @@ -55,6 +57,18 @@ struct event_t {
char filename[PATH_MAX];
inode_key_t inode;
file_activity_type_t type;
union {
struct {
short unsigned int new;
short unsigned int old;
} chmod;
struct {
struct {
unsigned int uid;
unsigned int gid;
} old, new;
} chown;
};
};

/**
Expand Down Expand Up @@ -83,4 +97,6 @@ struct metrics_by_hook_t {
struct metrics_t {
struct metrics_by_hook_t file_open;
struct metrics_by_hook_t path_unlink;
struct metrics_by_hook_t path_chmod;
struct metrics_by_hook_t path_chown;
};
1 change: 1 addition & 0 deletions fact-ebpf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ impl metrics_t {
let mut m = metrics_t { ..*self };
m.file_open = m.file_open.accumulate(&other.file_open);
m.path_unlink = m.path_unlink.accumulate(&other.path_unlink);
m.path_chmod = m.path_chmod.accumulate(&other.path_chmod);
m
}
}
Expand Down
7 changes: 4 additions & 3 deletions fact/src/bpf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use aya::{
};
use checks::Checks;
use libc::c_char;
use log::{debug, error, info};
use log::{error, info};
use tokio::{
io::unix::AsyncFd,
sync::{mpsc, watch},
Expand Down Expand Up @@ -154,7 +154,9 @@ impl Bpf {

fn load_progs(&mut self, btf: &Btf) -> anyhow::Result<()> {
self.load_lsm_prog("trace_file_open", "file_open", btf)?;
self.load_lsm_prog("trace_path_unlink", "path_unlink", btf)
self.load_lsm_prog("trace_path_unlink", "path_unlink", btf)?;
self.load_lsm_prog("trace_path_chmod", "path_chmod", btf)?;
self.load_lsm_prog("trace_path_chown", "path_chown", btf)
}

fn attach_progs(&mut self) -> anyhow::Result<()> {
Expand Down Expand Up @@ -192,7 +194,6 @@ impl Bpf {
Ok(event) => event,
Err(e) => {
error!("Failed to parse event: '{e}'");
debug!("Event: {event:?}");
event_counter.dropped();
continue;
}
Expand Down
Loading
Loading