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 Aug 12, 2024
1 parent b55f889 commit 205f618
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 184 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
100 changes: 52 additions & 48 deletions pkg/ebpf/c/tracee.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -4926,31 +4926,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);
return -1;
}

statfunc int execute_failed_tail1(struct pt_regs *ctx, u32 tail_call_id)
SEC("kprobe/execute_failed_tail1")
int execute_failed_tail1(struct pt_regs *ctx)
{
program_data_t p = {};
if (!init_tailcall_program_data(&p, ctx))
Expand All @@ -4960,83 +4961,58 @@ 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);
bpf_tail_call(ctx, &prog_array, TAIL_PROCESS_EXECUTE_FAILED2);
return -1;
}

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

syscall_data_t *sys = &p.task_info->syscall_data;
save_str_arr_to_buf(
&p.event->args_buf, (const char *const *) sys->args.args[1], 10); // userspace argv
struct pt_regs *task_regs = get_current_task_pt_regs();
u64 argv = get_syscall_arg2(p.event->task, task_regs, false);
u64 envp = get_syscall_arg3(p.event->task, task_regs, false);
save_str_arr_to_buf(&p.event->args_buf, (const char *const *) argv, 12); // userspace argv

if (p.config->options & OPT_EXEC_ENV) {
save_str_arr_to_buf(
&p.event->args_buf, (const char *const *) sys->args.args[2], 11); // userspace envp
save_str_arr_to_buf(&p.event->args_buf, (const char *const *) envp, 13); // 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 @@ -5051,6 +5027,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
57 changes: 35 additions & 22 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 @@ -12943,25 +12943,45 @@ 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", "execute_failed_tail1", []uint32{TailProcessExecuteFailed1}},
{"prog_array", "execute_failed_tail2", []uint32{TailProcessExecuteFailed2}},
},
},
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 @@ -12971,8 +12991,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 @@ -12982,19 +13002,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},
{handle: probes.SyscallEnter__Internal, required: true},
},
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 @@ -13004,8 +13017,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
Loading

0 comments on commit 205f618

Please sign in to comment.