diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-20 15:06:02 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-20 15:06:02 +0300 |
| commit | 271af607921ceabc640271c475a66e45b9460d3f (patch) | |
| tree | 6ae443fd372dbeea947cba7bd5851f7936f354b5 /internal | |
| parent | 63184df8d5e30f70011a97d862103fa38d797bb3 (diff) | |
feat: add mount/fs management syscall tracing for c7
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/c/generated_tracepoints.c | 97 | ||||
| -rw-r--r-- | internal/c/generated_tracepoints_result.txt | 22 | ||||
| -rw-r--r-- | internal/c/types.h | 13 | ||||
| -rw-r--r-- | internal/event/interface_assertions.go | 3 | ||||
| -rw-r--r-- | internal/eventloop_exit.go | 12 | ||||
| -rw-r--r-- | internal/eventloop_mountfs_test.go | 81 | ||||
| -rw-r--r-- | internal/eventloop_runtime.go | 11 | ||||
| -rw-r--r-- | internal/generate/bpfhandler.go | 18 | ||||
| -rw-r--r-- | internal/generate/classify.go | 53 | ||||
| -rw-r--r-- | internal/generate/classify_test.go | 123 | ||||
| -rw-r--r-- | internal/generate/codegen_test.go | 25 | ||||
| -rw-r--r-- | internal/generate/family.go | 8 | ||||
| -rw-r--r-- | internal/generate/kindregistry.go | 1 | ||||
| -rw-r--r-- | internal/generate/testdata.go | 333 | ||||
| -rw-r--r-- | internal/types/fastdecode.go | 20 | ||||
| -rw-r--r-- | internal/types/fastdecode_test.go | 43 | ||||
| -rw-r--r-- | internal/types/generated_types.go | 74 | ||||
| -rw-r--r-- | internal/types/types_test.go | 27 |
18 files changed, 907 insertions, 57 deletions
diff --git a/internal/c/generated_tracepoints.c b/internal/c/generated_tracepoints.c index 55164d5..4db2e8d 100644 --- a/internal/c/generated_tracepoints.c +++ b/internal/c/generated_tracepoints.c @@ -3344,7 +3344,7 @@ int handle_sys_exit_msgrcv(struct syscall_trace_exit *ctx) { return 0; } -/// sys_enter_quotactl is a struct null_event +/// sys_enter_quotactl is a struct path_event SEC("tracepoint/syscalls/sys_enter_quotactl") int handle_sys_enter_quotactl(struct syscall_trace_enter *ctx) { __u32 pid, tid; @@ -3354,15 +3354,17 @@ int handle_sys_enter_quotactl(struct syscall_trace_enter *ctx) { if (!ior_on_syscall_enter(tid, SYS_ENTER_QUOTACTL)) return 0; - struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0); + struct path_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct path_event), 0); if (!ev) return 0; - ev->event_type = ENTER_NULL_EVENT; + ev->event_type = ENTER_PATH_EVENT; ev->trace_id = SYS_ENTER_QUOTACTL; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + __builtin_memset(&(ev->pathname), 0, sizeof(ev->pathname)); + bpf_probe_read_user_str(ev->pathname, sizeof(ev->pathname), (void*)ctx->args[1]); bpf_ringbuf_submit(ev, 0); return 0; @@ -5500,7 +5502,7 @@ int handle_sys_exit_futimesat(struct syscall_trace_exit *ctx) { return 0; } -/// sys_enter_utimes is a struct null_event +/// sys_enter_utimes is a struct path_event SEC("tracepoint/syscalls/sys_enter_utimes") int handle_sys_enter_utimes(struct syscall_trace_enter *ctx) { __u32 pid, tid; @@ -5510,15 +5512,17 @@ int handle_sys_enter_utimes(struct syscall_trace_enter *ctx) { if (!ior_on_syscall_enter(tid, SYS_ENTER_UTIMES)) return 0; - struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0); + struct path_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct path_event), 0); if (!ev) return 0; - ev->event_type = ENTER_NULL_EVENT; + ev->event_type = ENTER_PATH_EVENT; ev->trace_id = SYS_ENTER_UTIMES; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + __builtin_memset(&(ev->pathname), 0, sizeof(ev->pathname)); + bpf_probe_read_user_str(ev->pathname, sizeof(ev->pathname), (void*)ctx->args[0]); bpf_ringbuf_submit(ev, 0); return 0; @@ -5550,7 +5554,7 @@ int handle_sys_exit_utimes(struct syscall_trace_exit *ctx) { return 0; } -/// sys_enter_utime is a struct null_event +/// sys_enter_utime is a struct path_event SEC("tracepoint/syscalls/sys_enter_utime") int handle_sys_enter_utime(struct syscall_trace_enter *ctx) { __u32 pid, tid; @@ -5560,15 +5564,17 @@ int handle_sys_enter_utime(struct syscall_trace_enter *ctx) { if (!ior_on_syscall_enter(tid, SYS_ENTER_UTIME)) return 0; - struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0); + struct path_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct path_event), 0); if (!ev) return 0; - ev->event_type = ENTER_NULL_EVENT; + ev->event_type = ENTER_PATH_EVENT; ev->trace_id = SYS_ENTER_UTIME; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + __builtin_memset(&(ev->pathname), 0, sizeof(ev->pathname)); + bpf_probe_read_user_str(ev->pathname, sizeof(ev->pathname), (void*)ctx->args[0]); bpf_ringbuf_submit(ev, 0); return 0; @@ -6833,7 +6839,7 @@ int handle_sys_exit_fremovexattr(struct syscall_trace_exit *ctx) { return 0; } -/// sys_enter_umount is a struct null_event +/// sys_enter_umount is a struct path_event SEC("tracepoint/syscalls/sys_enter_umount") int handle_sys_enter_umount(struct syscall_trace_enter *ctx) { __u32 pid, tid; @@ -6843,15 +6849,17 @@ int handle_sys_enter_umount(struct syscall_trace_enter *ctx) { if (!ior_on_syscall_enter(tid, SYS_ENTER_UMOUNT)) return 0; - struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0); + struct path_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct path_event), 0); if (!ev) return 0; - ev->event_type = ENTER_NULL_EVENT; + ev->event_type = ENTER_PATH_EVENT; ev->trace_id = SYS_ENTER_UMOUNT; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + __builtin_memset(&(ev->pathname), 0, sizeof(ev->pathname)); + bpf_probe_read_user_str(ev->pathname, sizeof(ev->pathname), (void*)ctx->args[0]); bpf_ringbuf_submit(ev, 0); return 0; @@ -6937,7 +6945,7 @@ int handle_sys_exit_open_tree(struct syscall_trace_exit *ctx) { return 0; } -/// sys_enter_mount is a struct null_event +/// sys_enter_mount is a struct path_event SEC("tracepoint/syscalls/sys_enter_mount") int handle_sys_enter_mount(struct syscall_trace_enter *ctx) { __u32 pid, tid; @@ -6947,15 +6955,17 @@ int handle_sys_enter_mount(struct syscall_trace_enter *ctx) { if (!ior_on_syscall_enter(tid, SYS_ENTER_MOUNT)) return 0; - struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0); + struct path_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct path_event), 0); if (!ev) return 0; - ev->event_type = ENTER_NULL_EVENT; + ev->event_type = ENTER_PATH_EVENT; ev->trace_id = SYS_ENTER_MOUNT; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + __builtin_memset(&(ev->pathname), 0, sizeof(ev->pathname)); + bpf_probe_read_user_str(ev->pathname, sizeof(ev->pathname), (void*)ctx->args[1]); bpf_ringbuf_submit(ev, 0); return 0; @@ -6987,7 +6997,7 @@ int handle_sys_exit_mount(struct syscall_trace_exit *ctx) { return 0; } -/// sys_enter_fsmount is a struct null_event +/// sys_enter_fsmount is a struct eventfd_event SEC("tracepoint/syscalls/sys_enter_fsmount") int handle_sys_enter_fsmount(struct syscall_trace_enter *ctx) { __u32 pid, tid; @@ -6997,21 +7007,25 @@ int handle_sys_enter_fsmount(struct syscall_trace_enter *ctx) { if (!ior_on_syscall_enter(tid, SYS_ENTER_FSMOUNT)) return 0; - struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0); + struct eventfd_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct eventfd_event), 0); if (!ev) return 0; - ev->event_type = ENTER_NULL_EVENT; + ev->event_type = ENTER_EVENTFD_EVENT; ev->trace_id = SYS_ENTER_FSMOUNT; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + __s32 flags = (__s32)ctx->args[1]; + bpf_map_update_elem(&eventfd_flags_map, &tid, &flags, BPF_ANY); + ev->flags = flags; + ev->ret = -1; bpf_ringbuf_submit(ev, 0); return 0; } -/// sys_exit_fsmount is a struct ret_event (UNCLASSIFIED) +/// sys_exit_fsmount is a struct eventfd_event SEC("tracepoint/syscalls/sys_exit_fsmount") int handle_sys_exit_fsmount(struct syscall_trace_exit *ctx) { __u32 pid, tid; @@ -7021,23 +7035,29 @@ int handle_sys_exit_fsmount(struct syscall_trace_exit *ctx) { if (!ior_on_syscall_exit(tid, SYS_EXIT_FSMOUNT, ctx->ret)) return 0; - struct ret_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct ret_event), 0); + struct eventfd_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct eventfd_event), 0); if (!ev) return 0; - ev->event_type = EXIT_RET_EVENT; + ev->event_type = EXIT_EVENTFD_EVENT; ev->trace_id = SYS_EXIT_FSMOUNT; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + __s32 flags = 0; + __s32 *pending = bpf_map_lookup_elem(&eventfd_flags_map, &tid); + if (pending) { + flags = *pending; + bpf_map_delete_elem(&eventfd_flags_map, &tid); + } + ev->flags = flags; ev->ret = ctx->ret; - ev->ret_type = UNCLASSIFIED; bpf_ringbuf_submit(ev, 0); return 0; } -/// sys_enter_move_mount is a struct null_event +/// sys_enter_move_mount is a struct two_fd_event SEC("tracepoint/syscalls/sys_enter_move_mount") int handle_sys_enter_move_mount(struct syscall_trace_enter *ctx) { __u32 pid, tid; @@ -7047,15 +7067,18 @@ int handle_sys_enter_move_mount(struct syscall_trace_enter *ctx) { if (!ior_on_syscall_enter(tid, SYS_ENTER_MOVE_MOUNT)) return 0; - struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0); + struct two_fd_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct two_fd_event), 0); if (!ev) return 0; - ev->event_type = ENTER_NULL_EVENT; + ev->event_type = ENTER_TWO_FD_EVENT; ev->trace_id = SYS_ENTER_MOVE_MOUNT; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + ev->fd_a = (__s32)ctx->args[0]; + ev->fd_b = (__s32)ctx->args[2]; + ev->extra = (__u64)ctx->args[4]; bpf_ringbuf_submit(ev, 0); return 0; @@ -7087,7 +7110,7 @@ int handle_sys_exit_move_mount(struct syscall_trace_exit *ctx) { return 0; } -/// sys_enter_pivot_root is a struct null_event +/// sys_enter_pivot_root is a struct path_event SEC("tracepoint/syscalls/sys_enter_pivot_root") int handle_sys_enter_pivot_root(struct syscall_trace_enter *ctx) { __u32 pid, tid; @@ -7097,15 +7120,17 @@ int handle_sys_enter_pivot_root(struct syscall_trace_enter *ctx) { if (!ior_on_syscall_enter(tid, SYS_ENTER_PIVOT_ROOT)) return 0; - struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0); + struct path_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct path_event), 0); if (!ev) return 0; - ev->event_type = ENTER_NULL_EVENT; + ev->event_type = ENTER_PATH_EVENT; ev->trace_id = SYS_ENTER_PIVOT_ROOT; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + __builtin_memset(&(ev->pathname), 0, sizeof(ev->pathname)); + bpf_probe_read_user_str(ev->pathname, sizeof(ev->pathname), (void*)ctx->args[0]); bpf_ringbuf_submit(ev, 0); return 0; @@ -11650,7 +11675,7 @@ int handle_sys_exit_get_mempolicy(struct syscall_trace_exit *ctx) { return 0; } -/// sys_enter_swapoff is a struct null_event +/// sys_enter_swapoff is a struct path_event SEC("tracepoint/syscalls/sys_enter_swapoff") int handle_sys_enter_swapoff(struct syscall_trace_enter *ctx) { __u32 pid, tid; @@ -11660,15 +11685,17 @@ int handle_sys_enter_swapoff(struct syscall_trace_enter *ctx) { if (!ior_on_syscall_enter(tid, SYS_ENTER_SWAPOFF)) return 0; - struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0); + struct path_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct path_event), 0); if (!ev) return 0; - ev->event_type = ENTER_NULL_EVENT; + ev->event_type = ENTER_PATH_EVENT; ev->trace_id = SYS_ENTER_SWAPOFF; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + __builtin_memset(&(ev->pathname), 0, sizeof(ev->pathname)); + bpf_probe_read_user_str(ev->pathname, sizeof(ev->pathname), (void*)ctx->args[0]); bpf_ringbuf_submit(ev, 0); return 0; @@ -11700,7 +11727,7 @@ int handle_sys_exit_swapoff(struct syscall_trace_exit *ctx) { return 0; } -/// sys_enter_swapon is a struct null_event +/// sys_enter_swapon is a struct path_event SEC("tracepoint/syscalls/sys_enter_swapon") int handle_sys_enter_swapon(struct syscall_trace_enter *ctx) { __u32 pid, tid; @@ -11710,15 +11737,17 @@ int handle_sys_enter_swapon(struct syscall_trace_enter *ctx) { if (!ior_on_syscall_enter(tid, SYS_ENTER_SWAPON)) return 0; - struct null_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct null_event), 0); + struct path_event *ev = bpf_ringbuf_reserve(&event_map, sizeof(struct path_event), 0); if (!ev) return 0; - ev->event_type = ENTER_NULL_EVENT; + ev->event_type = ENTER_PATH_EVENT; ev->trace_id = SYS_ENTER_SWAPON; ev->pid = pid; ev->tid = tid; ev->time = bpf_ktime_get_boot_ns(); + __builtin_memset(&(ev->pathname), 0, sizeof(ev->pathname)); + bpf_probe_read_user_str(ev->pathname, sizeof(ev->pathname), (void*)ctx->args[0]); bpf_ringbuf_submit(ev, 0); return 0; diff --git a/internal/c/generated_tracepoints_result.txt b/internal/c/generated_tracepoints_result.txt index 6319861..3a5282e 100644 --- a/internal/c/generated_tracepoints_result.txt +++ b/internal/c/generated_tracepoints_result.txt @@ -68,7 +68,7 @@ sys_enter_fork is a struct null_event sys_enter_fremovexattr is a struct fd_event sys_enter_fsconfig is a struct fd_event sys_enter_fsetxattr is a struct fd_event -sys_enter_fsmount is a struct null_event +sys_enter_fsmount is a struct eventfd_event sys_enter_fsopen is a struct null_event sys_enter_fspick is a struct path_event sys_enter_fstatfs is a struct fd_event @@ -170,9 +170,9 @@ sys_enter_mlock2 is a struct null_event sys_enter_mlockall is a struct null_event sys_enter_mmap is a struct fd_event sys_enter_modify_ldt is a struct null_event -sys_enter_mount is a struct null_event +sys_enter_mount is a struct path_event sys_enter_mount_setattr is a struct path_event -sys_enter_move_mount is a struct null_event +sys_enter_move_mount is a struct two_fd_event sys_enter_move_pages is a struct null_event sys_enter_mprotect is a struct null_event sys_enter_mq_getsetattr is a struct null_event @@ -212,7 +212,7 @@ sys_enter_pidfd_open is a struct null_event sys_enter_pidfd_send_signal is a struct null_event sys_enter_pipe is a struct pipe_event sys_enter_pipe2 is a struct pipe_event -sys_enter_pivot_root is a struct null_event +sys_enter_pivot_root is a struct path_event sys_enter_pkey_alloc is a struct null_event sys_enter_pkey_free is a struct null_event sys_enter_pkey_mprotect is a struct null_event @@ -232,7 +232,7 @@ sys_enter_ptrace is a struct null_event sys_enter_pwrite64 is a struct fd_event sys_enter_pwritev is a struct fd_event sys_enter_pwritev2 is a struct fd_event -sys_enter_quotactl is a struct null_event +sys_enter_quotactl is a struct path_event sys_enter_quotactl_fd is a struct fd_event sys_enter_read is a struct fd_event sys_enter_readahead is a struct fd_event @@ -322,8 +322,8 @@ sys_enter_splice is a struct null_event sys_enter_statfs is a struct path_event sys_enter_statmount is a struct null_event sys_enter_statx is a struct path_event -sys_enter_swapoff is a struct null_event -sys_enter_swapon is a struct null_event +sys_enter_swapoff is a struct path_event +sys_enter_swapon is a struct path_event sys_enter_symlink is a struct name_event sys_enter_symlinkat is a struct name_event sys_enter_sync is a struct null_event @@ -347,7 +347,7 @@ sys_enter_times is a struct null_event sys_enter_tkill is a struct null_event sys_enter_truncate is a struct path_event sys_enter_umask is a struct null_event -sys_enter_umount is a struct null_event +sys_enter_umount is a struct path_event sys_enter_unlink is a struct path_event sys_enter_unlinkat is a struct path_event sys_enter_unshare is a struct null_event @@ -355,9 +355,9 @@ sys_enter_uprobe is a struct null_event sys_enter_uretprobe is a struct null_event sys_enter_userfaultfd is a struct null_event sys_enter_ustat is a struct null_event -sys_enter_utime is a struct null_event +sys_enter_utime is a struct path_event sys_enter_utimensat is a struct path_event -sys_enter_utimes is a struct null_event +sys_enter_utimes is a struct path_event sys_enter_vfork is a struct null_event sys_enter_vhangup is a struct null_event sys_enter_vmsplice is a struct fd_event @@ -435,7 +435,7 @@ sys_exit_fork is a struct ret_event (UNCLASSIFIED) sys_exit_fremovexattr is a struct ret_event (UNCLASSIFIED) sys_exit_fsconfig is a struct ret_event (UNCLASSIFIED) sys_exit_fsetxattr is a struct ret_event (UNCLASSIFIED) -sys_exit_fsmount is a struct ret_event (UNCLASSIFIED) +sys_exit_fsmount is a struct eventfd_event sys_exit_fsopen is a struct ret_event (UNCLASSIFIED) sys_exit_fspick is a struct ret_event (UNCLASSIFIED) sys_exit_fstatfs is a struct ret_event (UNCLASSIFIED) diff --git a/internal/c/types.h b/internal/c/types.h index 6c22b90..6b4785e 100644 --- a/internal/c/types.h +++ b/internal/c/types.h @@ -39,6 +39,8 @@ #define EXIT_MEM_EVENT 34 #define ENTER_SLEEP_EVENT 35 #define EXIT_SLEEP_EVENT 36 +#define ENTER_TWO_FD_EVENT 37 +#define EXIT_TWO_FD_EVENT 38 #define UNCLASSIFIED 0 #define READ_CLASSIFIED 1 @@ -232,3 +234,14 @@ struct sleep_event { __u32 tid; __s64 requested_ns; }; + +struct two_fd_event { + __u32 event_type; + __u32 trace_id; + __u64 time; + __u32 pid; + __u32 tid; + __s32 fd_a; + __s32 fd_b; + __u64 extra; +}; diff --git a/internal/event/interface_assertions.go b/internal/event/interface_assertions.go index ebe1d9f..2e1f958 100644 --- a/internal/event/interface_assertions.go +++ b/internal/event/interface_assertions.go @@ -68,4 +68,7 @@ var ( // *types.SleepEvent carries requested sleep duration metadata. _ Event = (*types.SleepEvent)(nil) + + // *types.TwoFdEvent carries operations that include two fd inputs. + _ Event = (*types.TwoFdEvent)(nil) ) diff --git a/internal/eventloop_exit.go b/internal/eventloop_exit.go index 7a69774..faaa9e1 100644 --- a/internal/eventloop_exit.go +++ b/internal/eventloop_exit.go @@ -40,6 +40,8 @@ func (e *eventLoop) handleTracepointExit(ep *event.Pair) bool { return e.handleEpollCtlExit(ep, ev) case *types.PollEvent: return e.handlePollExit(ep, ev) + case *types.TwoFdEvent: + return e.handleTwoFdExit(ep, ev) case *types.MemEvent: return e.handleMemExit(ep, ev) case *types.SleepEvent: @@ -410,6 +412,16 @@ func (e *eventLoop) handlePollExit(ep *event.Pair, pollEv *types.PollEvent) bool return true } +func (e *eventLoop) handleTwoFdExit(ep *event.Pair, twoFdEv *types.TwoFdEvent) bool { + ep.File = e.fdState().resolve(twoFdEv.FdA, twoFdEv.Pid) + ep.Comm = e.comm(twoFdEv.GetTid()) + if !e.Filter().MatchPair(ep) { + ep.Recycle() + return false + } + return true +} + func (e *eventLoop) handleMemExit(ep *event.Pair, memEv *types.MemEvent) bool { ep.Comm = e.comm(memEv.GetTid()) if !e.Filter().MatchPair(ep) { diff --git a/internal/eventloop_mountfs_test.go b/internal/eventloop_mountfs_test.go new file mode 100644 index 0000000..05c11d9 --- /dev/null +++ b/internal/eventloop_mountfs_test.go @@ -0,0 +1,81 @@ +package internal + +import ( + "testing" + + "ior/internal/event" + "ior/internal/file" + "ior/internal/globalfilter" + "ior/internal/types" +) + +func TestHandleTwoFdExitUsesFirstDescriptor(t *testing.T) { + el := mustNewEventLoop(t, eventLoopConfig{}) + el.fdState().set(81, file.NewFd(81, "/proc/self/fd/81", -1)) + + enter := &types.TwoFdEvent{ + EventType: types.ENTER_TWO_FD_EVENT, + TraceId: types.SYS_ENTER_MOVE_MOUNT, + Time: 100, + Pid: 70, + Tid: 71, + FdA: 81, + FdB: 82, + Extra: 0x2, + } + exit := &types.RetEvent{ + EventType: types.EXIT_RET_EVENT, + TraceId: types.SYS_EXIT_MOVE_MOUNT, + Time: 200, + Ret: 0, + Pid: 70, + Tid: 71, + } + ep := &event.Pair{EnterEv: enter, ExitEv: exit} + + if ok := el.handleTwoFdExit(ep, enter); !ok { + t.Fatal("handleTwoFdExit returned false") + } + if ep.File == nil || ep.File.FD() != 81 { + t.Fatalf("expected resolved descriptor 81, got file=%v", ep.File) + } +} + +func TestHandleTwoFdExitAppliesPairFilter(t *testing.T) { + el := mustNewEventLoop(t, eventLoopConfig{ + filter: globalfilter.Filter{ + Syscall: &globalfilter.StringFilter{Pattern: "openat"}, + }, + }) + + enter := &types.TwoFdEvent{ + EventType: types.ENTER_TWO_FD_EVENT, + TraceId: types.SYS_ENTER_MOVE_MOUNT, + Time: 100, + Pid: 72, + Tid: 73, + FdA: 91, + FdB: 92, + Extra: 0, + } + exit := &types.RetEvent{ + EventType: types.EXIT_RET_EVENT, + TraceId: types.SYS_EXIT_MOVE_MOUNT, + Time: 200, + Ret: 0, + Pid: 72, + Tid: 73, + } + ep := &event.Pair{EnterEv: enter, ExitEv: exit} + + if ok := el.handleTwoFdExit(ep, enter); ok { + t.Fatal("handleTwoFdExit should reject pair due to filter mismatch") + } +} + +func TestInitRawHandlersRegistersTwoFdEvent(t *testing.T) { + el := mustNewEventLoop(t, eventLoopConfig{}) + if _, ok := el.rawHandlers[types.ENTER_TWO_FD_EVENT]; !ok { + t.Fatal("ENTER_TWO_FD_EVENT handler is not registered") + } +} diff --git a/internal/eventloop_runtime.go b/internal/eventloop_runtime.go index 8ef3abf..9a818e3 100644 --- a/internal/eventloop_runtime.go +++ b/internal/eventloop_runtime.go @@ -247,6 +247,7 @@ func (e *eventLoop) initRawHandlers() { e.registerSocketHandlers() e.registerIPCHandlers() e.registerPollingHandlers() + e.registerTwoFdHandlers() e.registerMemoryHandlers() e.registerSleepHandlers() } @@ -451,6 +452,16 @@ func (e *eventLoop) registerPollingHandlers() { } } +func (e *eventLoop) registerTwoFdHandlers() { + e.rawHandlers[types.ENTER_TWO_FD_EVENT] = func(raw []byte, _ chan<- *event.Pair) { + twoFdEv, ok := decodeRawEvent(e, types.ENTER_TWO_FD_EVENT, raw, types.NewTwoFdEventFast) + if !ok { + return + } + e.tracepointEntered(twoFdEv) + } +} + func (e *eventLoop) registerMemoryHandlers() { e.rawHandlers[types.ENTER_MEM_EVENT] = func(raw []byte, _ chan<- *event.Pair) { memEv, ok := decodeRawEvent(e, types.ENTER_MEM_EVENT, raw, types.NewMemEventFast) diff --git a/internal/generate/bpfhandler.go b/internal/generate/bpfhandler.go index 5c42464..afdb83e 100644 --- a/internal/generate/bpfhandler.go +++ b/internal/generate/bpfhandler.go @@ -93,6 +93,8 @@ func generateExtra(tp GeneratedTracepoint, isEnter bool) string { return generateExtraEventfd(f, isEnter) case KindEpollCtl: return generateExtraEpollCtl() + case KindTwoFd: + return generateExtraTwoFd(f.Name) case KindPoll: return generateExtraPoll(f.Name) case KindMem: @@ -207,7 +209,12 @@ func generateExtraPipe(f *Format, isEnter bool) string { func generateExtraEventfd(f *Format, isEnter bool) string { if isEnter { flagsExpr := "0" - if f.Name == "sys_enter_eventfd2" { + switch f.Name { + case "sys_enter_eventfd2": + flagsExpr = "(__s32)ctx->args[1]" + case "sys_enter_fsmount": + flagsExpr = "(__s32)ctx->args[1]" + case "sys_enter_fsopen": flagsExpr = "(__s32)ctx->args[1]" } return " __s32 flags = " + flagsExpr + ";\n bpf_map_update_elem(&eventfd_flags_map, &tid, &flags, BPF_ANY);\n ev->flags = flags;\n ev->ret = -1;\n" @@ -219,6 +226,15 @@ func generateExtraEpollCtl() string { return " ev->epfd = (__s32)ctx->args[0];\n ev->op = (__s32)ctx->args[1];\n ev->fd = (__s32)ctx->args[2];\n ev->events = 0;\n if (ctx->args[3] != 0) {\n __u32 user_events = 0;\n if (bpf_probe_read_user(&user_events, sizeof(user_events), (void *)ctx->args[3]) == 0) {\n ev->events = user_events;\n }\n }\n" } +func generateExtraTwoFd(name string) string { + switch name { + case "sys_enter_move_mount": + return " ev->fd_a = (__s32)ctx->args[0];\n ev->fd_b = (__s32)ctx->args[2];\n ev->extra = (__u64)ctx->args[4];\n" + default: + return " ev->fd_a = (__s32)ctx->args[0];\n ev->fd_b = (__s32)ctx->args[1];\n ev->extra = (__u64)ctx->args[2];\n" + } +} + func generateExtraPoll(name string) string { switch name { case "sys_enter_poll": diff --git a/internal/generate/classify.go b/internal/generate/classify.go index 2bb2b81..2b750cf 100644 --- a/internal/generate/classify.go +++ b/internal/generate/classify.go @@ -21,6 +21,7 @@ const ( KindPipe KindEventfd KindEpollCtl + KindTwoFd KindPoll KindMem KindSleep @@ -142,6 +143,18 @@ func classifyNameOnly(name string) (ClassificationResult, bool) { return ClassificationResult{Kind: KindFd}, true case "sys_enter_epoll_ctl": return ClassificationResult{Kind: KindEpollCtl}, true + case "sys_enter_move_mount": + return ClassificationResult{Kind: KindTwoFd}, true + case "sys_enter_fsmount": + return ClassificationResult{Kind: KindEventfd}, true + case "sys_exit_fsmount": + return ClassificationResult{Kind: KindEventfd}, true + case "sys_enter_statmount": + return ClassificationResult{Kind: KindNull}, true + case "sys_enter_listmount": + return ClassificationResult{Kind: KindNull}, true + case "sys_enter_listns": + return ClassificationResult{Kind: KindNull}, true case "sys_enter_poll": return ClassificationResult{Kind: KindPoll}, true case "sys_enter_ppoll": @@ -182,18 +195,42 @@ func classifyNameAndField(name, fieldType, fieldName string) (ClassificationResu return ClassificationResult{Kind: KindDup3}, true } case "sys_enter_name_to_handle_at": - if fieldType == "const char *" && fieldName == "name" { + if isCStringPtrType(fieldType) && fieldName == "name" { return ClassificationResult{Kind: KindPathname, PathnameField: "name"}, true } case "sys_enter_copy_file_range": if isFdType(fieldType) && fieldName == "fd_in" { return ClassificationResult{Kind: KindFd}, true } + case "sys_enter_mount": + if isCStringPtrType(fieldType) && fieldName == "dir_name" { + return ClassificationResult{Kind: KindPathname, PathnameField: "dir_name"}, true + } + case "sys_enter_umount": + if isCStringPtrType(fieldType) && fieldName == "name" { + return ClassificationResult{Kind: KindPathname, PathnameField: "name"}, true + } + case "sys_enter_pivot_root": + if isCStringPtrType(fieldType) && fieldName == "new_root" { + return ClassificationResult{Kind: KindPathname, PathnameField: "new_root"}, true + } + case "sys_enter_quotactl": + if isCStringPtrType(fieldType) && fieldName == "special" { + return ClassificationResult{Kind: KindPathname, PathnameField: "special"}, true + } + case "sys_enter_swapon": + if isCStringPtrType(fieldType) && fieldName == "specialfile" { + return ClassificationResult{Kind: KindPathname, PathnameField: "specialfile"}, true + } + case "sys_enter_swapoff": + if isCStringPtrType(fieldType) && fieldName == "specialfile" { + return ClassificationResult{Kind: KindPathname, PathnameField: "specialfile"}, true + } } if strings.HasPrefix(name, "sys_enter") && strings.Contains(name, "open") && - fieldType == "const char *" && fieldName == "filename" { + isCStringPtrType(fieldType) && fieldName == "filename" { return ClassificationResult{Kind: KindOpen}, true } @@ -204,13 +241,13 @@ func classifyByField(fieldType, fieldName string) (ClassificationResult, bool) { switch { case fieldName == "fd" && isFdType(fieldType): return ClassificationResult{Kind: KindFd}, true - case fieldType == "const char *" && fieldName == "newname": + case isCStringPtrType(fieldType) && fieldName == "newname": return ClassificationResult{Kind: KindName}, true - case fieldType == "const char *" && fieldName == "pathname": + case isCStringPtrType(fieldType) && fieldName == "pathname": return ClassificationResult{Kind: KindPathname, PathnameField: "pathname"}, true - case fieldType == "const char *" && fieldName == "path": + case isCStringPtrType(fieldType) && fieldName == "path": return ClassificationResult{Kind: KindPathname, PathnameField: "path"}, true - case fieldType == "const char *" && fieldName == "filename": + case isCStringPtrType(fieldType) && fieldName == "filename": return ClassificationResult{Kind: KindPathname, PathnameField: "filename"}, true case fieldType == "long" && fieldName == "ret": return ClassificationResult{Kind: KindRet}, true @@ -222,6 +259,10 @@ func isFdType(t string) bool { return t == "unsigned int" || t == "unsigned long" || t == "int" } +func isCStringPtrType(t string) bool { + return t == "const char *" || t == "char *" +} + // ClassifyRet returns the RetClassification for a syscall exit name. func ClassifyRet(name string) RetClassification { syscall := strings.ToLower(strings.TrimPrefix(name, "sys_exit_")) diff --git a/internal/generate/classify_test.go b/internal/generate/classify_test.go index daf008a..b853994 100644 --- a/internal/generate/classify_test.go +++ b/internal/generate/classify_test.go @@ -453,6 +453,108 @@ func TestClassifyClockNanosleep(t *testing.T) { } } +func TestClassifyMount(t *testing.T) { + r := classifyFromData(t, FormatMount) + if r.Kind != KindPathname { + t.Errorf("mount: got kind %d, want KindPathname", r.Kind) + } + if r.PathnameField != "dir_name" { + t.Errorf("mount: PathnameField = %q, want dir_name", r.PathnameField) + } +} + +func TestClassifyUmount(t *testing.T) { + r := classifyFromData(t, FormatUmount) + if r.Kind != KindPathname { + t.Errorf("umount: got kind %d, want KindPathname", r.Kind) + } + if r.PathnameField != "name" { + t.Errorf("umount: PathnameField = %q, want name", r.PathnameField) + } +} + +func TestClassifyMoveMount(t *testing.T) { + r := classifyFromData(t, FormatMoveMount) + if r.Kind != KindTwoFd { + t.Errorf("move_mount: got kind %d, want KindTwoFd", r.Kind) + } +} + +func TestClassifyFsmount(t *testing.T) { + r := classifyFromData(t, FormatFsmount) + if r.Kind != KindEventfd { + t.Errorf("fsmount: got kind %d, want KindEventfd", r.Kind) + } +} + +func TestClassifyExitFsmount(t *testing.T) { + r := classifyFromData(t, FormatExitFsmount) + if r.Kind != KindEventfd { + t.Errorf("exit_fsmount: got kind %d, want KindEventfd", r.Kind) + } +} + +func TestClassifyPivotRoot(t *testing.T) { + r := classifyFromData(t, FormatPivotRoot) + if r.Kind != KindPathname { + t.Errorf("pivot_root: got kind %d, want KindPathname", r.Kind) + } + if r.PathnameField != "new_root" { + t.Errorf("pivot_root: PathnameField = %q, want new_root", r.PathnameField) + } +} + +func TestClassifyQuotactl(t *testing.T) { + r := classifyFromData(t, FormatQuotactl) + if r.Kind != KindPathname { + t.Errorf("quotactl: got kind %d, want KindPathname", r.Kind) + } + if r.PathnameField != "special" { + t.Errorf("quotactl: PathnameField = %q, want special", r.PathnameField) + } +} + +func TestClassifyStatmount(t *testing.T) { + r := classifyFromData(t, FormatStatmount) + if r.Kind != KindNull { + t.Errorf("statmount: got kind %d, want KindNull", r.Kind) + } +} + +func TestClassifyListmount(t *testing.T) { + r := classifyFromData(t, FormatListmount) + if r.Kind != KindNull { + t.Errorf("listmount: got kind %d, want KindNull", r.Kind) + } +} + +func TestClassifyListns(t *testing.T) { + r := classifyFromData(t, FormatListns) + if r.Kind != KindNull { + t.Errorf("listns: got kind %d, want KindNull", r.Kind) + } +} + +func TestClassifySwapon(t *testing.T) { + r := classifyFromData(t, FormatSwapon) + if r.Kind != KindPathname { + t.Errorf("swapon: got kind %d, want KindPathname", r.Kind) + } + if r.PathnameField != "specialfile" { + t.Errorf("swapon: PathnameField = %q, want specialfile", r.PathnameField) + } +} + +func TestClassifySwapoff( |
