From 61bdb7fe54719ddfa453b3a77cb18d9853e37e2b Mon Sep 17 00:00:00 2001 From: Michal Stanek <75310947+stanek-michal@users.noreply.github.com> Date: Wed, 29 May 2024 17:14:35 +0200 Subject: [PATCH] Add probes for memfd_create and friends (#185) * Add probes for memfd_create and friends New events added: EBPF_EVENT_FILE_MEMFD_OPEN EBPF_EVENT_FILE_SHMEM_OPEN EBPF_EVENT_PROCESS_MEMFD_CREATE EBPF_EVENT_PROCESS_SHMGET EBPF_EVENT_PROCESS_PTRACE EBPF_EVENT_PROCESS_LOAD_MODULE Also added new fields to process exec event * clang-format fixes * Address review comments * clang-format 14 fixes for unrelated code * Fix memory corruption in EventsTrace * Add missing commas in JSON output * Fix commas again * Condense is_foo from exec into flags. (#194) * Address review * clang-format * clang format * Use types with well defined sizes * Address review comments * clang-format fixes --------- Co-authored-by: Christiano Haesbaert --- GPL/Events/EbpfEventProto.h | 71 +++++++- GPL/Events/File/Probe.bpf.c | 125 +++++++++---- GPL/Events/Helpers.h | 56 ++++++ GPL/Events/Process/Probe.bpf.c | 220 +++++++++++++++++++++++ cmake/modules/setup.cmake | 4 +- non-GPL/Events/EventsTrace/EventsTrace.c | 183 ++++++++++++++++++- 6 files changed, 617 insertions(+), 42 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index 49df5f0a..60914a66 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -30,9 +30,15 @@ enum ebpf_event_type { EBPF_EVENT_FILE_CREATE = (1 << 9), EBPF_EVENT_FILE_RENAME = (1 << 10), EBPF_EVENT_FILE_MODIFY = (1 << 11), - EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED = (1 << 12), - EBPF_EVENT_NETWORK_CONNECTION_ATTEMPTED = (1 << 13), - EBPF_EVENT_NETWORK_CONNECTION_CLOSED = (1 << 14), + EBPF_EVENT_FILE_MEMFD_OPEN = (1 << 12), + EBPF_EVENT_FILE_SHMEM_OPEN = (1 << 13), + EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED = (1 << 14), + EBPF_EVENT_NETWORK_CONNECTION_ATTEMPTED = (1 << 15), + EBPF_EVENT_NETWORK_CONNECTION_CLOSED = (1 << 16), + EBPF_EVENT_PROCESS_MEMFD_CREATE = (1 << 17), + EBPF_EVENT_PROCESS_SHMGET = (1 << 18), + EBPF_EVENT_PROCESS_PTRACE = (1 << 19), + EBPF_EVENT_PROCESS_LOAD_MODULE = (1 << 20), }; struct ebpf_event_header { @@ -57,6 +63,8 @@ enum ebpf_varlen_field_type { EBPF_VL_FIELD_TTY_OUT, EBPF_VL_FIELD_PIDS_SS_CGROUP_PATH, EBPF_VL_FIELD_SYMLINK_TARGET_PATH, + EBPF_VL_FIELD_MOD_VERSION, + EBPF_VL_FIELD_MOD_SRCVERSION, }; // Convenience macro to iterate all the variable length fields in an event @@ -154,6 +162,7 @@ struct ebpf_file_delete_event { struct ebpf_varlen_fields_start vl_fields; } __attribute__((packed)); +// reused by memfd_open and shmem_open events struct ebpf_file_create_event { struct ebpf_event_header hdr; struct ebpf_pid_info pids; @@ -210,12 +219,18 @@ struct ebpf_process_fork_event { struct ebpf_varlen_fields_start vl_fields; } __attribute__((packed)); +#define EXEC_F_SETUID (1 << 0) +#define EXEC_F_SETGID (1 << 1) +#define EXEC_F_MEMFD (1 << 2) + struct ebpf_process_exec_event { struct ebpf_event_header hdr; struct ebpf_pid_info pids; struct ebpf_cred_info creds; struct ebpf_tty_dev ctty; char comm[TASK_COMM_LEN]; + uint32_t inode_nlink; + uint32_t flags; // Variable length fields: cwd, argv, env, filename, pids_ss_cgroup_path struct ebpf_varlen_fields_start vl_fields; @@ -271,6 +286,56 @@ struct ebpf_process_setgid_event { uint32_t new_euid; } __attribute__((packed)); +// from linux/memfd.h: +// +/* flags for memfd_create(2) (unsigned int) */ +#ifndef MFD_CLOEXEC +#define MFD_CLOEXEC 0x0001U +#endif +#ifndef MFD_ALLOW_SEALING +#define MFD_ALLOW_SEALING 0x0002U +#endif +#ifndef MFD_HUGETLB +#define MFD_HUGETLB 0x0004U +#endif +/* not executable and sealed to prevent changing to executable. */ +#ifndef MFD_NOEXEC_SEAL +#define MFD_NOEXEC_SEAL 0x0008U +#endif +/* executable */ +#ifndef MFD_EXEC +#define MFD_EXEC 0x0010U +#endif +struct ebpf_process_memfd_create_event { + struct ebpf_event_header hdr; + struct ebpf_pid_info pids; + uint32_t flags; // memfd_create flags + // Variable length fields: memfd name + struct ebpf_varlen_fields_start vl_fields; +} __attribute__((packed)); + +struct ebpf_process_shmget_event { + struct ebpf_event_header hdr; + struct ebpf_pid_info pids; + int64_t key; + uint64_t size; + int64_t shmflg; // shmget() flags +} __attribute__((packed)); + +struct ebpf_process_ptrace_event { + struct ebpf_event_header hdr; + struct ebpf_pid_info pids; + uint32_t child_pid; + int64_t request; +} __attribute__((packed)); + +struct ebpf_process_load_module_event { + struct ebpf_event_header hdr; + struct ebpf_pid_info pids; + // Variable length fields: filename, mod version, mod srcversion + struct ebpf_varlen_fields_start vl_fields; +} __attribute__((packed)); + enum ebpf_net_info_transport { EBPF_NETWORK_EVENT_TRANSPORT_TCP = 1, }; diff --git a/GPL/Events/File/Probe.bpf.c b/GPL/Events/File/Probe.bpf.c index 780c9473..fa140847 100644 --- a/GPL/Events/File/Probe.bpf.c +++ b/GPL/Events/File/Probe.bpf.c @@ -216,6 +216,60 @@ int BPF_KPROBE(kprobe__vfs_unlink) return vfs_unlink__enter(de); } +// prepare a file event and send it to ringbuf. +// if path_prefix is non-NULL then event will only be sent to ringbuf if file path has that prefix +static void prepare_and_send_file_event(struct file *f, + enum ebpf_event_type type, + const char *path_prefix, + int path_prefix_len) +{ + struct ebpf_file_create_event *event = get_event_buffer(); + if (!event) + return; + + event->hdr.type = type; + event->hdr.ts = bpf_ktime_get_ns(); + + struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + struct path p = BPF_CORE_READ(f, f_path); + ebpf_pid_info__fill(&event->pids, task); + ebpf_cred_info__fill(&event->creds, task); + event->mntns = mntns(task); + bpf_get_current_comm(event->comm, TASK_COMM_LEN); + ebpf_file_info__fill(&event->finfo, p.dentry); + + // Variable length fields + ebpf_vl_fields__init(&event->vl_fields); + struct ebpf_varlen_field *field; + long size; + + // symlink_target_path + field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_SYMLINK_TARGET_PATH); + char *link = BPF_CORE_READ(p.dentry, d_inode, i_link); + size = read_kernel_str_or_empty_str(field->data, PATH_MAX, link); + ebpf_vl_field__set_size(&event->vl_fields, field, size); + + // pids ss cgroup path + field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_PIDS_SS_CGROUP_PATH); + size = ebpf_resolve_pids_ss_cgroup_path_to_string(field->data, task); + ebpf_vl_field__set_size(&event->vl_fields, field, size); + + // path + field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_PATH); + size = ebpf_resolve_path_to_string(field->data, &p, task); + ebpf_vl_field__set_size(&event->vl_fields, field, size); + + // skip event if prefix is specified and file path does not start with it + if (path_prefix) { + if ((path_prefix_len > 0) && (size >= path_prefix_len)) { + if (is_equal_prefix(field->data, path_prefix, path_prefix_len)) + bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0); + } + } else { + bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0); + } +} + static int do_filp_open__exit(struct file *f) { /* @@ -232,43 +286,46 @@ static int do_filp_open__exit(struct file *f) fmode_t fmode = BPF_CORE_READ(f, f_mode); if (fmode & (fmode_t)0x100000) { // FMODE_CREATED - struct ebpf_file_create_event *event = get_event_buffer(); - if (!event) + // generate a file creation event + prepare_and_send_file_event(f, EBPF_EVENT_FILE_CREATE, NULL, 0); + } else { + // check if memfd file is being opened + struct path p = BPF_CORE_READ(f, f_path); + struct dentry *curr_dentry = BPF_CORE_READ(&p, dentry); + struct qstr component = BPF_CORE_READ(curr_dentry, d_name); + char buf_filename[8] = {0}; + int ret = + bpf_probe_read_kernel_str(buf_filename, sizeof(MEMFD_STRING), (void *)component.name); + if (ret <= 0) { + bpf_printk("could not read d_name at %p\n", component.name); goto out; + } + // check if file name starts with "memfd:" + int is_memfd = is_equal_prefix(MEMFD_STRING, buf_filename, sizeof(MEMFD_STRING) - 1); + if (is_memfd) { + // generate a memfd file open event + prepare_and_send_file_event(f, EBPF_EVENT_FILE_MEMFD_OPEN, NULL, 0); + goto out; + } - event->hdr.type = EBPF_EVENT_FILE_CREATE; - event->hdr.ts = bpf_ktime_get_ns(); - - struct task_struct *task = (struct task_struct *)bpf_get_current_task(); - struct path p = BPF_CORE_READ(f, f_path); - ebpf_pid_info__fill(&event->pids, task); - ebpf_cred_info__fill(&event->creds, task); - event->mntns = mntns(task); - bpf_get_current_comm(event->comm, TASK_COMM_LEN); - ebpf_file_info__fill(&event->finfo, p.dentry); - - // Variable length fields - ebpf_vl_fields__init(&event->vl_fields); - struct ebpf_varlen_field *field; - long size; - - // path - field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_PATH); - size = ebpf_resolve_path_to_string(field->data, &p, task); - ebpf_vl_field__set_size(&event->vl_fields, field, size); - - // symlink_target_path - field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_SYMLINK_TARGET_PATH); - char *link = BPF_CORE_READ(p.dentry, d_inode, i_link); - size = read_kernel_str_or_empty_str(field->data, PATH_MAX, link); - ebpf_vl_field__set_size(&event->vl_fields, field, size); - - // pids ss cgroup path - field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_PIDS_SS_CGROUP_PATH); - size = ebpf_resolve_pids_ss_cgroup_path_to_string(field->data, task); - ebpf_vl_field__set_size(&event->vl_fields, field, size); + struct vfsmount *curr_vfsmount = BPF_CORE_READ(&p, mnt); + const char *fs_type_name = BPF_CORE_READ(curr_vfsmount, mnt_sb, s_type, name); - bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0); + // check if /dev/shm shared memory file is being opened + // first check if fs is tmpfs + char buf_fsname[8] = {0}; + ret = bpf_probe_read_kernel_str(buf_fsname, sizeof(TMPFS_STRING), (void *)fs_type_name); + if (ret <= 0) { + bpf_printk("could not read fsname at %p\n", fs_type_name); + goto out; + } + + int is_tmpfs = is_equal_prefix(buf_fsname, TMPFS_STRING, sizeof(TMPFS_STRING) - 1); + if (is_tmpfs) { + // now filter for /dev/shm prefix, if there is match - send an SHMEM file open event + prepare_and_send_file_event(f, EBPF_EVENT_FILE_SHMEM_OPEN, DEVSHM_STRING, + sizeof(DEVSHM_STRING) - 1); + } } out: diff --git a/GPL/Events/Helpers.h b/GPL/Events/Helpers.h index 886626b6..d5e7bcd6 100644 --- a/GPL/Events/Helpers.h +++ b/GPL/Events/Helpers.h @@ -7,6 +7,37 @@ * You may choose either one of them if you use this software. */ +/* $OpenBSD: strncmp.c,v 1.11 2014/06/10 04:16:57 deraadt Exp $ */ + +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + #ifndef EBPF_EVENTPROBE_HELPERS_H #define EBPF_EVENTPROBE_HELPERS_H @@ -14,6 +45,10 @@ const volatile int consumer_pid = 0; +#define MEMFD_STRING "memfd:" +#define TMPFS_STRING "tmpfs" +#define DEVSHM_STRING "/dev/shm" + #if BPF_DEBUG_TRACE == 0 #undef bpf_printk #define bpf_printk(fmt, ...) @@ -279,4 +314,25 @@ static bool is_consumer() return consumer_pid == pid; } +static int strncmp(const char *s1, const char *s2, size_t n) +{ + + if (n == 0) + return (0); + do { + if (*s1 != *s2++) + return (*(unsigned char *)s1 - *(unsigned char *)--s2); + if (*s1++ == 0) + break; + } while (--n != 0); + return (0); +} + +// compares first 'len' characters of str1 and str2, returns 1 if equal +// NOTE: no bounds check, assumes use under eBPF verifier +static int is_equal_prefix(const char *str1, const char *str2, int len) +{ + return !strncmp(str1, str2, len); +} + #endif // EBPF_EVENTPROBE_HELPERS_H diff --git a/GPL/Events/Process/Probe.bpf.c b/GPL/Events/Process/Probe.bpf.c index b0a8cfac..88fbca23 100644 --- a/GPL/Events/Process/Probe.bpf.c +++ b/GPL/Events/Process/Probe.bpf.c @@ -30,6 +30,9 @@ DECL_FIELD_OFFSET(iov_iter, __iov); #define ENV_MAX 40960 #define TTY_OUT_MAX 8192 +#define S_ISUID 0004000 +#define S_ISGID 0002000 + SEC("tp_btf/sched_process_fork") int BPF_PROG(sched_process_fork, const struct task_struct *parent, const struct task_struct *child) { @@ -77,6 +80,9 @@ int BPF_PROG(sched_process_exec, pid_t old_pid, const struct linux_binprm *binprm) { + if (!binprm) + goto out; + // Note that we don't ignore the !is_thread_group_leader(task) case here. // if a non-thread-group-leader thread performs an execve, it assumes the // pid info of the thread group leader, all other threads are terminated, @@ -97,6 +103,31 @@ int BPF_PROG(sched_process_exec, ebpf_ctty__fill(&event->ctty, task); ebpf_comm__fill(event->comm, sizeof(event->comm), task); + // set setuid and setgid flags + struct file *f = BPF_CORE_READ(binprm, file); + struct inode *f_inode = BPF_CORE_READ(f, f_inode); + event->flags = 0; + if (BPF_CORE_READ(f_inode, i_mode) & S_ISUID) + event->flags |= EXEC_F_SETUID; + if (BPF_CORE_READ(f_inode, i_mode) & S_ISGID) + event->flags |= EXEC_F_SETGID; + + // set inode link count (0 means anonymous or deleted file) + event->inode_nlink = BPF_CORE_READ(f_inode, i_nlink); + + // check if memfd file is being exec'd + struct path p = BPF_CORE_READ(binprm, file, f_path); + struct dentry *curr_dentry = BPF_CORE_READ(&p, dentry); + struct qstr component = BPF_CORE_READ(curr_dentry, d_name); + char buf_filename[sizeof(MEMFD_STRING)] = {0}; + int ret = bpf_probe_read_kernel_str(buf_filename, sizeof(MEMFD_STRING), (void *)component.name); + if (ret <= 0) { + bpf_printk("could not read d_name at %p\n", component.name); + goto out; + } + if (is_equal_prefix(MEMFD_STRING, buf_filename, sizeof(MEMFD_STRING) - 1)) + event->flags |= EXEC_F_MEMFD; + // Variable length fields ebpf_vl_fields__init(&event->vl_fields); struct ebpf_varlen_field *field; @@ -226,6 +257,195 @@ int tracepoint_syscalls_sys_exit_setsid(struct trace_event_raw_sys_exit *args) return 0; } +SEC("tp_btf/module_load") +int BPF_PROG(module_load, struct module *mod) +{ + if (ebpf_events_is_trusted_pid()) + goto out; + + struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + + if (is_kernel_thread(task)) + goto out; + + struct ebpf_process_load_module_event *event = get_event_buffer(); + if (!event) + goto out; + + event->hdr.type = EBPF_EVENT_PROCESS_LOAD_MODULE; + event->hdr.ts = bpf_ktime_get_ns(); + + ebpf_pid_info__fill(&event->pids, task); + + pid_t ppid = BPF_CORE_READ(task, group_leader, real_parent, tgid); + pid_t curr_tgid = BPF_CORE_READ(task, tgid); + + // ignore if process is child of init/systemd/whatever + if ((curr_tgid == 1) || (curr_tgid == 2) || (ppid == 1) || (ppid == 2)) + goto out; + + // Variable length fields + ebpf_vl_fields__init(&event->vl_fields); + struct ebpf_varlen_field *field; + long size; + +// from include/linux/moduleparam.h +#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) + + // mod name + field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_FILENAME); + size = read_kernel_str_or_empty_str(field->data, MAX_PARAM_PREFIX_LEN, mod->name); + ebpf_vl_field__set_size(&event->vl_fields, field, size); + + // mod version + field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_MOD_VERSION); + size = read_kernel_str_or_empty_str(field->data, PATH_MAX, mod->version); + ebpf_vl_field__set_size(&event->vl_fields, field, size); + + // mod srcversion + field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_MOD_SRCVERSION); + size = read_kernel_str_or_empty_str(field->data, PATH_MAX, mod->srcversion); + ebpf_vl_field__set_size(&event->vl_fields, field, size); + + bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0); + +out: + return 0; +} + +SEC("kprobe/ptrace_attach") +int BPF_KPROBE(kprobe__ptrace_attach, + struct task_struct *child, + long request, + unsigned long addr, + unsigned long flags) +{ + if (ebpf_events_is_trusted_pid()) + goto out; + + struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + if (is_kernel_thread(task)) + goto out; + + pid_t curr_tgid = BPF_CORE_READ(task, tgid); + pid_t child_ppid = BPF_CORE_READ(child, group_leader, real_parent, tgid); + pid_t child_tgid = BPF_CORE_READ(child, tgid); + + // ignore if child is a child of current process (parents ptrace'ing their children is fine) + if (child_ppid == curr_tgid) + goto out; + // ignore if child is same as current process (process is inspecting itself) + if (child_tgid == curr_tgid) + goto out; + + struct ebpf_process_ptrace_event *event = bpf_ringbuf_reserve(&ringbuf, sizeof(*event), 0); + if (!event) + goto out; + + event->hdr.type = EBPF_EVENT_PROCESS_PTRACE; + event->hdr.ts = bpf_ktime_get_ns(); + + ebpf_pid_info__fill(&event->pids, task); + + event->child_pid = child_tgid; + event->request = request; + + bpf_ringbuf_submit(event, 0); + +out: + return 0; +} + +SEC("tracepoint/syscalls/sys_enter_shmget") +int tracepoint_syscalls_sys_enter_shmget(struct trace_event_raw_sys_enter *ctx) +{ + if (ebpf_events_is_trusted_pid()) + goto out; + + struct shmget_args { + short common_type; + char common_flags; + char common_preempt_count; + int common_pid; + int __syscall_nr; + long key; + size_t size; + long shmflg; + }; + struct shmget_args *ex_args = (struct shmget_args *)ctx; + const struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + + if (is_kernel_thread(task)) + goto out; + + struct ebpf_process_shmget_event *event = bpf_ringbuf_reserve(&ringbuf, sizeof(*event), 0); + if (!event) + goto out; + + event->hdr.type = EBPF_EVENT_PROCESS_SHMGET; + event->hdr.ts = bpf_ktime_get_ns(); + ebpf_pid_info__fill(&event->pids, task); + + event->key = ex_args->key; + event->size = ex_args->size; + event->shmflg = ex_args->shmflg; + + bpf_ringbuf_submit(event, 0); +out: + return 0; +} + +SEC("tracepoint/syscalls/sys_enter_memfd_create") +int tracepoint_syscalls_sys_enter_memfd_create(struct trace_event_raw_sys_enter *ctx) +{ + if (ebpf_events_is_trusted_pid()) + goto out; + + // from: /sys/kernel/debug/tracing/events/syscalls/sys_enter_memfd_create/format + struct memfd_create_args { + short common_type; + char common_flags; + char common_preempt_count; + int common_pid; + int __syscall_nr; + const char *uname; + unsigned long flags; + }; + struct memfd_create_args *ex_args = (struct memfd_create_args *)ctx; + + const struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + + if (is_kernel_thread(task)) + goto out; + + struct ebpf_process_memfd_create_event *event = get_event_buffer(); + if (!event) + goto out; + + event->hdr.type = EBPF_EVENT_PROCESS_MEMFD_CREATE; + event->hdr.ts = bpf_ktime_get_ns(); + event->flags = ex_args->flags; + + ebpf_pid_info__fill(&event->pids, task); + + // Variable length fields + ebpf_vl_fields__init(&event->vl_fields); + struct ebpf_varlen_field *field; + long size; + + // memfd filename + field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_FILENAME); + size = bpf_probe_read_user_str(field->data, PATH_MAX, ex_args->uname); + if (size <= 0) + goto out; + ebpf_vl_field__set_size(&event->vl_fields, field, size); + + bpf_ringbuf_output(&ringbuf, event, EVENT_SIZE(event), 0); + +out: + return 0; +} + static int commit_creds__enter(struct cred *new) { const struct task_struct *task = (struct task_struct *)bpf_get_current_task(); diff --git a/cmake/modules/setup.cmake b/cmake/modules/setup.cmake index 2b4f1eb1..e3e87f5f 100644 --- a/cmake/modules/setup.cmake +++ b/cmake/modules/setup.cmake @@ -65,6 +65,8 @@ function(ebpf_static_binary target) add_executable(${target} ${EBPF_BIN_SOURCES}) + target_compile_options(${target} PUBLIC -g -Wall -Wextra) + if (EBPF_BIN_LINK) target_link_libraries(${target} ${EBPF_BIN_LINK}) endif() @@ -90,4 +92,4 @@ function(ebpf_static_binary target) RUNTIME DESTINATION ${EBPF_INSTALL_DIR}/bin ) endif() -endfunction() \ No newline at end of file +endfunction() diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index c015f7c9..37f1eafc 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -30,9 +30,10 @@ const char argp_program_doc[] = "Prints process, network and file events sourced from the Elastic ebpf events library\n" "\n" "USAGE: ./EventsTrace [--all|-a] [--file-delete] [--file-create] [--file-rename] " - "[--file-modify]\n" + "[--file-memfd-open] [--file-shmem-open] [--file-modify]\n" "[--process-fork] [--process-exec] [--process-exit] [--process-setsid] [--process-setuid] " - "[--process-setgid] [--process-tty-write]\n" + "[--process-setgid] [--process-tty-write] [--process-memfd_create] [--process-shmget] " + "[--process-ptrace] [--process-load_module]\n" "[--net-conn-accept] [--net-conn-attempt] [--net-conn-closed]\n" "[--print-features-on-init] [--unbuffer-stdout] [--libbpf-verbose]\n"; @@ -46,6 +47,8 @@ enum cmdline_opts { FILE_CREATE, FILE_RENAME, FILE_MODIFY, + FILE_MEMFD_OPEN, + FILE_SHMEM_OPEN, PROCESS_FORK, PROCESS_EXEC, PROCESS_EXIT, @@ -53,6 +56,10 @@ enum cmdline_opts { PROCESS_SETUID, PROCESS_SETGID, PROCESS_TTY_WRITE, + PROCESS_MEMFD_CREATE, + PROCESS_SHMGET, + PROCESS_PTRACE, + PROCESS_LOAD_MODULE, NETWORK_CONNECTION_ATTEMPTED, NETWORK_CONNECTION_ACCEPTED, NETWORK_CONNECTION_CLOSED, @@ -66,6 +73,8 @@ static uint64_t cmdline_to_lib[CMDLINE_MAX] = { x(FILE_CREATE) x(FILE_RENAME) x(FILE_MODIFY) + x(FILE_MEMFD_OPEN) + x(FILE_SHMEM_OPEN) x(PROCESS_FORK) x(PROCESS_EXEC) x(PROCESS_EXIT) @@ -73,6 +82,10 @@ static uint64_t cmdline_to_lib[CMDLINE_MAX] = { x(PROCESS_SETUID) x(PROCESS_SETGID) x(PROCESS_TTY_WRITE) + x(PROCESS_MEMFD_CREATE) + x(PROCESS_SHMGET) + x(PROCESS_PTRACE) + x(PROCESS_LOAD_MODULE) x(NETWORK_CONNECTION_ATTEMPTED) x(NETWORK_CONNECTION_ACCEPTED) x(NETWORK_CONNECTION_CLOSED) @@ -86,6 +99,8 @@ static const struct argp_option opts[] = { {"file-create", FILE_CREATE, NULL, false, "Print file create events", 0}, {"file-rename", FILE_RENAME, NULL, false, "Print file rename events", 0}, {"file-modify", FILE_MODIFY, NULL, false, "Print file modification events", 0}, + {"file-memfd-open", FILE_MEMFD_OPEN, NULL, false, "Print memfd file open events", 0}, + {"file-shmem-open", FILE_SHMEM_OPEN, NULL, false, "Print shmem (/dev/shm) file open events", 0}, {"process-fork", PROCESS_FORK, NULL, false, "Print process fork events", 0}, {"process-exec", PROCESS_EXEC, NULL, false, "Print process exec events", 0}, {"process-exit", PROCESS_EXIT, NULL, false, "Print process exit events", 0}, @@ -93,6 +108,10 @@ static const struct argp_option opts[] = { {"process-setuid", PROCESS_SETUID, NULL, false, "Print process setuid events", 0}, {"process-setgid", PROCESS_SETGID, NULL, false, "Print process setgid events", 0}, {"process-tty-write", PROCESS_TTY_WRITE, NULL, false, "Print process tty-write events", 0}, + {"process-memfd-create", PROCESS_MEMFD_CREATE, NULL, false, "Print memfd_create events", 0}, + {"process-shmget", PROCESS_SHMGET, NULL, false, "Print shmget events", 0}, + {"process-ptrace", PROCESS_PTRACE, NULL, false, "Print ptrace events", 0}, + {"process-load-module", PROCESS_LOAD_MODULE, NULL, false, "Print kernel module load events", 0}, {"net-conn-accept", NETWORK_CONNECTION_ACCEPTED, NULL, false, "Print network connection accepted events", 0}, {"net-conn-attempt", NETWORK_CONNECTION_ATTEMPTED, NULL, false, @@ -133,6 +152,8 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case FILE_CREATE: case FILE_RENAME: case FILE_MODIFY: + case FILE_MEMFD_OPEN: + case FILE_SHMEM_OPEN: case PROCESS_FORK: case PROCESS_EXEC: case PROCESS_EXIT: @@ -140,6 +161,10 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case PROCESS_SETUID: case PROCESS_SETGID: case PROCESS_TTY_WRITE: + case PROCESS_MEMFD_CREATE: + case PROCESS_SHMGET: + case PROCESS_PTRACE: + case PROCESS_LOAD_MODULE: case NETWORK_CONNECTION_ACCEPTED: case NETWORK_CONNECTION_ATTEMPTED: case NETWORK_CONNECTION_CLOSED: @@ -260,6 +285,11 @@ static void out_string(const char *name, const char *value) printf("\""); } +static void out_bool(const char *name, bool value) +{ + printf("\"%s\":%s", name, value ? "true" : "false"); +} + static void out_tty_dev(const char *name, struct ebpf_tty_dev *tty_dev) { printf("\"%s\":", name); @@ -438,10 +468,10 @@ static void out_file_delete(struct ebpf_file_delete_event *evt) out_newline(); } -static void out_file_create(struct ebpf_file_create_event *evt) +static void out_file_generic(struct ebpf_file_create_event *evt, const char *event_type_str) { out_object_start(); - out_event_type("FILE_CREATE"); + out_event_type(event_type_str); out_comma(); out_pid_info("pids", &evt->pids); @@ -481,6 +511,121 @@ static void out_file_create(struct ebpf_file_create_event *evt) out_object_end(); out_newline(); } +static void out_file_create(struct ebpf_file_create_event *evt) +{ + out_file_generic(evt, "FILE_CREATE"); +} + +// reuse struct ebpf_file_create_event for memfd open events +static void out_file_memfd_open(struct ebpf_file_create_event *evt) +{ + out_file_generic(evt, "FILE_MEMFD_OPEN"); +} +// reuse struct ebpf_file_create_event for shmem open events +static void out_file_shmem_open(struct ebpf_file_create_event *evt) +{ + out_file_generic(evt, "FILE_SHMEM_OPEN"); +} +// kernel load module event +static void out_process_load_module(struct ebpf_process_load_module_event *evt) +{ + out_object_start(); + out_event_type("PROCESS_LOAD_MODULE"); + out_comma(); + out_pid_info("pids", &evt->pids); + + struct ebpf_varlen_field *field; + FOR_EACH_VARLEN_FIELD(evt->vl_fields, field) + { + out_comma(); + switch (field->type) { + case EBPF_VL_FIELD_FILENAME: + out_string("filename", field->data); + break; + case EBPF_VL_FIELD_MOD_VERSION: + out_string("mod_version", field->data); + break; + case EBPF_VL_FIELD_MOD_SRCVERSION: + out_string("mod_srcversion", field->data); + break; + default: + fprintf(stderr, "Unexpected variable length field: %d\n", field->type); + break; + } + } + + out_object_end(); + out_newline(); +} +// ptrace() event +static void out_process_ptrace(struct ebpf_process_ptrace_event *evt) +{ + out_object_start(); + out_event_type("PROCESS_PTRACE"); + out_comma(); + out_pid_info("pids", &evt->pids); + out_comma(); + out_int("child_pid", (int)evt->child_pid); + out_comma(); + out_int("request", evt->request); + + out_object_end(); + out_newline(); +} +// shmget() event +static void out_process_shmget(struct ebpf_process_shmget_event *evt) +{ + out_object_start(); + out_event_type("PROCESS_SHMGET"); + out_comma(); + out_pid_info("pids", &evt->pids); + out_comma(); + out_uint("key", (unsigned int)evt->key); + out_comma(); + out_uint("size", evt->size); + out_comma(); + out_int("shmflg", evt->shmflg); + + out_object_end(); + out_newline(); +} +// memfd_create() event +static void out_process_memfd_create(struct ebpf_process_memfd_create_event *evt) +{ + out_object_start(); + out_event_type("PROCESS_MEMFD_CREATE"); + out_comma(); + out_pid_info("pids", &evt->pids); + out_comma(); + + out_uint("flags", evt->flags); + out_comma(); + out_bool("flag_cloexec", evt->flags & MFD_CLOEXEC); + out_comma(); + out_bool("flag_allow_seal", evt->flags & MFD_ALLOW_SEALING); + out_comma(); + out_bool("flag_hugetlb", evt->flags & MFD_HUGETLB); + out_comma(); + out_bool("flag_noexec_seal", evt->flags & MFD_NOEXEC_SEAL); + out_comma(); + out_bool("flag_exec", evt->flags & MFD_EXEC); + + struct ebpf_varlen_field *field; + FOR_EACH_VARLEN_FIELD(evt->vl_fields, field) + { + out_comma(); + switch (field->type) { + case EBPF_VL_FIELD_FILENAME: + out_string("filename", field->data); + break; + default: + fprintf(stderr, "Unexpected variable length field: %d\n", field->type); + break; + } + } + out_object_end(); + out_newline(); +} static void out_file_rename(struct ebpf_file_rename_event *evt) { @@ -643,6 +788,16 @@ static void out_process_exec(struct ebpf_process_exec_event *evt) out_comma(); out_string("comm", evt->comm); + out_comma(); + + out_bool("is_setuid", evt->flags & EXEC_F_SETUID); + out_comma(); + out_bool("is_setgid", evt->flags & EXEC_F_SETGID); + out_comma(); + out_bool("is_memfd", evt->flags & EXEC_F_MEMFD); + out_comma(); + unsigned int nlinks = evt->inode_nlink; + out_uint("inode_nlinks", nlinks); struct ebpf_varlen_field *field; FOR_EACH_VARLEN_FIELD(evt->vl_fields, field) @@ -920,6 +1075,18 @@ static int event_ctx_callback(struct ebpf_event_header *evt_hdr) case EBPF_EVENT_PROCESS_TTY_WRITE: out_process_tty_write((struct ebpf_process_tty_write_event *)evt_hdr); break; + case EBPF_EVENT_PROCESS_MEMFD_CREATE: + out_process_memfd_create((struct ebpf_process_memfd_create_event *)evt_hdr); + break; + case EBPF_EVENT_PROCESS_SHMGET: + out_process_shmget((struct ebpf_process_shmget_event *)evt_hdr); + break; + case EBPF_EVENT_PROCESS_PTRACE: + out_process_ptrace((struct ebpf_process_ptrace_event *)evt_hdr); + break; + case EBPF_EVENT_PROCESS_LOAD_MODULE: + out_process_load_module((struct ebpf_process_load_module_event *)evt_hdr); + break; case EBPF_EVENT_FILE_DELETE: out_file_delete((struct ebpf_file_delete_event *)evt_hdr); break; @@ -932,6 +1099,14 @@ static int event_ctx_callback(struct ebpf_event_header *evt_hdr) case EBPF_EVENT_FILE_MODIFY: out_file_modify((struct ebpf_file_modify_event *)evt_hdr); break; + case EBPF_EVENT_FILE_MEMFD_OPEN: + // reuses struct ebpf_file_create_event + out_file_memfd_open((struct ebpf_file_create_event *)evt_hdr); + break; + case EBPF_EVENT_FILE_SHMEM_OPEN: + // reuses struct ebpf_file_create_event + out_file_shmem_open((struct ebpf_file_create_event *)evt_hdr); + break; case EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED: out_network_connection_accepted_event((struct ebpf_net_event *)evt_hdr); break;