Skip to content
Open
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
168 changes: 33 additions & 135 deletions bpf/enhancedrecording/command.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,25 @@
// Size, in bytes, of the ring buffer used to report
// audit events to userspace. This is the default,
// the userspace can adjust this value based on config.
#define EVENTS_BUF_SIZE (4096*8)
#define EVENTS_BUF_SIZE (4096 * 128)

char LICENSE[] SEC("license") = "Dual BSD/GPL";

enum event_type {
EVENT_ARG,
EVENT_RET,
};

// common_data_t is a struct used to store fields that are common across
// multiple events. Those fields are the same as `data_t`.
struct common_data_t {
u64 pid;
u64 ppid;
u8 command[TASK_COMM_LEN];
u64 cgroup;
u32 audit_session_id;
};

struct data_t {
// pid as in the userspace term (i.e. task->tgid in kernel).
u64 pid;
// ppid is the userspace term (i.e task->real_parent->tgid in kernel).
u64 ppid;
// Command is the executable.
u8 command[TASK_COMM_LEN];
// Type is the type of event.
enum event_type type;
// Argv is the list of arguments to the program.
u8 argv[ARGSIZE];
// ReturnCode is the return code of execve.
int retval;
// Filename is the path of the executable.
u8 filename[FILENAMESIZE];
// Args is the list of arguments to the program.
u8 args[ARGBUFSIZE];
// ArgsLen is the length of the args.
u64 args_len;
// ArgsTruncated is true if the args were truncated.
bool args_truncated;
// CgroupID is the internal cgroupv2 ID of the event.
u64 cgroup;
// AuditSessionID is the audit session ID that is used to correlate
Expand All @@ -59,144 +46,55 @@ BPF_RING_BUF(execve_events, EVENTS_BUF_SIZE);

BPF_COUNTER(lost);

static int __submit_arg(void *ptr, struct common_data_t *common)
static int enter_execve(struct trace_event_raw_sched_process_exec *tp)
{
struct data_t *data = bpf_ringbuf_reserve(&execve_events, sizeof(*data), 0);
if (!data) {
return -1;
}

if (bpf_probe_read_user(data->argv, sizeof(data->argv), ptr) < 0) {
bpf_ringbuf_discard(data, 0);
return -1;
}

data->type = EVENT_ARG;
data->pid = common->pid;
data->cgroup = common->cgroup;
data->audit_session_id = common->audit_session_id;
for (int i = 0; i < TASK_COMM_LEN; i++)
data->command[i] = common->command[i];

bpf_ringbuf_submit(data, 0);
return 1;
}

static int submit_arg(void *ptr, struct common_data_t *common)
{
const char *argp = 0;
bpf_probe_read_user(&argp, sizeof(argp), ptr);
if (argp) {
return __submit_arg((void *)(argp), common);
}
return 0;
}

static int enter_execve(const char *filename,
const char *const *argv,
const char *const *envp)
{
struct common_data_t common = {};

struct task_struct *task = (struct task_struct *)bpf_get_current_task();
u32 session_id = BPF_CORE_READ(task, sessionid);
u8 *is_monitored = bpf_map_lookup_elem(&monitored_sessionids, &session_id);
if (is_monitored == NULL) {
return 0;
}

print_command_event(task, filename, argv);

common.pid = bpf_get_current_pid_tgid() >> 32;
common.cgroup = bpf_get_current_cgroup_id();
common.audit_session_id = session_id;

common.ppid = BPF_CORE_READ(task, real_parent, tgid);
bpf_get_current_comm(&common.command, sizeof(common.command));

if(__submit_arg((void *)filename, &common) < 0) {
struct data_t *data = bpf_ringbuf_reserve(&execve_events, sizeof(*data), 0);
if (!data) {
INCR_COUNTER(lost);
goto out;
bpf_printk("execve_events ring buffer full");
return 0;
}

for (int i = 1; i < MAXARGS; i++) {
int res = submit_arg((void *)&argv[i], &common);
if (res < 0) {
INCR_COUNTER(lost);
goto out;
}

// If no arguments were sent, we reached the end of the arguments list.
if (res == 0)
goto out;
u64 filename_loc = BPF_CORE_READ(tp, __data_loc_filename) & 0xFFFF;
bpf_probe_read_str(&data->filename, sizeof(data->filename), (void *)tp + filename_loc);

void *arg_start = (void *)BPF_CORE_READ(task, mm, arg_start);
void *arg_end = (void *)BPF_CORE_READ(task, mm, arg_end);
data->args_len = arg_end - arg_start;

data->args_truncated = false;
if (data->args_len > ARGBUFSIZE) {
data->args_len = ARGBUFSIZE;
data->args_truncated = true;
}

// handle truncated argument list
char ellipsis[] = "...";
if (__submit_arg((void *)ellipsis, &common) < 0)
INCR_COUNTER(lost);
out:
return 0;
}

static int exit_execve(int ret)
{
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
u32 session_id = BPF_CORE_READ(task, sessionid);
u8 *is_monitored = bpf_map_lookup_elem(&monitored_sessionids, &session_id);
if (is_monitored == NULL) {
return 0;
int read_ret = bpf_probe_read_user(&data->args, data->args_len, arg_start);
if (read_ret < 0) {
data->args_len = 0;
}

struct data_t *data = bpf_ringbuf_reserve(&execve_events, sizeof(*data), 0);
if (!data) {
INCR_COUNTER(lost);
return 0;
}
print_command_event(task, data->filename, data->args);

data->pid = bpf_get_current_pid_tgid() >> 32;
data->cgroup = bpf_get_current_cgroup_id();
data->audit_session_id = session_id;

task = (struct task_struct *)bpf_get_current_task();
data->ppid = BPF_CORE_READ(task, real_parent, tgid);

bpf_get_current_comm(&data->command, sizeof(data->command));
data->type = EVENT_RET;
data->retval = ret;

bpf_ringbuf_submit(data, 0);
return 0;
}

SEC("tp/syscalls/sys_execve")
int tracepoint__syscalls__sys_enter_execve(struct syscall_trace_enter *tp)
{
const char *filename = (const char *)tp->args[0];
const char *const *argv = (const char *const *)tp->args[1];
const char *const *envp = (const char *const *)tp->args[2];

return enter_execve(filename, argv, envp);
}

SEC("tp/syscalls/sys_exit_execve")
int tracepoint__syscalls__sys_exit_execve(struct syscall_trace_exit *tp)
{
return exit_execve(tp->ret);
}

SEC("tp/syscalls/sys_execveat")
int tracepoint__syscalls__sys_enter_execveat(struct syscall_trace_enter *tp)
{
const char *filename = (const char *)tp->args[1];
const char *const *argv = (const char *const *)tp->args[2];
const char *const *envp = (const char *const *)tp->args[3];

return enter_execve(filename, argv, envp);
return 0;
}

SEC("tp/syscalls/sys_exit_execveat")
int tracepoint__syscalls__sys_exit_execveat(struct syscall_trace_exit *tp)
SEC("tracepoint/sched/sched_process_exec")
int tracepoint__sched__sched_process_exec(struct trace_event_raw_sched_process_exec *tp)
{
return exit_execve(tp->ret);
return enter_execve(tp);
}
21 changes: 9 additions & 12 deletions bpf/enhancedrecording/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@
// Maximum monitored sessions.
#define MAX_MONITORED_SESSIONS 1024

#define FILENAMESIZE 512

// ARGSIZE specifies the max argument size read.
#define ARGSIZE 1024
#define MAXARGS 20
#define _ARGSIZE 1024
#define _MAXARGS 20
#define ARGBUFSIZE (_ARGSIZE * _MAXARGS)

// Easier to use bpf_printk taken from https://nakryiko.com/posts/bpf-tips-printk/

Expand Down Expand Up @@ -49,19 +52,13 @@ static void print_event(struct task_struct *task) {
bpf_printk(" session ID: %lu", session_id);
}

static void print_command_event(struct task_struct *task, const char *filename, const char *const *argv) {
static void print_command_event(struct task_struct *task, const u8 filename[FILENAMESIZE], const u8 argv[ARGBUFSIZE]) {
const char *arg = NULL;

bpf_printk("command:");
print_event(task);
bpf_printk(" filename: %s", filename);
for (int i = 1; i < MAXARGS; i++) {
bpf_probe_read_user_str(&arg, MAXARGS, (void*)&argv[i]);
if (arg == NULL){
break;
}
bpf_printk(" argv[%d]: %s", i, arg);
}
bpf_printk(" argv[0]: %s", argv);
}

static void print_disk_event(struct task_struct *task, const char *path) {
Expand All @@ -72,7 +69,7 @@ static void print_disk_event(struct task_struct *task, const char *path) {
#else
#define bpf_printk(fmt, ...)
static void print_event(struct task_struct *task) {}
static void print_command_event(struct task_struct *task, const char *filename, const char *const *argv) {}
static void print_command_event(struct task_struct *task, const u8 filename[FILENAMESIZE], const u8 argv[ARGBUFSIZE]) {}
static void print_disk_event(struct task_struct *task, const char *path) {}
#endif

Expand Down
Loading
Loading