From 86cf965cc1dc276cadb9f6e5bb183980407a2325 Mon Sep 17 00:00:00 2001 From: Mahe Tardy Date: Mon, 11 Dec 2023 16:34:02 +0000 Subject: [PATCH] bpf: read proc exe at tracepoint/sys_execve This is needed for matchBinaries in the next commit. Previously we were using the tracepoint argugement filename, which is potentially a relative path. This change has two main benefits: all paths checked against matchBinaries will be absolutes and all symbolic links will be resolved by the kernel. Signed-off-by: Mahe Tardy --- bpf/lib/bpf_task.h | 3 +++ bpf/lib/process.h | 16 ++++++++++++++-- bpf/process/bpf_execve_event.c | 20 ++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/bpf/lib/bpf_task.h b/bpf/lib/bpf_task.h index 4a5a5f0341f..f63c2e00440 100644 --- a/bpf/lib/bpf_task.h +++ b/bpf/lib/bpf_task.h @@ -10,6 +10,9 @@ /* __d_path_local flags */ // #define UNRESOLVED_MOUNT_POINTS 0x01 // (deprecated) +// this error is returned by __d_path_local in the following cases: +// - the path walk did not conclude (too many dentry) +// - the path was too long to fit in the buffer #define UNRESOLVED_PATH_COMPONENTS 0x02 #ifdef __LARGE_BPF_PROG diff --git a/bpf/lib/process.h b/bpf/lib/process.h index d9a3d6ffbee..716ad7d80f1 100644 --- a/bpf/lib/process.h +++ b/bpf/lib/process.h @@ -270,6 +270,19 @@ struct msg_k8s { char docker_id[DOCKER_ID_LENGTH]; }; // All fields aligned so no 'packed' attribute. +#define BINARY_PATH_MAX_LEN 256 + +struct heap_exe { + // because of verifier limitations, this has to be 2 * 256 bytes while 256 + // should be theoretically sufficient, and actually is, in unit tests. + char buf[BINARY_PATH_MAX_LEN * 2]; + // offset points to the start of the path in the above buffer. Use offset to + // read the path in the buffer since it's written from the end. + char *off; + __u32 len; + __u32 error; +}; // All fields aligned so no 'packed' attribute. + struct msg_execve_event { struct msg_common common; struct msg_k8s kube; @@ -289,10 +302,9 @@ struct msg_execve_event { /* below fields are not part of the event, serve just as * heap for execve programs */ + struct heap_exe exe; }; // All fields aligned so no 'packed' attribute. -#define BINARY_PATH_MAX_LEN 256 - // This structure stores the binary path that was recorded on execve. // Technically PATH_MAX is 4096 but we limit the length we store since we have // limits on the length of the string to compare: diff --git a/bpf/process/bpf_execve_event.c b/bpf/process/bpf_execve_event.c index e0303b2dab7..743c6525a63 100644 --- a/bpf/process/bpf_execve_event.c +++ b/bpf/process/bpf_execve_event.c @@ -144,6 +144,21 @@ read_execve_shared_info(void *ctx, __u64 pid) return secureexec; } +static inline __attribute__((always_inline)) __u32 +read_exe(struct task_struct *task, struct heap_exe *exe) +{ + struct file *file = BPF_CORE_READ(task, mm, exe_file); + struct path *path = __builtin_preserve_access_index(&file->f_path); + + exe->len = BINARY_PATH_MAX_LEN; + exe->off = (char *)&exe->buf; + exe->off = __d_path_local(path, exe->off, (int *)&exe->len, (int *)&exe->error); + if (exe->len > 0) + exe->len = BINARY_PATH_MAX_LEN - exe->len; + + return exe->len; +} + __attribute__((section("tracepoint/sys_execve"), used)) int event_execve(struct sched_execve_args *ctx) { @@ -184,6 +199,11 @@ event_execve(struct sched_execve_args *ctx) p->auid = get_auid(); p->uid = get_current_uid_gid(); + // Reading the absolute path of the process exe for matchBinaries. + // Historically we used the filename, a potentially relative path (maybe to + // a symlink) coming from the execve tracepoint. + read_exe(task, &event->exe); + p->size += read_path(ctx, event, filename); p->size += read_args(ctx, event); p->size += read_cwd(ctx, p);