From 55083175268ee1d7229fcd6732d185a54b58ed3e Mon Sep 17 00:00:00 2001 From: Eddy Duer Date: Wed, 26 Jun 2024 17:58:21 +0300 Subject: [PATCH] Overlay FS: Add fields proc.is_exe_lower_layer, fd.is_upper_layer and fd.is_lower_layer Signed-off-by: Eddy Duer --- driver/bpf/filler_helpers.h | 9 +- driver/bpf/fillers.h | 311 +++++++++++++----- driver/event_table.c | 10 +- driver/flags_table.c | 9 +- .../helpers/extract/extract_from_kernel.h | 60 ++-- .../attached/events/sched_process_exec.bpf.c | 9 +- .../syscall_dispatched_events/creat.bpf.c | 14 +- .../syscall_dispatched_events/execve.bpf.c | 9 +- .../syscall_dispatched_events/execveat.bpf.c | 9 +- .../syscall_dispatched_events/open.bpf.c | 15 +- .../open_by_handle_at.bpf.c | 15 +- .../syscall_dispatched_events/openat.bpf.c | 15 +- .../syscall_dispatched_events/openat2.bpf.c | 15 +- driver/ppm_events_public.h | 14 + driver/ppm_fillers.c | 214 +++++++++--- userspace/libscap/scap.h | 1 + userspace/libsinsp/fdinfo.h | 22 ++ userspace/libsinsp/parsers.cpp | 34 ++ userspace/libsinsp/sinsp_filtercheck_fd.cpp | 24 ++ userspace/libsinsp/sinsp_filtercheck_fd.h | 2 + .../libsinsp/sinsp_filtercheck_thread.cpp | 4 + userspace/libsinsp/sinsp_filtercheck_thread.h | 1 + userspace/libsinsp/threadinfo.cpp | 3 + userspace/libsinsp/threadinfo.h | 1 + 24 files changed, 647 insertions(+), 173 deletions(-) diff --git a/driver/bpf/filler_helpers.h b/driver/bpf/filler_helpers.h index a2b7115bc8..01c3cd8ce7 100644 --- a/driver/bpf/filler_helpers.h +++ b/driver/bpf/filler_helpers.h @@ -280,21 +280,20 @@ static __always_inline unsigned long bpf_encode_dev(dev_t dev) return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); } -static __always_inline void bpf_get_fd_dev_ino(int fd, unsigned long *dev, unsigned long *ino) +static __always_inline void bpf_get_fd_dev_ino_file(int fd, unsigned long *dev, unsigned long *ino, struct file **file) { struct super_block *sb; struct inode *inode; - struct file *file; dev_t kdev; if (fd < 0) return; - file = bpf_fget(fd); - if (!file) + *file = bpf_fget(fd); + if (!*file) return; - inode = _READ(file->f_inode); + inode = _READ((*file)->f_inode); if (!inode) return; diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h index 8ec2cd881a..15208457db 100644 --- a/driver/bpf/fillers.h +++ b/driver/bpf/fillers.h @@ -89,6 +89,59 @@ static __always_inline int bpf_##x(void *ctx) \ \ static __always_inline int __bpf_##x(struct filler_data *data) \ +static __always_inline struct inode *get_file_inode(struct file *file) +{ + if (file) { + return _READ(file->f_inode); + } + return NULL; +} + +static __always_inline enum ppm_overlay get_overlay_layer(struct dentry *dentry, struct super_block *sb) +{ + unsigned long sb_magic = _READ(sb->s_magic); + if(sb_magic == PPM_OVERLAYFS_SUPER_MAGIC) + { + struct dentry *upper_dentry = NULL; + char *vfs_inode = (char *)_READ(dentry->d_inode); + + // Pointer arithmetics due to unexported ovl_inode struct + // warning: this works if and only if the dentry pointer is placed right after the inode struct + struct dentry *tmp = (struct dentry *)(vfs_inode + sizeof(struct inode)); + upper_dentry = _READ(tmp); + if(!upper_dentry) + { + return PPM_OVERLAY_LOWER; + } + + unsigned int d_flags = _READ(dentry->d_flags); + bool disconnected = (d_flags & DCACHE_DISCONNECTED); + if(disconnected) + { + return PPM_OVERLAY_UPPER; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0) + struct ovl_entry *oe = (struct ovl_entry*)_READ(dentry->d_fsdata); + unsigned long has_upper = (unsigned long)_READ(oe->has_upper); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0) + struct ovl_entry *oe = (struct ovl_entry*)_READ(dentry->d_fsdata); + unsigned long flags = _READ(oe->flags); + unsigned long has_upper = (flags & (1U << (OVL_E_UPPER_ALIAS))); +#else + unsigned long flags = (unsigned long)_READ(dentry->d_fsdata); + unsigned long has_upper = (flags & (1U << (OVL_E_UPPER_ALIAS))); +#endif + + if(has_upper) + { + return PPM_OVERLAY_UPPER; + } + return PPM_OVERLAY_LOWER; + } + return PPM_NOT_OVERLAY_FS; +} + FILLER_RAW(terminate_filler) { struct scap_bpf_per_cpu_state *state; @@ -364,6 +417,8 @@ FILLER(sys_open_x, true) unsigned long ino = 0; long retval; int res; + struct file *file = NULL; + unsigned int fd_flags = 0; /* Parameter 1: ret (type: PT_FD) */ retval = bpf_syscall_get_retval(data->ctx); @@ -389,14 +444,39 @@ FILLER(sys_open_x, true) res = bpf_push_u32_to_ring(data, mode); CHECK_RES(res); - bpf_get_fd_dev_ino(retval, &dev, &ino); + bpf_get_fd_dev_ino_file(retval, &dev, &ino, &file); /* Parameter 5: dev (type: PT_UINT32) */ res = bpf_push_u32_to_ring(data, (uint32_t)dev); CHECK_RES(res); /* Parameter 6: ino (type: PT_UINT64) */ - return bpf_push_u64_to_ring(data, (uint64_t)ino);; + res = bpf_push_u64_to_ring(data, (uint64_t)ino); + CHECK_RES(res); + + /* Parameter 7: fd_flags (type: PT_UINT32) */ + if (likely(file)) + { + enum ppm_overlay ol; + struct inode *inode = get_file_inode(file); + struct path f_path = (struct path)_READ(file->f_path); + struct dentry* dentry = f_path.dentry; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) + struct super_block* sb = _READ(dentry->d_sb); +#else + struct super_block *sb = _READ(inode->i_sb); +#endif + ol = get_overlay_layer(dentry, sb); + if (ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else if (ol == PPM_OVERLAY_LOWER) + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + } + return bpf_push_u32_to_ring(data, (uint32_t)fd_flags); } FILLER(sys_read_e, true) @@ -2162,14 +2242,6 @@ static __always_inline struct file *get_exe_file(struct task_struct *task) return NULL; } -static __always_inline struct inode *get_file_inode(struct file *file) -{ - if (file) { - return _READ(file->f_inode); - } - return NULL; -} - /* * Detect whether the file being referenced is an anonymous file created using memfd_create() * and is being executed by referencing its file descriptor (fd). This type of file does not @@ -2314,50 +2386,6 @@ static __always_inline bool get_exe_writable(struct inode *inode, struct cred *c return false; } -static __always_inline bool get_exe_upper_layer(struct dentry *dentry, struct super_block *sb) -{ - unsigned long sb_magic = _READ(sb->s_magic); - if(sb_magic == PPM_OVERLAYFS_SUPER_MAGIC) - { - struct dentry *upper_dentry = NULL; - char *vfs_inode = (char *)_READ(dentry->d_inode); - - // Pointer arithmetics due to unexported ovl_inode struct - // warning: this works if and only if the dentry pointer is placed right after the inode struct - struct dentry *tmp = (struct dentry *)(vfs_inode + sizeof(struct inode)); - upper_dentry = _READ(tmp); - if(!upper_dentry) - { - return false; - } - - unsigned int d_flags = _READ(dentry->d_flags); - bool disconnected = (d_flags & DCACHE_DISCONNECTED); - if(disconnected) - { - return true; - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0) - struct ovl_entry *oe = (struct ovl_entry*)_READ(dentry->d_fsdata); - unsigned long has_upper = (unsigned long)_READ(oe->has_upper); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0) - struct ovl_entry *oe = (struct ovl_entry*)_READ(dentry->d_fsdata); - unsigned long flags = _READ(oe->flags); - unsigned long has_upper = (flags & (1U << (OVL_E_UPPER_ALIAS))); -#else - unsigned long flags = (unsigned long)_READ(dentry->d_fsdata); - unsigned long has_upper = (flags & (1U << (OVL_E_UPPER_ALIAS))); -#endif - - if(has_upper) - { - return true; - } - } - return false; -} - FILLER(proc_startupdate, true) { struct task_struct *real_parent; @@ -2876,9 +2904,9 @@ FILLER(execve_extra_tail_1, true) struct super_block *sb = _READ(inode->i_sb); #endif - /* `exe_writable` and `exe_upper_layer` flag logic */ + /* `exe_writable`, `exe_upper_layer` and `exe_lower_layer` flag logic */ bool exe_writable = false; - bool exe_upper_layer = false; + enum ppm_overlay exe_layer = false; uint32_t flags = 0; kuid_t euid; @@ -2895,13 +2923,17 @@ FILLER(execve_extra_tail_1, true) } /* - * exe_upper_layer + * exe_upper_layer and exe_lower_layer */ - exe_upper_layer = get_exe_upper_layer(dentry,sb); - if (exe_upper_layer) + exe_layer = get_overlay_layer(dentry,sb); + if (exe_layer == PPM_OVERLAY_UPPER) { flags |= PPM_EXE_UPPER_LAYER; } + else if (exe_layer == PPM_OVERLAY_LOWER) + { + flags |= PPM_EXE_LOWER_LAYER; + } // write all additional flags for execve family here... } @@ -3217,6 +3249,8 @@ FILLER(sys_openat_x, true) long retval; int32_t fd; int res; + struct file *file = NULL; + unsigned int fd_flags = 0; retval = bpf_syscall_get_retval(data->ctx); res = bpf_push_s64_to_ring(data, retval); @@ -3258,7 +3292,7 @@ FILLER(sys_openat_x, true) res = bpf_push_u32_to_ring(data, mode); CHECK_RES(res); - bpf_get_fd_dev_ino(retval, &dev, &ino); + bpf_get_fd_dev_ino_file(retval, &dev, &ino, &file); /* * Device @@ -3269,7 +3303,34 @@ FILLER(sys_openat_x, true) /* * Ino */ - return bpf_push_u64_to_ring(data, ino); + res = bpf_push_u64_to_ring(data, ino); + CHECK_RES(res); + + /* + * fd_flags + */ + if (likely(file)) + { + enum ppm_overlay ol; + struct inode *inode = get_file_inode(file); + struct path f_path = (struct path)_READ(file->f_path); + struct dentry* dentry = f_path.dentry; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) + struct super_block* sb = _READ(dentry->d_sb); +#else + struct super_block *sb = _READ(inode->i_sb); +#endif + ol = get_overlay_layer(dentry, sb); + if (ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else if (ol == PPM_OVERLAY_LOWER) + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + } + return bpf_push_u32_to_ring(data, (uint32_t)fd_flags); } FILLER(sys_openat2_e, true) @@ -3350,6 +3411,8 @@ FILLER(sys_openat2_x, true) long retval; int32_t fd; int res; + struct file *file = NULL; + unsigned int fd_flags = 0; #ifdef __NR_openat2 struct open_how how; #endif @@ -3415,7 +3478,7 @@ FILLER(sys_openat2_x, true) res = bpf_push_u32_to_ring(data, resolve); CHECK_RES(res); - bpf_get_fd_dev_ino(retval, &dev, &ino); + bpf_get_fd_dev_ino_file(retval, &dev, &ino, &file); /* * dev @@ -3426,7 +3489,34 @@ FILLER(sys_openat2_x, true) /* * ino */ - return bpf_push_u64_to_ring(data, ino); + res = bpf_push_u64_to_ring(data, ino); + CHECK_RES(res); + + /* + * fd_flags + */ + if (likely(file)) + { + enum ppm_overlay ol; + struct inode *inode = get_file_inode(file); + struct path f_path = (struct path)_READ(file->f_path); + struct dentry* dentry = f_path.dentry; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) + struct super_block* sb = _READ(dentry->d_sb); +#else + struct super_block *sb = _READ(inode->i_sb); +#endif + ol = get_overlay_layer(dentry, sb); + if (ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else if (ol == PPM_OVERLAY_LOWER) + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + } + return bpf_push_u32_to_ring(data, (uint32_t)fd_flags); } FILLER(sys_open_by_handle_at_x, true) @@ -3478,7 +3568,13 @@ FILLER(sys_open_by_handle_at_x, true) FILLER(open_by_handle_at_x_extra_tail_1, true) { long retval = bpf_syscall_get_retval(data->ctx); - struct file *f = bpf_fget(retval); + struct file *f = NULL; + unsigned long dev = 0; + unsigned long ino = 0; + unsigned int fd_flags = 0; + + bpf_get_fd_dev_ino_file(retval, &dev, &ino, &f); + if(f == NULL) { /* In theory here we should send an empty param but we are experimenting some issues @@ -3495,17 +3591,37 @@ FILLER(open_by_handle_at_x_extra_tail_1, true) char* filepath = bpf_d_path_approx(data, &(f->f_path)); int res = bpf_val_to_ring_mem(data,(unsigned long)filepath, KERNEL); - unsigned long dev = 0; - unsigned long ino = 0; - - bpf_get_fd_dev_ino(retval, &dev, &ino); - /* Parameter 5: dev (type: PT_UINT32) */ res = bpf_push_u32_to_ring(data, dev); CHECK_RES(res); /* Parameter 6: ino (type: PT_UINT64) */ - return bpf_push_u64_to_ring(data, ino); + res = bpf_push_u64_to_ring(data, ino); + CHECK_RES(res); + + /* Parameter 7: fd_flags (type: PT_UINT32) */ + if (likely(f)) + { + enum ppm_overlay ol; + struct inode *inode = get_file_inode(f); + struct path f_path = (struct path)_READ(f->f_path); + struct dentry* dentry = f_path.dentry; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) + struct super_block* sb = _READ(dentry->d_sb); +#else + struct super_block *sb = _READ(inode->i_sb); +#endif + ol = get_overlay_layer(dentry, sb); + if (ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else if (ol == PPM_OVERLAY_LOWER) + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + } + return bpf_push_u32_to_ring(data, (uint32_t)fd_flags); } FILLER(sys_io_uring_setup_x, true) @@ -4586,6 +4702,8 @@ FILLER(sys_creat_x, true) unsigned long mode; long retval; int res; + struct file *file = NULL; + unsigned int fd_flags = 0; retval = bpf_syscall_get_retval(data->ctx); res = bpf_push_s64_to_ring(data, retval); @@ -4606,7 +4724,7 @@ FILLER(sys_creat_x, true) res = bpf_push_u32_to_ring(data, mode); CHECK_RES(res); - bpf_get_fd_dev_ino(retval, &dev, &ino); + bpf_get_fd_dev_ino_file(retval, &dev, &ino, &file); /* * Device @@ -4617,7 +4735,34 @@ FILLER(sys_creat_x, true) /* * Ino */ - return bpf_push_u64_to_ring(data, ino); + res = bpf_push_u64_to_ring(data, ino); + CHECK_RES(res); + + /* + * fd_flags + */ + if (likely(file)) + { + enum ppm_overlay ol; + struct inode *inode = get_file_inode(file); + struct path f_path = (struct path)_READ(file->f_path); + struct dentry* dentry = f_path.dentry; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) + struct super_block* sb = _READ(dentry->d_sb); +#else + struct super_block *sb = _READ(inode->i_sb); +#endif + ol = get_overlay_layer(dentry, sb); + if (ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else if (ol == PPM_OVERLAY_LOWER) + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + } + return bpf_push_u32_to_ring(data, (uint32_t)fd_flags); } FILLER(sys_pipe_x, true) @@ -4626,6 +4771,7 @@ FILLER(sys_pipe_x, true) long retval = bpf_syscall_get_retval(data->ctx); int res = bpf_push_s64_to_ring(data, retval); CHECK_RES(res); + struct file *file = NULL; int32_t pipefd[2] = {-1, -1}; /* This is a pointer to the vector with the 2 file descriptors. */ @@ -4645,12 +4791,12 @@ FILLER(sys_pipe_x, true) CHECK_RES(res); unsigned long ino = 0; - /* Not used, we use it just to call `bpf_get_fd_dev_ino` */ + /* Not used, we use it just to call `bpf_get_fd_dev_ino_file` */ unsigned long dev = 0; /* On success, pipe returns `0` */ if(retval == 0) { - bpf_get_fd_dev_ino(pipefd[0], &dev, &ino); + bpf_get_fd_dev_ino_file(pipefd[0], &dev, &ino, &file); } /* Parameter 4: ino (type: PT_UINT64) */ @@ -4663,6 +4809,7 @@ FILLER(sys_pipe2_x, true) long retval = bpf_syscall_get_retval(data->ctx); int res = bpf_push_s64_to_ring(data, retval); CHECK_RES(res); + struct file *file = NULL; int32_t pipefd[2] = {-1, -1}; /* This is a pointer to the vector with the 2 file descriptors. */ @@ -4682,12 +4829,12 @@ FILLER(sys_pipe2_x, true) CHECK_RES(res); unsigned long ino = 0; - /* Not used, we use it just to call `bpf_get_fd_dev_ino` */ + /* Not used, we use it just to call `bpf_get_fd_dev_ino_file` */ unsigned long dev = 0; /* On success, pipe returns `0` */ if(retval == 0) { - bpf_get_fd_dev_ino(pipefd[0], &dev, &ino); + bpf_get_fd_dev_ino_file(pipefd[0], &dev, &ino, &file); } /* Parameter 4: ino (type: PT_UINT64) */ @@ -6802,7 +6949,7 @@ FILLER(sched_prog_exec_4, false) /* `exe_writable` and `exe_upper_layer` flag logic */ bool exe_writable = false; - bool exe_upper_layer = false; + enum ppm_overlay exe_layer = false; uint32_t flags = 0; kuid_t euid; @@ -6818,13 +6965,17 @@ FILLER(sched_prog_exec_4, false) } /* - * exe_upper_layer + * exe_upper_layer and exe_lower_layer */ - exe_upper_layer = get_exe_upper_layer(dentry,sb); - if (exe_upper_layer) + exe_layer = get_overlay_layer(dentry,sb); + if (exe_layer == PPM_OVERLAY_UPPER) { flags |= PPM_EXE_UPPER_LAYER; } + else if (exe_layer == PPM_OVERLAY_LOWER) + { + flags |= PPM_EXE_LOWER_LAYER; + } // write all additional flags for execve family here... } diff --git a/driver/event_table.c b/driver/event_table.c index dda33eb007..ac219c357b 100644 --- a/driver/event_table.c +++ b/driver/event_table.c @@ -53,7 +53,7 @@ const struct ppm_event_info g_event_info[] = { [PPME_GENERIC_E] = {"syscall", EC_OTHER | EC_SYSCALL, EF_NONE, 2, {{"ID", PT_SYSCALLID, PF_DEC}, {"nativeID", PT_UINT16, PF_DEC} } }, [PPME_GENERIC_X] = {"syscall", EC_OTHER | EC_SYSCALL, EF_NONE, 1, {{"ID", PT_SYSCALLID, PF_DEC} } }, [PPME_SYSCALL_OPEN_E] = {"open", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 3, {{"name", PT_FSPATH, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT} } }, - [PPME_SYSCALL_OPEN_X] = {"open", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 6, {{"fd", PT_FD, PF_DEC}, {"name", PT_FSPATH, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"dev", PT_UINT32, PF_HEX}, {"ino", PT_UINT64, PF_DEC} } }, + [PPME_SYSCALL_OPEN_X] = {"open", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 7, {{"fd", PT_FD, PF_DEC}, {"name", PT_FSPATH, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"dev", PT_UINT32, PF_HEX}, {"ino", PT_UINT64, PF_DEC}, {"fd_flags", PT_UINT32, PF_DEC} } }, [PPME_SYSCALL_CLOSE_E] = {"close", EC_IO_OTHER | EC_SYSCALL, EF_DESTROYS_FD | EF_USES_FD | EF_MODIFIES_STATE, 1, {{"fd", PT_FD, PF_DEC} } }, [PPME_SYSCALL_CLOSE_X] = {"close", EC_IO_OTHER | EC_SYSCALL, EF_DESTROYS_FD | EF_USES_FD | EF_MODIFIES_STATE, 1, {{"res", PT_ERRNO, PF_DEC} } }, [PPME_SYSCALL_READ_E] = {"read", EC_IO_READ | EC_SYSCALL, EF_USES_FD | EF_READS_FROM_FD, 2, {{"fd", PT_FD, PF_DEC}, {"size", PT_UINT32, PF_DEC} } }, @@ -109,7 +109,7 @@ const struct ppm_event_info g_event_info[] = { [PPME_SOCKET_ACCEPT4_E] = {"accept", EC_NET | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE | EF_OLD_VERSION, 1, {{"flags", PT_INT32, PF_HEX} } }, [PPME_SOCKET_ACCEPT4_X] = {"accept", EC_NET | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE | EF_OLD_VERSION, 3, {{"fd", PT_FD, PF_DEC}, {"tuple", PT_SOCKTUPLE, PF_NA}, {"queuepct", PT_UINT8, PF_DEC} } }, [PPME_SYSCALL_CREAT_E] = {"creat", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 2, {{"name", PT_FSPATH, PF_NA}, {"mode", PT_UINT32, PF_OCT} } }, - [PPME_SYSCALL_CREAT_X] = {"creat", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 5, {{"fd", PT_FD, PF_DEC}, {"name", PT_FSPATH, PF_NA}, {"mode", PT_UINT32, PF_OCT}, {"dev", PT_UINT32, PF_HEX}, {"ino", PT_UINT64, PF_DEC} } }, + [PPME_SYSCALL_CREAT_X] = {"creat", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 6, {{"fd", PT_FD, PF_DEC}, {"name", PT_FSPATH, PF_NA}, {"mode", PT_UINT32, PF_OCT}, {"dev", PT_UINT32, PF_HEX}, {"ino", PT_UINT64, PF_DEC}, {"fd_flags", PT_UINT32, PF_DEC} } }, [PPME_SYSCALL_PIPE_E] = {"pipe", EC_IPC | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 0}, [PPME_SYSCALL_PIPE_X] = {"pipe", EC_IPC | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 4, {{"res", PT_ERRNO, PF_DEC}, {"fd1", PT_FD, PF_DEC}, {"fd2", PT_FD, PF_DEC}, {"ino", PT_UINT64, PF_DEC} } }, [PPME_SYSCALL_EVENTFD_E] = {"eventfd", EC_IPC | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 2, {{"initval", PT_UINT64, PF_DEC}, {"flags", PT_UINT32, PF_HEX} } }, @@ -359,7 +359,7 @@ const struct ppm_event_info g_event_info[] = { [PPME_SYSCALL_MKDIRAT_E] = {"mkdirat", EC_FILE | EC_SYSCALL, EF_NONE, 0}, [PPME_SYSCALL_MKDIRAT_X] = {"mkdirat", EC_FILE | EC_SYSCALL, EF_NONE, 4, {{"res", PT_ERRNO, PF_DEC}, {"dirfd", PT_FD, PF_DEC}, {"path", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"mode", PT_UINT32, PF_HEX} } }, [PPME_SYSCALL_OPENAT_2_E] = {"openat", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 4, {{"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(0)}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT} } }, - [PPME_SYSCALL_OPENAT_2_X] = {"openat", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 7, {{"fd", PT_FD, PF_DEC}, {"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"dev", PT_UINT32, PF_HEX}, {"ino", PT_UINT64, PF_DEC} } }, + [PPME_SYSCALL_OPENAT_2_X] = {"openat", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 8, {{"fd", PT_FD, PF_DEC}, {"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"dev", PT_UINT32, PF_HEX}, {"ino", PT_UINT64, PF_DEC}, {"fd_flags", PT_UINT32, PF_DEC} } }, [PPME_SYSCALL_LINK_2_E] = {"link", EC_FILE | EC_SYSCALL, EF_NONE, 0}, [PPME_SYSCALL_LINK_2_X] = {"link", EC_FILE | EC_SYSCALL, EF_NONE, 3, {{"res", PT_ERRNO, PF_DEC}, {"oldpath", PT_FSPATH, PF_NA}, {"newpath", PT_FSPATH, PF_NA} } }, [PPME_SYSCALL_LINKAT_2_E] = {"linkat", EC_FILE | EC_SYSCALL, EF_NONE, 0}, @@ -379,7 +379,7 @@ const struct ppm_event_info g_event_info[] = { [PPME_CONTAINER_JSON_2_E] = {"container", EC_PROCESS | EC_METAEVENT, EF_MODIFIES_STATE | EF_LARGE_PAYLOAD, 1, {{"json", PT_CHARBUF, PF_NA} } }, /// TODO: do we need SKIPPARSERESET flag? [PPME_CONTAINER_JSON_2_X] = {"NA", EC_UNKNOWN, EF_UNUSED, 0}, [PPME_SYSCALL_OPENAT2_E] = {"openat2", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 5, {{"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"resolve", PT_FLAGS32, PF_HEX, openat2_flags} } }, - [PPME_SYSCALL_OPENAT2_X] = {"openat2", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 8, {{"fd", PT_FD, PF_DEC}, {"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"resolve", PT_FLAGS32, PF_HEX, openat2_flags}, {"dev", PT_UINT32, PF_HEX}, {"ino", PT_UINT64, PF_DEC} } }, + [PPME_SYSCALL_OPENAT2_X] = {"openat2", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 9, {{"fd", PT_FD, PF_DEC}, {"dirfd", PT_FD, PF_DEC}, {"name", PT_FSRELPATH, PF_NA, DIRFD_PARAM(1)}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"mode", PT_UINT32, PF_OCT}, {"resolve", PT_FLAGS32, PF_HEX, openat2_flags}, {"dev", PT_UINT32, PF_HEX}, {"ino", PT_UINT64, PF_DEC}, {"fd_flags", PT_UINT32, PF_DEC} } }, [PPME_SYSCALL_MPROTECT_E] = {"mprotect", EC_MEMORY | EC_SYSCALL, EF_NONE, 3, {{"addr", PT_UINT64, PF_HEX}, {"length", PT_UINT64, PF_DEC}, {"prot", PT_FLAGS32, PF_HEX, prot_flags} } }, [PPME_SYSCALL_MPROTECT_X] = {"mprotect", EC_MEMORY | EC_SYSCALL, EF_NONE, 1, {{"res", PT_ERRNO, PF_DEC} } }, [PPME_SYSCALL_EXECVEAT_E] = {"execveat", EC_PROCESS | EC_SYSCALL, EF_MODIFIES_STATE, 3, {{"dirfd", PT_FD, PF_DEC}, {"pathname", PT_FSRELPATH, PF_NA, DIRFD_PARAM(0)}, {"flags", PT_FLAGS32, PF_HEX, execveat_flags} } }, @@ -389,7 +389,7 @@ const struct ppm_event_info g_event_info[] = { [PPME_SYSCALL_CLONE3_E] = {"clone3", EC_PROCESS | EC_SYSCALL, EF_MODIFIES_STATE, 0}, [PPME_SYSCALL_CLONE3_X] = {"clone3", EC_PROCESS | EC_SYSCALL, EF_MODIFIES_STATE, 21, {{"res", PT_PID, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_INT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"cgroups", PT_BYTEBUF, PF_NA}, {"flags", PT_FLAGS32, PF_HEX, clone_flags}, {"uid", PT_UINT32, PF_DEC}, {"gid", PT_UINT32, PF_DEC}, {"vtid", PT_PID, PF_DEC}, {"vpid", PT_PID, PF_DEC}, {"pidns_init_start_ts", PT_UINT64, PF_DEC} } }, [PPME_SYSCALL_OPEN_BY_HANDLE_AT_E] = {"open_by_handle_at", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 0}, - [PPME_SYSCALL_OPEN_BY_HANDLE_AT_X] = {"open_by_handle_at", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 6, {{"fd", PT_FD, PF_DEC}, {"mountfd", PT_FD, PF_DEC}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"path", PT_FSPATH, PF_NA}, {"dev", PT_UINT32, PF_HEX}, {"ino", PT_UINT64, PF_DEC} } }, + [PPME_SYSCALL_OPEN_BY_HANDLE_AT_X] = {"open_by_handle_at", EC_FILE | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 7, {{"fd", PT_FD, PF_DEC}, {"mountfd", PT_FD, PF_DEC}, {"flags", PT_FLAGS32, PF_HEX, file_flags}, {"path", PT_FSPATH, PF_NA}, {"dev", PT_UINT32, PF_HEX}, {"ino", PT_UINT64, PF_DEC}, {"fd_flags", PT_UINT32, PF_DEC} } }, [PPME_SYSCALL_IO_URING_SETUP_E] = {"io_uring_setup", EC_IO_OTHER | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 0}, [PPME_SYSCALL_IO_URING_SETUP_X] = {"io_uring_setup", EC_IO_OTHER | EC_SYSCALL, EF_CREATES_FD | EF_MODIFIES_STATE, 8, {{"res", PT_ERRNO, PF_DEC}, {"entries", PT_UINT32, PF_DEC}, {"sq_entries", PT_UINT32, PF_DEC},{"cq_entries", PT_UINT32, PF_DEC},{"flags", PT_FLAGS32, PF_HEX, io_uring_setup_flags},{"sq_thread_cpu", PT_UINT32, PF_DEC}, {"sq_thread_idle", PT_UINT32, PF_DEC},{"features", PT_FLAGS32, PF_HEX, io_uring_setup_feats}}}, [PPME_SYSCALL_IO_URING_ENTER_E] = {"io_uring_enter", EC_IO_OTHER | EC_SYSCALL, EF_NONE, 0}, diff --git a/driver/flags_table.c b/driver/flags_table.c index 67de5c8429..d4b37f4118 100644 --- a/driver/flags_table.c +++ b/driver/flags_table.c @@ -558,6 +558,7 @@ const struct ppm_name_value execve_flags[] = { {"EXE_WRITABLE", PPM_EXE_WRITABLE}, {"EXE_UPPER_LAYER", PPM_EXE_UPPER_LAYER}, {"EXE_FROM_MEMFD", PPM_EXE_FROM_MEMFD}, + {"EXE_LOWER_LAYER", PPM_EXE_LOWER_LAYER}, {0, 0}, }; @@ -769,4 +770,10 @@ const struct ppm_name_value finit_module_flags[] = { {"MODULE_INIT_IGNORE_VERMAGIC", PPM_MODULE_INIT_IGNORE_VERMAGIC}, {"MODULE_INIT_COMPRESSED_FILE", PPM_MODULE_INIT_COMPRESSED_FILE}, {0, 0}, -}; \ No newline at end of file +}; + +const struct ppm_name_value fd_flags[] = { + {"FD_UPPER_LAYER", PPM_FD_UPPER_LAYER}, + {"FD_LOWER_LAYER", PPM_FD_LOWER_LAYER}, + {0, 0}, +}; diff --git a/driver/modern_bpf/helpers/extract/extract_from_kernel.h b/driver/modern_bpf/helpers/extract/extract_from_kernel.h index 6306e84d84..98c5d57612 100644 --- a/driver/modern_bpf/helpers/extract/extract_from_kernel.h +++ b/driver/modern_bpf/helpers/extract/extract_from_kernel.h @@ -337,26 +337,6 @@ static __always_inline uint64_t extract__epoch_ns_from_time(struct timespec64 ti return (tv_sec * (uint64_t) 1000000000 + time.tv_nsec); } -/** - * \brief Extract the device number and the inode number from a file descriptor. - * - * @param fd generic file descriptor. - * @param dev pointer to the device number we have to fill. - * @param ino pointer to the inode number we have to fill. - */ -static __always_inline void extract__dev_and_ino_from_fd(int32_t fd, dev_t *dev, uint64_t *ino) -{ - struct file *f = extract__file_struct_from_fd(fd); - if(!f) - { - return; - } - - BPF_CORE_READ_INTO(dev, f, f_inode, i_sb, s_dev); - *dev = encode_dev(*dev); - BPF_CORE_READ_INTO(ino, f, f_inode, i_ino); -} - /** * \brief Extract the file mode created flag from a file descriptor. * @@ -831,7 +811,7 @@ static __always_inline void extract__egid(struct task_struct *task, uint32_t *eg // EXECVE FLAGS EXTRACTION //////////////////////// -static __always_inline bool extract__exe_upper_layer(struct inode *inode, struct file *exe_file) +static __always_inline enum ppm_overlay extract__overlay_layer(struct inode *inode, struct file *exe_file) { unsigned long sb_magic = BPF_CORE_READ(inode, i_sb, s_magic); @@ -842,14 +822,14 @@ static __always_inline bool extract__exe_upper_layer(struct inode *inode, struct unsigned long inode_size = bpf_core_type_size(struct inode); if(!inode_size) { - return false; + return PPM_OVERLAY_LOWER; } bpf_probe_read_kernel(&upper_dentry, sizeof(upper_dentry), vfs_inode + inode_size); if(!upper_dentry) { - return false; + return PPM_OVERLAY_LOWER; } struct dentry *dentry = (struct dentry *)BPF_CORE_READ(exe_file, f_path.dentry); @@ -858,7 +838,7 @@ static __always_inline bool extract__exe_upper_layer(struct inode *inode, struct bool disconnected = (d_flags & DCACHE_DISCONNECTED); if(disconnected) { - return true; + return PPM_OVERLAY_UPPER; } unsigned long flags = 0; @@ -877,12 +857,12 @@ static __always_inline bool extract__exe_upper_layer(struct inode *inode, struct unsigned long has_upper = (flags & (1U << (OVL_E_UPPER_ALIAS))); if(has_upper) { - return true; + return PPM_OVERLAY_UPPER; } - + return PPM_OVERLAY_LOWER; } - return false; + return PPM_NOT_OVERLAY_FS; } /* @@ -939,6 +919,32 @@ static __always_inline bool extract__exe_from_memfd(struct file *file) return true; } +/** + * \brief Extract the device number and the inode number from a file descriptor. + * + * @param fd generic file descriptor. + * @param dev pointer to the device number we have to fill. + * @param ino pointer to the inode number we have to fill. + */ +static __always_inline void extract__dev_ino_and_file_from_fd(int32_t fd, dev_t *dev, uint64_t *ino, enum ppm_overlay *ol) +{ + struct file *f = extract__file_struct_from_fd(fd); + if(!f) + { + return; + } + + struct inode *i = BPF_CORE_READ(f, f_inode); + if(i) + { + *ol = extract__overlay_layer(i, f);; + } + + BPF_CORE_READ_INTO(dev, i, i_sb, s_dev); + *dev = encode_dev(*dev); + BPF_CORE_READ_INTO(ino, i, i_ino); +} + /* log(NGROUPS_MAX) = log(65536) */ #define MAX_GROUP_SEARCH_DEPTH 16 diff --git a/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c b/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c index d60638039b..b7de76d977 100644 --- a/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c +++ b/driver/modern_bpf/programs/attached/events/sched_process_exec.bpf.c @@ -166,14 +166,21 @@ int BPF_PROG(t1_sched_p_exec, struct inode *exe_inode = extract__exe_inode_from_task(task); struct file *exe_file = extract__exe_file_from_task(task); + enum ppm_overlay overlay; + if(extract__exe_writable(task, exe_inode)) { flags |= PPM_EXE_WRITABLE; } - if(extract__exe_upper_layer(exe_inode, exe_file)) + overlay = extract__overlay_layer(exe_inode, exe_file); + if(overlay == PPM_OVERLAY_UPPER) { flags |= PPM_EXE_UPPER_LAYER; } + else if (overlay == PPM_OVERLAY_LOWER) + { + flags |= PPM_EXE_LOWER_LAYER; + } if(extract__exe_from_memfd(exe_file)) { flags |= PPM_EXE_FROM_MEMFD; diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/creat.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/creat.bpf.c index 35615215da..54662189d5 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/creat.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/creat.bpf.c @@ -74,10 +74,12 @@ int BPF_PROG(creat_x, dev_t dev = 0; uint64_t ino = 0; + enum ppm_overlay ol = 0; + uint32_t fd_flags = 0; if(ret > 0) { - extract__dev_and_ino_from_fd(ret, &dev, &ino); + extract__dev_ino_and_file_from_fd(ret, &dev, &ino, &ol); } /* Parameter 4: dev (type: PT_UINT32) */ @@ -86,6 +88,16 @@ int BPF_PROG(creat_x, /* Parameter 5: ino (type: PT_UINT64) */ auxmap__store_u64_param(auxmap, ino); + /* Parameter 6: fd_flags (type: PT_UINT32) */ + if(ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else if(ol == PPM_OVERLAY_LOWER) + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + auxmap__store_u32_param(auxmap, fd_flags); /*=============================== COLLECT PARAMETERS ===========================*/ auxmap__finalize_event_header(auxmap); diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execve.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execve.bpf.c index 23579738ff..11d782ec69 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execve.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execve.bpf.c @@ -226,14 +226,21 @@ int BPF_PROG(t1_execve_x, struct inode *exe_inode = extract__exe_inode_from_task(task); struct file *exe_file = extract__exe_file_from_task(task); + enum ppm_overlay overlay; + if(extract__exe_writable(task, exe_inode)) { flags |= PPM_EXE_WRITABLE; } - if(extract__exe_upper_layer(exe_inode, exe_file)) + overlay = extract__overlay_layer(exe_inode, exe_file); + if(overlay == PPM_OVERLAY_UPPER) { flags |= PPM_EXE_UPPER_LAYER; } + else if (overlay == PPM_OVERLAY_LOWER) + { + flags |= PPM_EXE_LOWER_LAYER; + } if(extract__exe_from_memfd(exe_file)) { flags |= PPM_EXE_FROM_MEMFD; diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execveat.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execveat.bpf.c index 718d876877..abba60093a 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execveat.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execveat.bpf.c @@ -240,14 +240,21 @@ int BPF_PROG(t1_execveat_x, struct inode *exe_inode = extract__exe_inode_from_task(task); struct file *exe_file = extract__exe_file_from_task(task); + enum ppm_overlay overlay; + if(extract__exe_writable(task, exe_inode)) { flags |= PPM_EXE_WRITABLE; } - if(extract__exe_upper_layer(exe_inode, exe_file)) + overlay = extract__overlay_layer(exe_inode, exe_file); + if(overlay == PPM_OVERLAY_UPPER) { flags |= PPM_EXE_UPPER_LAYER; } + else if (overlay == PPM_OVERLAY_LOWER) + { + flags |= PPM_EXE_LOWER_LAYER; + } if(extract__exe_from_memfd(exe_file)) { flags |= PPM_EXE_FROM_MEMFD; diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/open.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/open.bpf.c index 17a5332288..af9c56ac99 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/open.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/open.bpf.c @@ -85,10 +85,12 @@ int BPF_PROG(open_x, dev_t dev = 0; uint64_t ino = 0; + enum ppm_overlay ol = 0; + uint32_t fd_flags = 0; if(ret > 0) { - extract__dev_and_ino_from_fd(ret, &dev, &ino); + extract__dev_ino_and_file_from_fd(ret, &dev, &ino, &ol); } /* Parameter 5: dev (type: PT_UINT32) */ @@ -97,6 +99,17 @@ int BPF_PROG(open_x, /* Parameter 6: ino (type: PT_UINT64) */ auxmap__store_u64_param(auxmap, ino); + /* Parameter 7: fd_flags (type: PT_UINT32) */ + if(ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else if(ol == PPM_OVERLAY_LOWER) + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + auxmap__store_u32_param(auxmap, fd_flags); + /*=============================== COLLECT PARAMETERS ===========================*/ auxmap__finalize_event_header(auxmap); diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/open_by_handle_at.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/open_by_handle_at.bpf.c index 9ac21a1208..c0fbccbfc1 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/open_by_handle_at.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/open_by_handle_at.bpf.c @@ -84,6 +84,8 @@ int BPF_PROG(t1_open_by_handle_at_x, struct pt_regs *regs, long ret) { dev_t dev = 0; uint64_t ino = 0; + enum ppm_overlay ol = 0; + uint32_t fd_flags = 0; struct auxiliary_map *auxmap = auxmap__get(); if(!auxmap) @@ -107,7 +109,7 @@ int BPF_PROG(t1_open_by_handle_at_x, struct pt_regs *regs, long ret) auxmap__store_empty_param(auxmap); } - extract__dev_and_ino_from_fd(ret, &dev, &ino); + extract__dev_ino_and_file_from_fd(ret, &dev, &ino, &ol); } else { @@ -120,6 +122,17 @@ int BPF_PROG(t1_open_by_handle_at_x, struct pt_regs *regs, long ret) /* Parameter 6: ino (type: PT_UINT64) */ auxmap__store_u64_param(auxmap, ino); + /* Parameter 7: fd_flags (type: PT_UINT32) */ + if(ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else if(ol == PPM_OVERLAY_LOWER) + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + auxmap__store_u32_param(auxmap, fd_flags); + /*=============================== COLLECT PARAMETERS ===========================*/ auxmap__finalize_event_header(auxmap); diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/openat.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/openat.bpf.c index ce58cb78d9..7bf4579102 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/openat.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/openat.bpf.c @@ -102,10 +102,12 @@ int BPF_PROG(openat_x, dev_t dev = 0; uint64_t ino = 0; + enum ppm_overlay ol = 0; + uint32_t fd_flags = 0; if(ret > 0) { - extract__dev_and_ino_from_fd(ret, &dev, &ino); + extract__dev_ino_and_file_from_fd(ret, &dev, &ino, &ol); } /* Parameter 6: dev (type: PT_UINT32) */ @@ -114,6 +116,17 @@ int BPF_PROG(openat_x, /* Parameter 7: ino (type: PT_UINT64) */ auxmap__store_u64_param(auxmap, ino); + /* Parameter 8: fd_flags (type: PT_UINT32) */ + if(ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else if(ol == PPM_OVERLAY_LOWER) + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + auxmap__store_u32_param(auxmap, fd_flags); + /*=============================== COLLECT PARAMETERS ===========================*/ auxmap__finalize_event_header(auxmap); diff --git a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/openat2.bpf.c b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/openat2.bpf.c index 133beeed3d..be20fe2587 100644 --- a/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/openat2.bpf.c +++ b/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/openat2.bpf.c @@ -114,10 +114,12 @@ int BPF_PROG(openat2_x, dev_t dev = 0; uint64_t ino = 0; + enum ppm_overlay ol = 0; + uint32_t fd_flags = 0; if(ret > 0) { - extract__dev_and_ino_from_fd(ret, &dev, &ino); + extract__dev_ino_and_file_from_fd(ret, &dev, &ino, &ol); } /* Parameter 7: dev (type: PT_UINT32) */ @@ -126,6 +128,17 @@ int BPF_PROG(openat2_x, /* Parameter 8: ino (type: PT_UINT64) */ auxmap__store_u64_param(auxmap, ino); + /* Parameter 9: fd_flags (type: PT_UINT32) */ + if(ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else if(ol == PPM_OVERLAY_LOWER) + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + auxmap__store_u32_param(auxmap, fd_flags); + /*=============================== COLLECT PARAMETERS ===========================*/ auxmap__finalize_event_header(auxmap); diff --git a/driver/ppm_events_public.h b/driver/ppm_events_public.h index 104abd8f35..ce129594cb 100644 --- a/driver/ppm_events_public.h +++ b/driver/ppm_events_public.h @@ -634,6 +634,7 @@ or GPL2.txt for full copies of the license. #define PPM_EXE_WRITABLE (1 << 0) #define PPM_EXE_UPPER_LAYER (1 << 1) #define PPM_EXE_FROM_MEMFD (1 << 2) +#define PPM_EXE_LOWER_LAYER (1 << 3) /* * Execveat flags @@ -812,6 +813,12 @@ or GPL2.txt for full copies of the license. #define PPM_DELETE_MODULE_O_TRUNC (1 << 0) #define PPM_DELETE_MODULE_O_NONBLOCK (1 << 1) +/* + * FD flags + */ +#define PPM_FD_UPPER_LAYER (1 << 0) +#define PPM_FD_LOWER_LAYER (1 << 1) + /* * bpf_commands */ @@ -1045,6 +1052,13 @@ enum ppm_capture_category { PPMC_SCHED_PROC_FORK = 6, }; +enum ppm_overlay +{ + PPM_NOT_OVERLAY_FS = 0, + PPM_OVERLAY_UPPER = 1, + PPM_OVERLAY_LOWER = 2, +}; + /** @defgroup etypes Event Types * @{ */ diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c index 38ae2294aa..4f69ba2b77 100644 --- a/driver/ppm_fillers.c +++ b/driver/ppm_fillers.c @@ -94,6 +94,8 @@ enum ovl_entry_flag { #define merge_64(hi, lo) ((((unsigned long long)(hi)) << 32) + ((lo) & 0xffffffffUL)) +static enum ppm_overlay ppm_get_overlay_layer(struct file *file); + static inline struct pid_namespace *pid_ns_for_children(struct task_struct *task) { #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) @@ -210,11 +212,10 @@ int f_sys_fstat_e(struct event_filler_arguments *args) return add_sentinel(args); } -static inline void get_fd_dev_ino(int64_t fd, uint32_t* dev, uint64_t* ino) +static inline void get_fd_dev_ino_file(int64_t fd, uint32_t* dev, uint64_t* ino, struct file **file) { struct files_struct *files; struct fdtable *fdt; - struct file *file; struct inode *inode; struct super_block *sb; @@ -230,11 +231,11 @@ static inline void get_fd_dev_ino(int64_t fd, uint32_t* dev, uint64_t* ino) if (unlikely(fd > fdt->max_fds)) goto out_unlock; - file = fdt->fd[fd]; - if (unlikely(!file)) + *file = fdt->fd[fd]; + if (unlikely(!*file)) goto out_unlock; - inode = file_inode(file); + inode = file_inode(*file); if (unlikely(!inode)) goto out_unlock; @@ -332,6 +333,9 @@ int f_sys_open_x(struct event_filler_arguments *args) uint64_t ino = 0; int res; int64_t retval; + struct file *file = NULL; + enum ppm_overlay ol; + int32_t fd_flags = 0; /* * fd @@ -366,7 +370,7 @@ int f_sys_open_x(struct event_filler_arguments *args) res = val_to_ring(args, open_modes_to_scap(flags, modes), 0, false, 0); CHECK_RES(res); - get_fd_dev_ino(retval, &dev, &ino); + get_fd_dev_ino_file(retval, &dev, &ino, &file); /* * dev @@ -380,6 +384,24 @@ int f_sys_open_x(struct event_filler_arguments *args) res = val_to_ring(args, ino, 0, false, 0); CHECK_RES(res); + /* + * fd_flags + */ + if (likely(file)) + { + ol = ppm_get_overlay_layer(file); + if (ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + } + res = val_to_ring(args, fd_flags, 0, false, 0); + CHECK_RES(res); + return add_sentinel(args); } @@ -880,54 +902,58 @@ static uint32_t ppm_get_tty(void) return tty_nr; } -static bool ppm_is_upper_layer(struct file *exe_file){ +static enum ppm_overlay ppm_get_overlay_layer(struct file *file){ #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) struct super_block *sb = NULL; unsigned long sb_magic = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) - sb = exe_file->f_path.dentry->d_sb; + sb = file->f_path.dentry->d_sb; #else - sb = exe_file->f_inode->i_sb; + sb = file->f_inode->i_sb; #endif if(sb) { - struct ovl_entry *oe = (struct ovl_entry*)(exe_file->f_path.dentry->d_fsdata); sb_magic = sb->s_magic; - if(sb_magic == PPM_OVERLAYFS_SUPER_MAGIC && oe) + if(sb_magic == PPM_OVERLAYFS_SUPER_MAGIC) { - unsigned long has_upper = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) - if(oe->__upperdentry) + struct ovl_entry *oe = (struct ovl_entry*)(file->f_path.dentry->d_fsdata); + if(oe) { - return true; - } + unsigned long has_upper = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) + if(oe->__upperdentry) + { + return PPM_OVERLAY_UPPER; + } #else - struct dentry *upper_dentry = NULL; - unsigned int d_flags = exe_file->f_path.dentry->d_flags; - bool disconnected = (d_flags & DCACHE_DISCONNECTED); + struct dentry *upper_dentry = NULL; + unsigned int d_flags = file->f_path.dentry->d_flags; + bool disconnected = (d_flags & DCACHE_DISCONNECTED); - // Pointer arithmetics due to unexported ovl_inode struct - // warning: this works if and only if the dentry pointer - // is placed right after the inode struct - upper_dentry = (struct dentry *)((char *)exe_file->f_path.dentry->d_inode + sizeof(struct inode)); + // Pointer arithmetics due to unexported ovl_inode struct + // warning: this works if and only if the dentry pointer + // is placed right after the inode struct + upper_dentry = (struct dentry *)((char *)file->f_path.dentry->d_inode + sizeof(struct inode)); #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0) - has_upper = oe->has_upper; + has_upper = oe->has_upper; #elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0) - has_upper = test_bit(OVL_E_UPPER_ALIAS, &(oe->flags)); + has_upper = test_bit(OVL_E_UPPER_ALIAS, &(oe->flags)); #else - has_upper = test_bit(OVL_E_UPPER_ALIAS, (unsigned long*)&oe); + has_upper = test_bit(OVL_E_UPPER_ALIAS, (unsigned long*)&oe); #endif - if(upper_dentry && (has_upper || disconnected)) - { - return true; - } + if(upper_dentry && (has_upper || disconnected)) + { + return PPM_OVERLAY_UPPER; + } #endif + } + return PPM_OVERLAY_LOWER; } } #endif - return false; + return PPM_NOT_OVERLAY_FS; } int f_proc_startupdate(struct event_filler_arguments *args) @@ -1290,7 +1316,7 @@ int f_proc_startupdate(struct event_filler_arguments *args) long env_len = 0; uint32_t tty_nr = 0; bool exe_writable = false; - bool exe_upper_layer = false; + enum ppm_overlay exe_layer = false; struct file *exe_file = NULL; uint32_t flags = 0; // execve additional flags unsigned long i_ino = 0; @@ -1387,7 +1413,7 @@ int f_proc_startupdate(struct event_filler_arguments *args) CHECK_RES(res); /* - * exe_writable and exe_upper_layer flags + * exe_writable, exe_upper_layer and exe_lower_layer flags */ exe_file = ppm_get_mm_exe_file(mm); @@ -1416,8 +1442,8 @@ int f_proc_startupdate(struct event_filler_arguments *args) * MAY_OT_BLOCK flag is introduced and avoids the processor to being yield. */ - /* Support exe_upper_layer */ - exe_upper_layer = ppm_is_upper_layer(exe_file); + /* Support exe_upper_layer and exe_lower_layer */ + exe_layer = ppm_get_overlay_layer(exe_file); /* Support exe_from_memfd */ flags |= get_exe_from_memfd(exe_file); @@ -1477,9 +1503,12 @@ int f_proc_startupdate(struct event_filler_arguments *args) flags |= PPM_EXE_WRITABLE; } - if (exe_upper_layer) { + if (exe_layer == PPM_OVERLAY_UPPER) { flags |= PPM_EXE_UPPER_LAYER; } + else if (exe_layer == PPM_OVERLAY_LOWER) { + flags |= PPM_EXE_LOWER_LAYER; + } // write all the additional flags for execve family here... @@ -2980,6 +3009,9 @@ int f_sys_creat_x(struct event_filler_arguments *args) uint64_t ino = 0; int res; int64_t retval; + struct file *file = NULL; + enum ppm_overlay ol; + int32_t fd_flags = 0; /* * fd @@ -3001,7 +3033,7 @@ int f_sys_creat_x(struct event_filler_arguments *args) res = val_to_ring(args, open_modes_to_scap(O_CREAT, modes), 0, false, 0); CHECK_RES(res); - get_fd_dev_ino(retval, &dev, &ino); + get_fd_dev_ino_file(retval, &dev, &ino, &file); /* * dev @@ -3015,6 +3047,24 @@ int f_sys_creat_x(struct event_filler_arguments *args) res = val_to_ring(args, ino, 0, false, 0); CHECK_RES(res); + /* + * fd_flags + */ + if (likely(file)) + { + ol = ppm_get_overlay_layer(file); + if (ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + } + res = val_to_ring(args, fd_flags, 0, false, 0); + CHECK_RES(res); + return add_sentinel(args); } @@ -3026,6 +3076,7 @@ int f_sys_pipe_x(struct event_filler_arguments *args) int pipefd[2] = {-1, -1}; uint32_t dev = 0; uint64_t ino = 0; + struct file *file = NULL; /* Parameter 1: res (type: PT_ERRNO) */ retval = (int64_t)syscall_get_return_value(current, args->regs); @@ -3064,7 +3115,7 @@ int f_sys_pipe_x(struct event_filler_arguments *args) /* On success, pipe returns `0` */ if(retval == 0) { - get_fd_dev_ino(pipefd[0], &dev, &ino); + get_fd_dev_ino_file(pipefd[0], &dev, &ino, &file); } /* Parameter 4: ino (type: PT_UINT64) */ @@ -3082,6 +3133,7 @@ int f_sys_pipe2_x(struct event_filler_arguments *args) int pipefd[2] = {-1, -1}; uint32_t dev = 0; uint64_t ino = 0; + struct file *file = NULL; /* Parameter 1: res (type: PT_ERRNO) */ retval = (int64_t)syscall_get_return_value(current, args->regs); @@ -3120,7 +3172,7 @@ int f_sys_pipe2_x(struct event_filler_arguments *args) /* On success, pipe returns `0` */ if(retval == 0) { - get_fd_dev_ino(pipefd[0], &dev, &ino); + get_fd_dev_ino_file(pipefd[0], &dev, &ino, &file); } /* Parameter 4: ino (type: PT_UINT64) */ @@ -3555,6 +3607,9 @@ int f_sys_openat_x(struct event_filler_arguments *args) int res; int32_t fd; int64_t retval; + struct file *file = NULL; + enum ppm_overlay ol; + int32_t fd_flags = 0; retval = (int64_t)syscall_get_return_value(current, args->regs); res = val_to_ring(args, retval, 0, false, 0); @@ -3594,7 +3649,7 @@ int f_sys_openat_x(struct event_filler_arguments *args) syscall_get_arguments_deprecated(args, 3, 1, &modes); res = val_to_ring(args, open_modes_to_scap(flags, modes), 0, false, 0); CHECK_RES(res); - get_fd_dev_ino(retval, &dev, &ino); + get_fd_dev_ino_file(retval, &dev, &ino, &file); /* * dev @@ -3606,6 +3661,25 @@ int f_sys_openat_x(struct event_filler_arguments *args) */ res = val_to_ring(args, ino, 0, false, 0); CHECK_RES(res); + + /* + * fd_flags + */ + if (likely(file)) + { + ol = ppm_get_overlay_layer(file); + if (ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + } + res = val_to_ring(args, fd_flags, 0, false, 0); + CHECK_RES(res); + return add_sentinel(args); } @@ -4694,6 +4768,7 @@ int f_sys_mmap_e(struct event_filler_arguments *args) syscall_get_arguments_deprecated(args, 4, 1, &val); fd = (int32_t)val; res = val_to_ring(args, (int64_t)fd, 0, false, 0); + args->fd = (int)val; CHECK_RES(res); /* @@ -4983,6 +5058,9 @@ int f_sys_openat2_x(struct event_filler_arguments *args) int res; int32_t fd; int64_t retval; + struct file *file = NULL; + enum ppm_overlay ol; + int32_t fd_flags = 0; #ifdef __NR_openat2 struct open_how how; #endif @@ -5050,7 +5128,7 @@ int f_sys_openat2_x(struct event_filler_arguments *args) res = val_to_ring(args, resolve, 0, true, 0); CHECK_RES(res); - get_fd_dev_ino(retval, &dev, &ino); + get_fd_dev_ino_file(retval, &dev, &ino, &file); /* * dev @@ -5064,6 +5142,24 @@ int f_sys_openat2_x(struct event_filler_arguments *args) res = val_to_ring(args, ino, 0, false, 0); CHECK_RES(res); + /* + * fd_flags + */ + if (likely(file)) + { + ol = ppm_get_overlay_layer(file); + if (ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + } + res = val_to_ring(args, fd_flags, 0, false, 0); + CHECK_RES(res); + return add_sentinel(args); } @@ -5135,6 +5231,9 @@ int f_sys_open_by_handle_at_x(struct event_filler_arguments *args) long retval = 0; char *pathname = NULL; int32_t mountfd = 0; + struct file *file = NULL; + enum ppm_overlay ol; + int32_t fd_flags = 0; /* Parameter 1: ret (type: PT_FD) */ retval = syscall_get_return_value(current, args->regs); @@ -5182,7 +5281,7 @@ int f_sys_open_by_handle_at_x(struct event_filler_arguments *args) res = val_to_ring(args, (unsigned long)pathname, 0, false, 0); CHECK_RES(res); - get_fd_dev_ino(retval, &dev, &ino); + get_fd_dev_ino_file(retval, &dev, &ino, &file); /* Parameter 5: dev (type: PT_UINT32) */ res = val_to_ring(args, dev, 0, false, 0); @@ -5192,6 +5291,23 @@ int f_sys_open_by_handle_at_x(struct event_filler_arguments *args) res = val_to_ring(args, ino, 0, false, 0); CHECK_RES(res); + /* + * fd_flags + */ + if (likely(file)) + { + ol = ppm_get_overlay_layer(file); + if (ol == PPM_OVERLAY_UPPER) + { + fd_flags |= PPM_FD_UPPER_LAYER; + } + else + { + fd_flags |= PPM_FD_LOWER_LAYER; + } + } + res = val_to_ring(args, fd_flags, 0, false, 0); + CHECK_RES(res); return add_sentinel(args); } @@ -7280,7 +7396,7 @@ int f_sched_prog_exec(struct event_filler_arguments *args) uint32_t tty_nr = 0; uint32_t flags = 0; bool exe_writable = false; - bool exe_upper_layer = false; + enum ppm_overlay exe_layer = false; struct file *exe_file = NULL; const struct cred *cred = NULL; unsigned long i_ino = 0; @@ -7464,7 +7580,7 @@ int f_sched_prog_exec(struct event_filler_arguments *args) res = val_to_ring(args, loginuid, 0, false, 0); CHECK_RES(res); - /* `exe_writable` and `exe_upper_layer` flag logic */ + /* `exe_writable`, `exe_upper_layer` and `exe_lower_layer` flag logic */ exe_file = ppm_get_mm_exe_file(mm); if(exe_file != NULL) { @@ -7490,8 +7606,8 @@ int f_sched_prog_exec(struct event_filler_arguments *args) * MAY_OT_BLOCK flag is introduced and avoids the processor to being yield. */ - /* Support exe_upper_layer */ - exe_upper_layer = ppm_is_upper_layer(exe_file); + /* Support exe_upper_layer and exe_lower_layer */ + exe_layer = ppm_get_overlay_layer(exe_file); /* Support exe_from_memfd */ flags |= get_exe_from_memfd(exe_file); @@ -7552,10 +7668,14 @@ int f_sched_prog_exec(struct event_filler_arguments *args) flags |= PPM_EXE_WRITABLE; } - if(exe_upper_layer) + if(exe_layer == PPM_OVERLAY_UPPER) { flags |= PPM_EXE_UPPER_LAYER; } + else if(exe_layer == PPM_OVERLAY_LOWER) + { + flags |= PPM_EXE_LOWER_LAYER; + } // write all the additional flags for execve family here... diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index 56be5c1d70..70b8876ff5 100644 --- a/userspace/libscap/scap.h +++ b/userspace/libscap/scap.h @@ -265,6 +265,7 @@ typedef struct scap_threadinfo char exepath[SCAP_MAX_PATH_SIZE+1]; ///< full executable path bool exe_writable; ///< true if the original executable is writable by the same user that spawned it. bool exe_upper_layer; //< True if the original executable belongs to upper layer in overlayfs + bool exe_lower_layer; //< True if the original executable belongs to lower layer in overlayfs bool exe_from_memfd; //< True if the original executable is stored in pathless memory referenced by a memfd char args[SCAP_MAX_ARGS_SIZE+1]; ///< Command line arguments (e.g. "-d1") uint16_t args_len; ///< Command line arguments length diff --git a/userspace/libsinsp/fdinfo.h b/userspace/libsinsp/fdinfo.h index b3c42e52e5..a0b3732820 100644 --- a/userspace/libsinsp/fdinfo.h +++ b/userspace/libsinsp/fdinfo.h @@ -109,6 +109,8 @@ class SINSP_PUBLIC sinsp_fdinfo : public libsinsp::state::table_entry FLAGS_IS_CLONED = (1 << 14), FLAGS_CONNECTION_PENDING = (1 << 15), FLAGS_CONNECTION_FAILED = (1 << 16), + FLAGS_OVERLAY_UPPER = (1 << 17), + FLAGS_OVERLAY_LOWER = (1 << 18), }; sinsp_fdinfo(std::shared_ptr dyn_fields = nullptr); @@ -323,6 +325,16 @@ class SINSP_PUBLIC sinsp_fdinfo : public libsinsp::state::table_entry return (m_flags & FLAGS_IS_CLONED) == FLAGS_IS_CLONED; } + inline bool is_overlay_upper() const + { + return (m_flags & FLAGS_OVERLAY_UPPER) == FLAGS_OVERLAY_UPPER; + } + + inline bool is_overlay_lower() const + { + return (m_flags & FLAGS_OVERLAY_LOWER) == FLAGS_OVERLAY_LOWER; + } + void add_filename_raw(std::string_view rawpath); void add_filename(std::string_view fullpath); @@ -422,6 +434,16 @@ class SINSP_PUBLIC sinsp_fdinfo : public libsinsp::state::table_entry m_flags |= FLAGS_IS_CLONED; } + inline void set_overlay_upper() + { + m_flags |= FLAGS_OVERLAY_UPPER; + } + + inline void set_overlay_lower() + { + m_flags |= FLAGS_OVERLAY_LOWER; + } + scap_fd_type m_type = SCAP_FD_UNINITIALIZED; ///< The fd type, e.g. file, directory, IPv4 socket... uint32_t m_openflags = 0; ///< If this FD is a file, the flags that were used when opening it. See the PPM_O_* definitions in driver/ppm_events_public.h. sinsp_sockinfo m_sockinfo = {}; ///< Socket-specific state. This is uninitialized (zero) for non-socket FDs. diff --git a/userspace/libsinsp/parsers.cpp b/userspace/libsinsp/parsers.cpp index 514956cb8c..6b9d509c4f 100644 --- a/userspace/libsinsp/parsers.cpp +++ b/userspace/libsinsp/parsers.cpp @@ -1388,6 +1388,8 @@ void sinsp_parser::parse_clone_exit_caller(sinsp_evt *evt, int64_t child_tid) child_tinfo->m_exe_upper_layer = caller_tinfo->m_exe_upper_layer; + child_tinfo->m_exe_lower_layer = caller_tinfo->m_exe_lower_layer; + child_tinfo->m_exe_from_memfd = caller_tinfo->m_exe_from_memfd; child_tinfo->m_root = caller_tinfo->m_root; @@ -1715,6 +1717,8 @@ void sinsp_parser::parse_clone_exit_child(sinsp_evt *evt) child_tinfo->m_exe_upper_layer = lookup_tinfo->m_exe_upper_layer; + child_tinfo->m_exe_lower_layer = lookup_tinfo->m_exe_lower_layer; + child_tinfo->m_exe_from_memfd = lookup_tinfo->m_exe_from_memfd; child_tinfo->m_root = lookup_tinfo->m_root; @@ -2378,6 +2382,7 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) evt->get_tinfo()->m_exe_writable = ((flags & PPM_EXE_WRITABLE) != 0); evt->get_tinfo()->m_exe_upper_layer = ((flags & PPM_EXE_UPPER_LAYER) != 0); evt->get_tinfo()->m_exe_from_memfd = ((flags & PPM_EXE_FROM_MEMFD) != 0); + evt->get_tinfo()->m_exe_lower_layer = ((flags & PPM_EXE_LOWER_LAYER) != 0); } // Get capabilities @@ -2564,6 +2569,7 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt) uint16_t etype = evt->get_type(); uint32_t dev = 0; uint64_t ino = 0; + uint32_t fd_flags = 0; bool lastevent_retrieved = false; if(evt->get_tinfo() == nullptr) @@ -2598,6 +2604,10 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt) if (evt->get_num_params() > 5) { ino = evt->get_param(5)->as(); + if (evt->get_num_params() > 6) + { + fd_flags = evt->get_param(6)->as(); + } } } @@ -2635,6 +2645,10 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt) if (evt->get_num_params() > 4) { ino = evt->get_param(4)->as(); + if (evt->get_num_params() > 5) + { + fd_flags = evt->get_param(5)->as(); + } } } @@ -2681,6 +2695,10 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt) if (evt->get_num_params() > 6) { ino = evt->get_param(6)->as(); + if (evt->get_num_params() > 7) + { + fd_flags = evt->get_param(7)->as(); + } } } else if(etype == PPME_SYSCALL_OPENAT2_X && evt->get_num_params() > 6) @@ -2689,6 +2707,10 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt) if (evt->get_num_params() > 7) { ino = evt->get_param(7)->as(); + if (evt->get_num_params() > 8) + { + fd_flags = evt->get_param(8)->as(); + } } } @@ -2729,6 +2751,10 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt) if (evt->get_num_params() > 5) { ino = evt->get_param(5)->as(); + if (evt->get_num_params() > 6) + { + fd_flags = evt->get_param(6)->as(); + } } } @@ -2769,6 +2795,14 @@ void sinsp_parser::parse_open_openat_creat_exit(sinsp_evt *evt) fdi->m_ino = ino; fdi->add_filename_raw(name); fdi->add_filename(fullpath); + if(fd_flags & PPM_FD_UPPER_LAYER) + { + fdi->set_overlay_upper(); + } + if(fd_flags & PPM_FD_LOWER_LAYER) + { + fdi->set_overlay_lower(); + } // // Add the fd to the table. diff --git a/userspace/libsinsp/sinsp_filtercheck_fd.cpp b/userspace/libsinsp/sinsp_filtercheck_fd.cpp index 9618866922..3516a7e70a 100644 --- a/userspace/libsinsp/sinsp_filtercheck_fd.cpp +++ b/userspace/libsinsp/sinsp_filtercheck_fd.cpp @@ -94,6 +94,8 @@ static const filtercheck_field_info sinsp_filter_check_fd_fields[] = {PT_INT64, EPF_NONE, PF_DEC, "fd.ino", "FD Inode Number", "inode number of the referenced file"}, {PT_CHARBUF, EPF_NONE, PF_NA, "fd.nameraw", "FD Name Raw", "FD full name raw. Just like fd.name, but only used if fd is a file path. File path is kept raw with limited sanitization and without deriving the absolute path."}, {PT_CHARBUF, EPF_IS_LIST | EPF_ARG_ALLOWED | EPF_NO_RHS | EPF_NO_TRANSFORMER, PF_DEC, "fd.types", "FD Type", "List of FD types in used. Can be passed an fd number e.g. fd.types[0] to get the type of stdout as a single item list."}, + {PT_BOOL, EPF_NONE, PF_NA, "fd.is_upper_layer", "FD Upper Layer", "'true' if the fd is of a file in the upper layer of an overlayfs."}, + {PT_BOOL, EPF_NONE, PF_NA, "fd.is_lower_layer", "FD Lower Layer", "'true' if the fd is of a file in the lower layer of an overlayfs."}, }; sinsp_filter_check_fd::sinsp_filter_check_fd() @@ -1388,6 +1390,28 @@ uint8_t* sinsp_filter_check_fd::extract_single(sinsp_evt *evt, uint32_t* len, bo RETURN_EXTRACT_STRING(m_tstr); } break; + case TYPE_FDUPPER: + { + if(m_fdinfo == NULL) + { + return NULL; + } + + m_val.u32 = m_fdinfo->is_overlay_upper(); + RETURN_EXTRACT_VAR(m_val.u32); + } + break; + case TYPE_FDLOWER: + { + if(m_fdinfo == NULL) + { + return NULL; + } + + m_val.u32 = m_fdinfo->is_overlay_lower(); + RETURN_EXTRACT_VAR(m_val.u32); + } + break; default: ASSERT(false); } diff --git a/userspace/libsinsp/sinsp_filtercheck_fd.h b/userspace/libsinsp/sinsp_filtercheck_fd.h index 0f94bbeeb8..1cc6ee22da 100644 --- a/userspace/libsinsp/sinsp_filtercheck_fd.h +++ b/userspace/libsinsp/sinsp_filtercheck_fd.h @@ -69,6 +69,8 @@ class sinsp_filter_check_fd : public sinsp_filter_check TYPE_INO = 41, TYPE_FDNAMERAW = 42, TYPE_FDTYPES = 43, + TYPE_FDUPPER = 44, + TYPE_FDLOWER = 45, }; sinsp_filter_check_fd(); diff --git a/userspace/libsinsp/sinsp_filtercheck_thread.cpp b/userspace/libsinsp/sinsp_filtercheck_thread.cpp index 2d59cfbd50..d137396ea2 100644 --- a/userspace/libsinsp/sinsp_filtercheck_thread.cpp +++ b/userspace/libsinsp/sinsp_filtercheck_thread.cpp @@ -86,6 +86,7 @@ static const filtercheck_field_info sinsp_filter_check_thread_fields[] = {PT_RELTIME, EPF_NONE, PF_DEC, "proc.ppid.ts", "Parent Process start ts", "Start of parent process as epoch timestamp in nanoseconds."}, {PT_BOOL, EPF_NONE, PF_NA, "proc.is_exe_writable", "Process Executable Is Writable", "'true' if this process' executable file is writable by the same user that spawned the process."}, {PT_BOOL, EPF_NONE, PF_NA, "proc.is_exe_upper_layer", "Process Executable Is In Upper Layer", "'true' if this process' executable file is in upper layer in overlayfs. This field value can only be trusted if the underlying kernel version is greater or equal than 3.18.0, since overlayfs was introduced at that time."}, + {PT_BOOL, EPF_NONE, PF_NA, "proc.is_exe_lower_layer", "Process Executable Is In Lower Layer", "'true' if this process' executable file is in lower layer in overlayfs. This field value can only be trusted if the underlying kernel version is greater or equal than 3.18.0, since overlayfs was introduced at that time."}, {PT_BOOL, EPF_NONE, PF_NA, "proc.is_exe_from_memfd", "Process Executable Is Stored In Memfd", "'true' if the executable file of the current process is an anonymous file created using memfd_create() and is being executed by referencing its file descriptor (fd). This type of file exists only in memory and not on disk. Relevant to detect malicious in-memory code injection. Requires kernel version greater or equal to 3.17.0."}, {PT_BOOL, EPF_NONE, PF_NA, "proc.is_sid_leader", "Process Is Process Session Leader", "'true' if this process is the leader of the process session, proc.sid == proc.vpid. For host processes vpid reflects pid."}, {PT_BOOL, EPF_NONE, PF_NA, "proc.is_vpgid_leader", "Process Is Virtual Process Group Leader", "'true' if this process is the leader of the virtual process group, proc.vpgid == proc.vpid. For host processes vpgid and vpid reflect pgid and pid. Can help to distinguish if the process was 'directly' executed for instance in a tty (similar to bash history logging, `is_vpgid_leader` would be 'true') or executed as descendent process in the same process group which for example is the case when subprocesses are spawned from a script (`is_vpgid_leader` would be 'false')."}, @@ -1511,6 +1512,9 @@ uint8_t* sinsp_filter_check_thread::extract_single(sinsp_evt *evt, uint32_t* len case TYPE_IS_EXE_UPPER_LAYER: m_val.u32 = tinfo->m_exe_upper_layer; RETURN_EXTRACT_VAR(m_val.u32); + case TYPE_IS_EXE_LOWER_LAYER: + m_val.u32 = tinfo->m_exe_lower_layer; + RETURN_EXTRACT_VAR(m_val.u32); case TYPE_IS_EXE_FROM_MEMFD: m_val.u32 = tinfo->m_exe_from_memfd; RETURN_EXTRACT_VAR(m_val.u32); diff --git a/userspace/libsinsp/sinsp_filtercheck_thread.h b/userspace/libsinsp/sinsp_filtercheck_thread.h index e3af894b97..5822bd2c41 100644 --- a/userspace/libsinsp/sinsp_filtercheck_thread.h +++ b/userspace/libsinsp/sinsp_filtercheck_thread.h @@ -66,6 +66,7 @@ class sinsp_filter_check_thread : public sinsp_filter_check TYPE_PPID_CLONE_TS, TYPE_IS_EXE_WRITABLE, TYPE_IS_EXE_UPPER_LAYER, + TYPE_IS_EXE_LOWER_LAYER, TYPE_IS_EXE_FROM_MEMFD, TYPE_IS_SID_LEADER, TYPE_IS_VPGID_LEADER, diff --git a/userspace/libsinsp/threadinfo.cpp b/userspace/libsinsp/threadinfo.cpp index a856098d77..30e8d35540 100644 --- a/userspace/libsinsp/threadinfo.cpp +++ b/userspace/libsinsp/threadinfo.cpp @@ -69,6 +69,7 @@ libsinsp::state::static_struct::field_infos sinsp_threadinfo::static_fields() co define_static_field(ret, this, m_exepath, "exe_path"); define_static_field(ret, this, m_exe_writable, "exe_writable"); define_static_field(ret, this, m_exe_upper_layer, "exe_upper_layer"); + define_static_field(ret, this, m_exe_lower_layer, "exe_lower_layer"); define_static_field(ret, this, m_exe_from_memfd, "exe_from_memfd"); define_static_field(ret, this, m_args_table_adapter.table_ptr(), "args", true); define_static_field(ret, this, m_env_table_adapter.table_ptr(), "env", true); @@ -156,6 +157,7 @@ void sinsp_threadinfo::init() m_filtered_out = false; m_exe_writable = false; m_exe_upper_layer = false; + m_exe_lower_layer = false; m_exe_from_memfd = false; } @@ -465,6 +467,7 @@ void sinsp_threadinfo::init(scap_threadinfo* pi) m_exepath = pi->exepath; m_exe_writable = pi->exe_writable; m_exe_upper_layer = pi->exe_upper_layer; + m_exe_lower_layer = pi->exe_lower_layer; m_exe_from_memfd = pi->exe_from_memfd; /* We cannot obtain the reaper_tid from a /proc scan */ diff --git a/userspace/libsinsp/threadinfo.h b/userspace/libsinsp/threadinfo.h index ec428de4da..e7d19b50a0 100644 --- a/userspace/libsinsp/threadinfo.h +++ b/userspace/libsinsp/threadinfo.h @@ -498,6 +498,7 @@ class SINSP_PUBLIC sinsp_threadinfo : public libsinsp::state::table_entry std::string m_exepath; ///< full executable path bool m_exe_writable; bool m_exe_upper_layer; ///< True if the executable file belongs to upper layer in overlayfs + bool m_exe_lower_layer; ///< True if the executable file belongs to lower layer in overlayfs bool m_exe_from_memfd; ///< True if the executable is stored in fileless memory referenced by memfd std::vector m_args; ///< Command line arguments (e.g. "-d1") std::vector m_env; ///< Environment variables