Skip to content

Commit

Permalink
feat(ebpf): make process_execute_failed not rely on sys_enter/exit
Browse files Browse the repository at this point in the history
  • Loading branch information
OriGlassman authored and randomname21 committed Sep 1, 2024
1 parent c717339 commit ae0e6d8
Show file tree
Hide file tree
Showing 14 changed files with 205 additions and 210 deletions.
2 changes: 1 addition & 1 deletion api/v1beta1/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ enum EventId {
module_load = 1082;
module_free = 1083;
execute_finished = 1084;
security_bprm_creds_for_exec = 1085;
process_execute_failed_internal = 1085;

// Events originated from user-space
net_packet_ipv4 = 2000;
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/events/builtin/extra/process_execute_failed.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Relevant from kernel version 5.8 onwards, matching the `security_bprm_creds_for_
## Example Use Case

```console
./tracee -e process_execution_failed
./tracee -e process_execute_failed
```

## Issues
Expand Down
3 changes: 1 addition & 2 deletions pkg/ebpf/c/maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ enum tail_call_id_e
TAIL_SCHED_PROCESS_EXEC_EVENT_SUBMIT,
TAIL_VFS_READ,
TAIL_VFS_READV,
TAIL_PROCESS_EXECUTE_FAILED1,
TAIL_PROCESS_EXECUTE_FAILED2,
TAIL_PROCESS_EXECUTE_FAILED,
TAIL_HIDDEN_KERNEL_MODULE_PROC,
TAIL_HIDDEN_KERNEL_MODULE_KSET,
TAIL_HIDDEN_KERNEL_MODULE_MOD_TREE,
Expand Down
116 changes: 46 additions & 70 deletions pkg/ebpf/c/tracee.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1521,7 +1521,7 @@ int syscall__accept4(void *ctx)

struct socket *old_sock = (struct socket *) saved_args.args[0];
struct socket *new_sock = (struct socket *) saved_args.args[1];
u32 sockfd = (u32) saved_args.args[2];
u64 sockfd = (u32) saved_args.args[2];

if (new_sock == NULL) {
return -1;
Expand Down Expand Up @@ -4940,31 +4940,32 @@ statfunc int submit_process_execute_failed(struct pt_regs *ctx, program_data_t *
struct file *file = get_file_ptr_from_bprm(bprm);

const char *path = get_binprm_filename(bprm);
save_str_to_buf(&p->event->args_buf, (void *) path, 0);
save_str_to_buf(&p->event->args_buf, (void *) path, 2);

void *binary_path = get_path_str(__builtin_preserve_access_index(&file->f_path));
save_str_to_buf(&p->event->args_buf, binary_path, 1);
save_str_to_buf(&p->event->args_buf, binary_path, 3);

dev_t binary_device_id = get_dev_from_file(file);
save_to_submit_buf(&p->event->args_buf, &binary_device_id, sizeof(dev_t), 2);
save_to_submit_buf(&p->event->args_buf, &binary_device_id, sizeof(dev_t), 4);

unsigned long binary_inode_number = get_inode_nr_from_file(file);
save_to_submit_buf(&p->event->args_buf, &binary_inode_number, sizeof(unsigned long), 3);
save_to_submit_buf(&p->event->args_buf, &binary_inode_number, sizeof(unsigned long), 5);

u64 binary_ctime = get_ctime_nanosec_from_file(file);
save_to_submit_buf(&p->event->args_buf, &binary_ctime, sizeof(u64), 4);
save_to_submit_buf(&p->event->args_buf, &binary_ctime, sizeof(u64), 6);

umode_t binary_inode_mode = get_inode_mode_from_file(file);
save_to_submit_buf(&p->event->args_buf, &binary_inode_mode, sizeof(umode_t), 5);
save_to_submit_buf(&p->event->args_buf, &binary_inode_mode, sizeof(umode_t), 7);

const char *interpreter_path = get_binprm_interp(bprm);
save_str_to_buf(&p->event->args_buf, (void *) interpreter_path, 6);
save_str_to_buf(&p->event->args_buf, (void *) interpreter_path, 8);

bpf_tail_call(ctx, &prog_array, TAIL_PROCESS_EXECUTE_FAILED1);
bpf_tail_call(ctx, &prog_array, TAIL_PROCESS_EXECUTE_FAILED);
return -1;
}

statfunc int execute_failed_tail1(struct pt_regs *ctx, u32 tail_call_id)
SEC("kprobe/process_execute_failed_tail")
int process_execute_failed_tail(struct pt_regs *ctx)
{
program_data_t p = {};
if (!init_tailcall_program_data(&p, ctx))
Expand All @@ -4974,91 +4975,38 @@ statfunc int execute_failed_tail1(struct pt_regs *ctx, u32 tail_call_id)
struct file *stdin_file = get_struct_file_from_fd(0);

unsigned short stdin_type = get_inode_mode_from_file(stdin_file) & S_IFMT;
save_to_submit_buf(&p.event->args_buf, &stdin_type, sizeof(unsigned short), 7);
save_to_submit_buf(&p.event->args_buf, &stdin_type, sizeof(unsigned short), 9);

void *stdin_path = get_path_str(__builtin_preserve_access_index(&stdin_file->f_path));
save_str_to_buf(&p.event->args_buf, stdin_path, 8);
save_str_to_buf(&p.event->args_buf, stdin_path, 10);

int kernel_invoked = (get_task_parent_flags(task) & PF_KTHREAD) ? 1 : 0;
save_to_submit_buf(&p.event->args_buf, &kernel_invoked, sizeof(int), 9);
save_to_submit_buf(&p.event->args_buf, &kernel_invoked, sizeof(int), 11);

bpf_tail_call(ctx, &prog_array, tail_call_id);
return -1;
}

statfunc int execute_failed_tail2(struct pt_regs *ctx)
{
program_data_t p = {};
if (!init_tailcall_program_data(&p, ctx))
return -1;

long long argv, envp;
struct pt_regs *regs = get_current_task_pt_regs();

if (p.event->context.syscall == SYSCALL_EXECVE) {
argv = get_syscall_arg2(p.event->task, regs, false);
envp = get_syscall_arg3(p.event->task, regs, false);
} else {
argv = get_syscall_arg3(p.event->task, regs, false);
envp = get_syscall_arg4(p.event->task, regs, false);
}

save_str_arr_to_buf(&p.event->args_buf, (const char *const *) argv, 10); // userspace argv

if (p.config->options & OPT_EXEC_ENV) {
save_str_arr_to_buf(&p.event->args_buf, (const char *const *) envp, 11); // userspace envp
}

int ret = PT_REGS_RC(ctx); // needs to be int
return events_perf_submit(&p, ret);
return events_perf_submit(&p, 0);
}

bool use_security_bprm_creds_for_exec = false;

SEC("kprobe/exec_binprm")
TRACE_ENT_FUNC(exec_binprm, EXEC_BINPRM);

SEC("kretprobe/exec_binprm")
int BPF_KPROBE(trace_ret_exec_binprm)
int BPF_KPROBE(trace_exec_binprm)
{
if (use_security_bprm_creds_for_exec) {
return 0;
}
args_t saved_args;
if (load_args(&saved_args, EXEC_BINPRM) != 0) {
// missed entry or not traced
return 0;
}
del_args(EXEC_BINPRM);

int ret_val = PT_REGS_RC(ctx);
if (ret_val == 0)
return 0; // not interested of successful execution - for that we have sched_process_exec

program_data_t p = {};
if (!init_program_data(&p, ctx, PROCESS_EXECUTION_FAILED))
if (!init_program_data(&p, ctx, PROCESS_EXECUTE_FAILED_INTERNAL))
return 0;
return submit_process_execute_failed(ctx, &p);
}

SEC("kretprobe/trace_execute_failed1")
int BPF_KPROBE(trace_execute_failed1)
{
return execute_failed_tail1(ctx, TAIL_PROCESS_EXECUTE_FAILED2);
}

SEC("kretprobe/trace_execute_failed2")
int BPF_KPROBE(trace_execute_failed2)
{
return execute_failed_tail2(ctx);
}

SEC("kprobe/security_bprm_creds_for_exec")
int BPF_KPROBE(trace_security_bprm_creds_for_exec)
{
use_security_bprm_creds_for_exec = true;
program_data_t p = {};
if (!init_program_data(&p, ctx, SECURITY_BPRM_CREDS_FOR_EXEC))
if (!init_program_data(&p, ctx, PROCESS_EXECUTE_FAILED_INTERNAL))
return 0;
return submit_process_execute_failed(ctx, &p);
}
Expand All @@ -5073,6 +5021,34 @@ int BPF_KPROBE(trace_execute_finished)
if (!evaluate_scope_filters(&p))
return 0;

// We can enrich the event with user provided arguments. If we have kernelspace arguments,
// the userspace arguments will be discarded.
struct pt_regs *task_regs = get_current_task_pt_regs();
u64 argv, envp;
void *path;

if (p.event->context.syscall == SYSCALL_EXECVEAT) {
int dirfd = get_syscall_arg1(p.event->task, task_regs, false);
path = (void *) get_syscall_arg2(p.event->task, task_regs, false);
argv = get_syscall_arg3(p.event->task, task_regs, false);
envp = get_syscall_arg4(p.event->task, task_regs, false);
int flags = get_syscall_arg5(p.event->task, task_regs, false);

// send args unique to execevat
save_to_submit_buf(&p.event->args_buf, &dirfd, sizeof(int), 0);
save_to_submit_buf(&p.event->args_buf, &flags, sizeof(int), 1);
} else {
path = (void *) get_syscall_arg1(p.event->task, task_regs, false);
argv = get_syscall_arg2(p.event->task, task_regs, false);
envp = get_syscall_arg3(p.event->task, task_regs, false);
}

save_str_to_buf(&p.event->args_buf, path, 2);
save_str_arr_to_buf(&p.event->args_buf, (const char *const *) argv, 12);
if (p.config->options & OPT_EXEC_ENV) {
save_str_arr_to_buf(&p.event->args_buf, (const char *const *) envp, 13);
}

long exec_ret = PT_REGS_RC(ctx);
return events_perf_submit(&p, exec_ret);
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/ebpf/c/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ enum event_id_e
FILE_MODIFICATION,
INOTIFY_WATCH,
SECURITY_BPF_PROG,
PROCESS_EXECUTION_FAILED,
PROCESS_EXECUTE_FAILED,
SECURITY_PATH_NOTIFY,
SET_FS_PWD,
HIDDEN_KERNEL_MODULE_SEEKER,
MODULE_LOAD,
MODULE_FREE,
EXECUTE_FINISHED,
SECURITY_BPRM_CREDS_FOR_EXEC,
PROCESS_EXECUTE_FAILED_INTERNAL,
SECURITY_TASK_SETRLIMIT,
SECURITY_SETTIME64,
MAX_EVENT_ID,
Expand Down
1 change: 0 additions & 1 deletion pkg/ebpf/probes/probe_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ func NewDefaultProbeGroup(module *bpf.Module, netEnabled bool) (*ProbeGroup, err
InotifyFindInodeRet: NewTraceProbe(KretProbe, "inotify_find_inode", "trace_ret_inotify_find_inode"),
BpfCheck: NewTraceProbe(KProbe, "bpf_check", "trace_bpf_check"),
ExecBinprm: NewTraceProbe(KProbe, "exec_binprm", "trace_exec_binprm"),
ExecBinprmRet: NewTraceProbe(KretProbe, "exec_binprm", "trace_ret_exec_binprm"),
SecurityPathNotify: NewTraceProbe(KProbe, "security_path_notify", "trace_security_path_notify"),
SecurityBprmCredsForExec: NewTraceProbe(KProbe, "security_bprm_creds_for_exec", "trace_security_bprm_creds_for_exec"),
SetFsPwd: NewTraceProbe(KProbe, "set_fs_pwd", "trace_set_fs_pwd"),
Expand Down
1 change: 0 additions & 1 deletion pkg/ebpf/probes/probes.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ const (
InotifyFindInodeRet
BpfCheck
ExecBinprm
ExecBinprmRet
SecurityPathNotify
SecurityBprmCredsForExec
SetFsPwd
Expand Down
2 changes: 1 addition & 1 deletion pkg/ebpf/tracee.go
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,7 @@ func (t *Tracee) initDerivationTable() error {
DeriveFunction: executeFailedGen.ProcessExecuteFailed(),
},
},
events.SecurityBprmCredsForExec: {
events.ProcessExecuteFailedInternal: {
events.ProcessExecuteFailed: {
Enabled: shouldSubmit(events.ProcessExecuteFailed),
DeriveFunction: executeFailedGen.ProcessExecuteFailed(),
Expand Down
55 changes: 34 additions & 21 deletions pkg/events/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const (
ModuleLoad
ModuleFree
ExecuteFinished
SecurityBprmCredsForExec
ProcessExecuteFailedInternal
SecurityTaskSetrlimit
SecuritySettime64
MaxCommonID
Expand Down Expand Up @@ -12877,25 +12877,44 @@ var CoreEvents = map[ID]Definition{
{handle: probes.ExecuteAtFinishedCompatARM, required: false},
},
},
params: []trace.ArgMeta{
{Type: "int", Name: "dirfd"},
{Type: "int", Name: "flags"},
{Type: "const char*", Name: "pathname"},
{Type: "const char*", Name: "binary.path"},
{Type: "dev_t", Name: "binary.device_id"},
{Type: "unsigned long", Name: "binary.inode_number"},
{Type: "unsigned long", Name: "binary.ctime"},
{Type: "umode_t", Name: "binary.inode_mode"},
{Type: "const char*", Name: "interpreter_path"},
{Type: "umode_t", Name: "stdin_type"},
{Type: "char*", Name: "stdin_path"},
{Type: "int", Name: "kernel_invoked"},
{Type: "const char*const*", Name: "argv"},
{Type: "const char*const*", Name: "envp"},
},
},
SecurityBprmCredsForExec: {
id: SecurityBprmCredsForExec,
ProcessExecuteFailedInternal: {
id: ProcessExecuteFailedInternal,
id32Bit: Sys32Undefined,
name: "security_bprm_creds_for_exec",
name: "process_execute_failed_internal",
version: NewVersion(1, 0, 0),
sets: []string{"proc"},
internal: true,
dependencies: Dependencies{
ids: []ID{ExecuteFinished},
probes: []Probe{
{handle: probes.ExecBinprm, required: false},
{handle: probes.SecurityBprmCredsForExec, required: false}, // TODO: Change to required once fallbacks are supported
},
tailCalls: []TailCall{
{"prog_array", "trace_execute_failed1", []uint32{TailProcessExecuteFailed1}},
{"prog_array", "trace_execute_failed2", []uint32{TailProcessExecuteFailed2}},
{"prog_array", "process_execute_failed_tail", []uint32{TailProcessExecuteFailed}},
},
},
params: []trace.ArgMeta{
{Type: "const char*", Name: "path"},
{Type: "int", Name: "dirfd"},
{Type: "int", Name: "flags"},
{Type: "const char*", Name: "pathname"},
{Type: "const char*", Name: "binary.path"},
{Type: "dev_t", Name: "binary.device_id"},
{Type: "unsigned long", Name: "binary.inode_number"},
Expand All @@ -12905,8 +12924,8 @@ var CoreEvents = map[ID]Definition{
{Type: "umode_t", Name: "stdin_type"},
{Type: "char*", Name: "stdin_path"},
{Type: "int", Name: "kernel_invoked"},
{Type: "const char*const*", Name: "binary.arguments"},
{Type: "const char*const*", Name: "environment"},
{Type: "const char*const*", Name: "argv"},
{Type: "const char*const*", Name: "envp"},
},
},
ProcessExecuteFailed: {
Expand All @@ -12916,18 +12935,12 @@ var CoreEvents = map[ID]Definition{
version: NewVersion(1, 0, 0),
sets: []string{"proc"},
dependencies: Dependencies{
ids: []ID{ExecuteFinished, SecurityBprmCredsForExec}, // For kernel version >= 5.8
probes: []Probe{
{handle: probes.ExecBinprm, required: false},
{handle: probes.ExecBinprmRet, required: false},
},
tailCalls: []TailCall{
{"prog_array", "trace_execute_failed1", []uint32{TailProcessExecuteFailed1}},
{"prog_array", "trace_execute_failed2", []uint32{TailProcessExecuteFailed2}},
},
ids: []ID{ProcessExecuteFailedInternal},
},
params: []trace.ArgMeta{
{Type: "const char*", Name: "path"},
{Type: "int", Name: "dirfd"},
{Type: "int", Name: "flags"},
{Type: "const char*", Name: "pathname"},
{Type: "const char*", Name: "binary.path"},
{Type: "dev_t", Name: "binary.device_id"},
{Type: "unsigned long", Name: "binary.inode_number"},
Expand All @@ -12937,8 +12950,8 @@ var CoreEvents = map[ID]Definition{
{Type: "umode_t", Name: "stdin_type"},
{Type: "char*", Name: "stdin_path"},
{Type: "int", Name: "kernel_invoked"},
{Type: "const char*const*", Name: "binary.arguments"},
{Type: "const char*const*", Name: "environment"},
{Type: "const char*const*", Name: "argv"},
{Type: "const char*const*", Name: "envp"},
},
},
FtraceHook: {
Expand Down
3 changes: 1 addition & 2 deletions pkg/events/definition_dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,7 @@ const (
TailSchedProcessExecEventSubmit
TailVfsRead
TailVfsReadv
TailProcessExecuteFailed1
TailProcessExecuteFailed2
TailProcessExecuteFailed
TailHiddenKernelModuleProc
TailHiddenKernelModuleKset
TailHiddenKernelModuleModTree
Expand Down
Loading

0 comments on commit ae0e6d8

Please sign in to comment.