summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-20 15:06:02 +0300
committerPaul Buetow <paul@buetow.org>2026-05-20 15:06:02 +0300
commit271af607921ceabc640271c475a66e45b9460d3f (patch)
tree6ae443fd372dbeea947cba7bd5851f7936f354b5
parent63184df8d5e30f70011a97d862103fa38d797bb3 (diff)
feat: add mount/fs management syscall tracing for c7
-rw-r--r--cmd/ioworkload/scenario_mountfs.go91
-rw-r--r--cmd/ioworkload/scenario_mountfs_test.go30
-rw-r--r--cmd/ioworkload/scenarios.go1
-rw-r--r--integrationtests/mountfs_test.go19
-rw-r--r--internal/c/generated_tracepoints.c97
-rw-r--r--internal/c/generated_tracepoints_result.txt22
-rw-r--r--internal/c/types.h13
-rw-r--r--internal/event/interface_assertions.go3
-rw-r--r--internal/eventloop_exit.go12
-rw-r--r--internal/eventloop_mountfs_test.go81
-rw-r--r--internal/eventloop_runtime.go11
-rw-r--r--internal/generate/bpfhandler.go18
-rw-r--r--internal/generate/classify.go53
-rw-r--r--internal/generate/classify_test.go123
-rw-r--r--internal/generate/codegen_test.go25
-rw-r--r--internal/generate/family.go8
-rw-r--r--internal/generate/kindregistry.go1
-rw-r--r--internal/generate/testdata.go333
-rw-r--r--internal/types/fastdecode.go20
-rw-r--r--internal/types/fastdecode_test.go43
-rw-r--r--internal/types/generated_types.go74
-rw-r--r--internal/types/types_test.go27
22 files changed, 1048 insertions, 57 deletions
diff --git a/cmd/ioworkload/scenario_mountfs.go b/cmd/ioworkload/scenario_mountfs.go
new file mode 100644
index 0000000..4c48ded
--- /dev/null
+++ b/cmd/ioworkload/scenario_mountfs.go
@@ -0,0 +1,91 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "runtime"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+type mountIDReq struct {
+ Size uint32
+ Pad uint32
+ MntID uint64
+ Param uint64
+}
+
+func mountfsManagement() error {
+ dir, cleanup, err := makeTempDir("mountfs-management")
+ if err != nil {
+ return err
+ }
+ defer cleanup()
+
+ mountPoint := filepath.Join(dir, "mnt")
+ if err := os.Mkdir(mountPoint, 0o755); err != nil {
+ return fmt.Errorf("mkdir mountpoint: %w", err)
+ }
+
+ swapFile := filepath.Join(dir, "swapfile")
+ if err := os.WriteFile(swapFile, []byte("swap"), 0o600); err != nil {
+ return fmt.Errorf("write swap file: %w", err)
+ }
+
+ mountPath := mustCStringPtr(mountPoint)
+ swapPath := mustCStringPtr(swapFile)
+ newRoot := mustCStringPtr(mountPoint)
+ putOld := mustCStringPtr(dir)
+ tmpfs := mustCStringPtr("tmpfs")
+ none := mustCStringPtr("none")
+ atFDCWDInt := int64(unix.AT_FDCWD)
+ atFDCWD := uintptr(atFDCWDInt)
+
+ // Best-effort coverage: these calls are expected to fail on most hosts
+ // without CAP_SYS_ADMIN, but still exercise syscall tracing paths.
+ _, _, _ = syscall.RawSyscall6(unix.SYS_MOUNT, uintptr(unsafe.Pointer(none)), uintptr(unsafe.Pointer(mountPath)), uintptr(unsafe.Pointer(tmpfs)), 0, 0, 0)
+ _, _, _ = syscall.RawSyscall(unix.SYS_UMOUNT2, uintptr(unsafe.Pointer(mountPath)), 0, 0)
+ _, _, _ = syscall.RawSyscall(unix.SYS_UMOUNT2, uintptr(unsafe.Pointer(mountPath)), uintptr(unix.MNT_DETACH), 0)
+ _, _, _ = syscall.RawSyscall6(unix.SYS_MOVE_MOUNT, atFDCWD, uintptr(unsafe.Pointer(mountPath)), atFDCWD, uintptr(unsafe.Pointer(mountPath)), 0, 0)
+ _, _, _ = syscall.RawSyscall(unix.SYS_FSMOUNT, ^uintptr(0), 0, 0)
+ _, _, _ = syscall.RawSyscall(unix.SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(newRoot)), uintptr(unsafe.Pointer(putOld)), 0)
+ _, _, _ = syscall.RawSyscall6(unix.SYS_QUOTACTL, 0, uintptr(unsafe.Pointer(mountPath)), 0, 0, 0, 0)
+ _, _, _ = syscall.RawSyscall(unix.SYS_SWAPON, uintptr(unsafe.Pointer(swapPath)), 0, 0)
+ _, _, _ = syscall.RawSyscall(unix.SYS_SWAPOFF, uintptr(unsafe.Pointer(swapPath)), 0, 0)
+
+ req := mountIDReq{Size: uint32(unsafe.Sizeof(mountIDReq{}))}
+ var statBuf [256]byte
+ _, _, _ = syscall.RawSyscall6(unix.SYS_STATMOUNT, uintptr(unsafe.Pointer(&req)), uintptr(unsafe.Pointer(&statBuf[0])), uintptr(len(statBuf)), 0, 0, 0)
+
+ var mountIDs [8]uint64
+ _, _, _ = syscall.RawSyscall6(unix.SYS_LISTMOUNT, uintptr(unsafe.Pointer(&req)), uintptr(unsafe.Pointer(&mountIDs[0])), uintptr(len(mountIDs)), 0, 0, 0)
+
+ if nr, err := listnsSyscallNr(); err == nil {
+ var nsIDs [8]uint64
+ _, _, _ = syscall.RawSyscall6(nr, uintptr(unsafe.Pointer(&req)), uintptr(unsafe.Pointer(&nsIDs[0])), uintptr(len(nsIDs)), 0, 0, 0)
+ }
+
+ return nil
+}
+
+func listnsSyscallNr() (uintptr, error) {
+ return listnsSyscallNrForArch(runtime.GOARCH)
+}
+
+func listnsSyscallNrForArch(arch string) (uintptr, error) {
+ // __NR_listns was introduced from asm-generic numbering where amd64/arm64 use 470.
+ switch arch {
+ case "amd64", "arm64":
+ return 470, nil
+ default:
+ return 0, fmt.Errorf("listns syscall number not defined for GOARCH=%s", arch)
+ }
+}
+
+func mustCStringPtr(s string) *byte {
+ p, _ := unix.BytePtrFromString(s)
+ return p
+}
diff --git a/cmd/ioworkload/scenario_mountfs_test.go b/cmd/ioworkload/scenario_mountfs_test.go
new file mode 100644
index 0000000..c1c317a
--- /dev/null
+++ b/cmd/ioworkload/scenario_mountfs_test.go
@@ -0,0 +1,30 @@
+package main
+
+import "testing"
+
+func TestListnsSyscallNrForArch(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ arch string
+ want uintptr
+ wantErr bool
+ }{
+ {name: "amd64", arch: "amd64", want: 470},
+ {name: "arm64", arch: "arm64", want: 470},
+ {name: "unsupported", arch: "riscv64", wantErr: true},
+ } {
+ got, err := listnsSyscallNrForArch(tc.arch)
+ if tc.wantErr {
+ if err == nil {
+ t.Fatalf("%s: expected error", tc.name)
+ }
+ continue
+ }
+ if err != nil {
+ t.Fatalf("%s: unexpected error: %v", tc.name, err)
+ }
+ if got != tc.want {
+ t.Fatalf("%s: got %d, want %d", tc.name, got, tc.want)
+ }
+ }
+}
diff --git a/cmd/ioworkload/scenarios.go b/cmd/ioworkload/scenarios.go
index e0827a5..79d4e6d 100644
--- a/cmd/ioworkload/scenarios.go
+++ b/cmd/ioworkload/scenarios.go
@@ -34,6 +34,7 @@ var scenarios = map[string]func() error{
"pipe2-basic": pipe2Basic,
"eventfd-basic": eventfdBasic,
"eventfd2-basic": eventfd2Basic,
+ "mountfs-management": mountfsManagement,
"polling-epoll": pollingEpoll,
"sleep-syscalls": sleepSyscalls,
"family-mixed": familyMixed,
diff --git a/integrationtests/mountfs_test.go b/integrationtests/mountfs_test.go
new file mode 100644
index 0000000..77f0009
--- /dev/null
+++ b/integrationtests/mountfs_test.go
@@ -0,0 +1,19 @@
+package integrationtests
+
+import "testing"
+
+func TestMountFsManagementSyscalls(t *testing.T) {
+ runScenario(t, "mountfs-management", []ExpectedEvent{
+ {Tracepoint: "enter_mount", MinCount: 1},
+ {Tracepoint: "enter_umount", MinCount: 1},
+ {Tracepoint: "enter_move_mount", MinCount: 1},
+ {Tracepoint: "enter_fsmount", MinCount: 1},
+ {Tracepoint: "enter_pivot_root", MinCount: 1},
+ {Tracepoint: "enter_quotactl", MinCount: 1},
+ {Tracepoint: "enter_statmount", MinCount: 1},
+ {Tracepoint: "enter_listmount", MinCount: 1},
+ {Tracepoint: "enter_listns", MinCount: 1},
+ {Tracepoint: "enter_swapon", MinCount: 1},
+ {Tracepoint: "enter_swapoff", MinCount: 1},
+ })
+}
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_