130 lines
3.1 KiB
C
130 lines
3.1 KiB
C
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
|
#include <vmlinux.h>
|
|
#include <bpf/bpf_helpers.h>
|
|
#include <bpf/bpf_core_read.h>
|
|
#include "execsnoop.h"
|
|
|
|
const volatile bool ignore_failed = true;
|
|
const volatile uid_t targ_uid = INVALID_UID;
|
|
const volatile int max_args = DEFAULT_MAXARGS;
|
|
|
|
static const struct event empty_event = {};
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_HASH);
|
|
__uint(max_entries, 10240);
|
|
__type(key, pid_t);
|
|
__type(value, struct event);
|
|
} execs SEC(".maps");
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
|
__uint(key_size, sizeof(u32));
|
|
__uint(value_size, sizeof(u32));
|
|
} events SEC(".maps");
|
|
|
|
static __always_inline bool valid_uid(uid_t uid) {
|
|
return uid != INVALID_UID;
|
|
}
|
|
|
|
SEC("tracepoint/syscalls/sys_enter_execve")
|
|
int tracepoint__syscalls__sys_enter_execve(struct trace_event_raw_sys_enter* ctx)
|
|
{
|
|
u64 id;
|
|
pid_t pid, tgid;
|
|
unsigned int ret;
|
|
struct event *event;
|
|
struct task_struct *task;
|
|
const char **args = (const char **)(ctx->args[1]);
|
|
const char *argp;
|
|
uid_t uid = (u32)bpf_get_current_uid_gid();
|
|
int i;
|
|
|
|
if (valid_uid(targ_uid) && targ_uid != uid)
|
|
return 0;
|
|
|
|
id = bpf_get_current_pid_tgid();
|
|
pid = (pid_t)id;
|
|
tgid = id >> 32;
|
|
if (bpf_map_update_elem(&execs, &pid, &empty_event, BPF_NOEXIST))
|
|
return 0;
|
|
|
|
event = bpf_map_lookup_elem(&execs, &pid);
|
|
if (!event)
|
|
return 0;
|
|
|
|
event->pid = tgid;
|
|
event->uid = uid;
|
|
task = (struct task_struct*)bpf_get_current_task();
|
|
event->ppid = (pid_t)BPF_CORE_READ(task, real_parent, tgid);
|
|
event->args_count = 0;
|
|
event->args_size = 0;
|
|
|
|
ret = bpf_probe_read_user_str(event->args, ARGSIZE, (const char*)ctx->args[0]);
|
|
if (ret <= ARGSIZE) {
|
|
event->args_size += ret;
|
|
} else {
|
|
/* write an empty string */
|
|
event->args[0] = '\0';
|
|
event->args_size++;
|
|
}
|
|
|
|
event->args_count++;
|
|
#pragma unroll
|
|
for (i = 1; i < TOTAL_MAX_ARGS && i < max_args; i++) {
|
|
bpf_probe_read_user(&argp, sizeof(argp), &args[i]);
|
|
if (!argp)
|
|
return 0;
|
|
|
|
if (event->args_size > LAST_ARG)
|
|
return 0;
|
|
|
|
ret = bpf_probe_read_user_str(&event->args[event->args_size], ARGSIZE, argp);
|
|
if (ret > ARGSIZE)
|
|
return 0;
|
|
|
|
event->args_count++;
|
|
event->args_size += ret;
|
|
}
|
|
/* try to read one more argument to check if there is one */
|
|
bpf_probe_read_user(&argp, sizeof(argp), &args[max_args]);
|
|
if (!argp)
|
|
return 0;
|
|
|
|
/* pointer to max_args+1 isn't null, asume we have more arguments */
|
|
event->args_count++;
|
|
return 0;
|
|
}
|
|
|
|
SEC("tracepoint/syscalls/sys_exit_execve")
|
|
int tracepoint__syscalls__sys_exit_execve(struct trace_event_raw_sys_exit* ctx)
|
|
{
|
|
u64 id;
|
|
pid_t pid;
|
|
int ret;
|
|
struct event *event;
|
|
u32 uid = (u32)bpf_get_current_uid_gid();
|
|
|
|
if (valid_uid(targ_uid) && targ_uid != uid)
|
|
return 0;
|
|
id = bpf_get_current_pid_tgid();
|
|
pid = (pid_t)id;
|
|
event = bpf_map_lookup_elem(&execs, &pid);
|
|
if (!event)
|
|
return 0;
|
|
ret = ctx->ret;
|
|
if (ignore_failed && ret < 0)
|
|
goto cleanup;
|
|
|
|
event->retval = ret;
|
|
bpf_get_current_comm(&event->comm, sizeof(event->comm));
|
|
size_t len = EVENT_SIZE(event);
|
|
if (len <= sizeof(*event))
|
|
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, len);
|
|
cleanup:
|
|
bpf_map_delete_elem(&execs, &pid);
|
|
return 0;
|
|
}
|
|
|
|
char LICENSE[] SEC("license") = "GPL";
|