diff --git a/pkg/ebpf/c/tracee.bpf.c b/pkg/ebpf/c/tracee.bpf.c index e727fbf41fc8..29d12b9fb01d 100644 --- a/pkg/ebpf/c/tracee.bpf.c +++ b/pkg/ebpf/c/tracee.bpf.c @@ -229,6 +229,7 @@ enum event_id_e SHARED_OBJECT_LOADED, DO_INIT_MODULE, SOCKET_ACCEPT, + LOAD_ELF_PHDRS, MAX_EVENT_ID, // Net events IDs @@ -347,6 +348,8 @@ enum container_state_e #define NUMBER_OF_SYSCALLS_TO_CHECK_X86 18 #define NUMBER_OF_SYSCALLS_TO_CHECK_ARM 14 +#define MAX_CACHED_PATH_SIZE 64 + // EBPF KCONFIGS ----------------------------------------------------------------------------------- #ifdef CORE @@ -631,6 +634,12 @@ typedef struct kernel_module_data { u64 next; } kernel_module_data_t; +typedef struct file_id { + char pathname[MAX_CACHED_PATH_SIZE]; + dev_t device; + unsigned long inode; +} file_id_t; + // KERNEL STRUCTS ---------------------------------------------------------------------------------- #ifndef CORE @@ -674,6 +683,7 @@ struct kprobe { // clang-format off BPF_HASH(kconfig_map, u32, u32); // kernel config variables +BPF_HASH(interpreter_map, u32, file_id_t); // interpreter file used for each process BPF_HASH(events_to_submit, u32, u32); // events chosen by the user BPF_HASH(traced_pids_map, u32, u32); // track traced pids BPF_HASH(new_pids_map, u32, u32); // track processes of newly executed binaries @@ -2796,6 +2806,11 @@ int tracepoint__sched__sched_process_exec(struct bpf_raw_tracepoint_args *ctx) void *file_path = get_path_str(GET_FIELD_ADDR(file->f_path)); + // The map of the interpreter will be updated for any loading of an elf, both for the elf and + // for the interpreter. Because the interpreter is loaded only after the executed elf is loaded, + // the map value of the executed elf should be overridden by the interpreter. + file_id_t *elf_interpreter = bpf_map_lookup_elem(&interpreter_map, &data.context.host_tid); + unsigned short stdin_type = get_inode_mode_from_fd(0) & S_IFMT; // Note: Starting from kernel 5.9, there are two new interesting fields in bprm that we should @@ -2815,6 +2830,11 @@ int tracepoint__sched__sched_process_exec(struct bpf_raw_tracepoint_args *ctx) save_to_submit_buf(&data, &invoked_from_kernel, sizeof(int), 6); save_to_submit_buf(&data, &ctime, sizeof(u64), 7); save_to_submit_buf(&data, &stdin_type, sizeof(unsigned short), 8); + if (elf_interpreter != NULL) { + save_str_to_buf(&data, &elf_interpreter->pathname, 9); + save_to_submit_buf(&data, &elf_interpreter->device, sizeof(dev_t), 10); + save_to_submit_buf(&data, &elf_interpreter->inode, sizeof(unsigned long), 11); + } events_perf_submit(&data, SCHED_PROCESS_EXEC, 0); } @@ -2838,6 +2858,7 @@ int tracepoint__sched__sched_process_exit(struct bpf_raw_tracepoint_args *ctx) bpf_map_delete_elem(&new_pids_map, &data.context.host_tid); bpf_map_delete_elem(&syscall_data_map, &data.context.host_tid); bpf_map_delete_elem(&process_context_map, &data.context.host_tid); + bpf_map_delete_elem(&interpreter_map, &data.context.host_tid); int proc_tree_filter_set = get_config(CONFIG_FILTERS) & FILTER_PROC_TREE_ENABLED; @@ -5246,6 +5267,35 @@ int BPF_KPROBE(trace_ret_do_init_module) return events_perf_submit(&data, DO_INIT_MODULE, 0); } +SEC("kprobe/load_elf_phdrs") +int BPF_KPROBE(trace_load_elf_phdrs) +{ + event_data_t data = {}; + if (!init_event_data(&data, ctx)) + return 0; + if (!should_trace((&data.context))) + return 0; + + file_id_t elf = {}; + struct file *loaded_elf = (struct file *) PT_REGS_PARM2(ctx); + const char *elf_pathname = (char *) get_path_str(GET_FIELD_ADDR(loaded_elf->f_path)); + bpf_probe_read_str(elf.pathname, sizeof(elf.pathname), elf_pathname); + elf.device = get_dev_from_file(loaded_elf); + elf.inode = get_inode_nr_from_file(loaded_elf); + + bpf_map_update_elem(&interpreter_map, &data.context.host_tid, &elf, BPF_ANY); + + if (should_submit(LOAD_ELF_PHDRS)) { + save_str_to_buf(&data, (void *) elf_pathname, 0); + save_to_submit_buf(&data, &elf.device, sizeof(dev_t), 1); + save_to_submit_buf(&data, &elf.inode, sizeof(unsigned long), 2); + + events_perf_submit(&data, LOAD_ELF_PHDRS, 0); + } + + return 0; +} + static __always_inline bool skb_revalidate_data(struct __sk_buff *skb, uint8_t **head, uint8_t **tail, const u32 offset) { diff --git a/pkg/ebpf/events_definitions.go b/pkg/ebpf/events_definitions.go index 0cb4b4d97df7..67e357d3cfbf 100644 --- a/pkg/ebpf/events_definitions.go +++ b/pkg/ebpf/events_definitions.go @@ -101,6 +101,7 @@ const ( SharedObjectLoadedEventID DoInitModuleEventID SocketAcceptEventID + LoadElfPhdrsEventID MaxCommonEventID ) @@ -4869,6 +4870,7 @@ var EventsDefinitions = map[int32]EventDefinition{ Name: "sched_process_exec", Probes: []probe{ {event: "sched:sched_process_exec", attach: rawTracepoint, fn: "tracepoint__sched__sched_process_exec"}, + {event: "load_elf_phdrs", attach: kprobe, fn: "trace_load_elf_phdrs"}, }, Sets: []string{"default", "proc"}, Params: []trace.ArgMeta{ @@ -4881,6 +4883,9 @@ var EventsDefinitions = map[int32]EventDefinition{ {Type: "int", Name: "invoked_from_kernel"}, {Type: "unsigned long", Name: "ctime"}, {Type: "umode_t", Name: "stdin_type"}, + {Type: "const char*", Name: "interpreter_pathname"}, + {Type: "dev_t", Name: "interpreter_dev"}, + {Type: "unsigned long", Name: "ineterpreter_inode"}, }, }, SchedProcessExitEventID: { @@ -5702,4 +5707,17 @@ var EventsDefinitions = map[int32]EventDefinition{ {Type: "struct sockaddr*", Name: "local_addr"}, {Type: "struct sockaddr*", Name: "remote_addr"}}, }, + LoadElfPhdrsEventID: { + ID32Bit: sys32undefined, + Name: "load_elf_phdrs", + Probes: []probe{ + {event: "load_elf_phdrs", attach: kprobe, fn: "trace_load_elf_phdrs"}, + }, + Sets: []string{"proc"}, + Params: []trace.ArgMeta{ + {Type: "const char*", Name: "pathname"}, + {Type: "dev_t", Name: "dev"}, + {Type: "unsigned long", Name: "inode"}, + }, + }, }