summaryrefslogtreecommitdiff
path: root/internal/tracepoints
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-21 08:16:08 +0300
committerPaul Buetow <paul@buetow.org>2026-05-21 08:16:08 +0300
commitbe8735fe701f7398c19c17c394f4827614eab875 (patch)
treeaba59890563edb6e03f2eb82fee5d89b49fa2c81 /internal/tracepoints
parent3a5706f21d30258577a5934efb93c400dad723db (diff)
p7 add attach-time trace dimension gating
Diffstat (limited to 'internal/tracepoints')
-rw-r--r--internal/tracepoints/dimension_selector.go219
-rw-r--r--internal/tracepoints/dimension_selector_test.go147
-rw-r--r--internal/tracepoints/generated_tracepoints.go740
-rw-r--r--internal/tracepoints/selector.go46
-rw-r--r--internal/tracepoints/selector_test.go14
5 files changed, 1162 insertions, 4 deletions
diff --git a/internal/tracepoints/dimension_selector.go b/internal/tracepoints/dimension_selector.go
new file mode 100644
index 0000000..22a70fb
--- /dev/null
+++ b/internal/tracepoints/dimension_selector.go
@@ -0,0 +1,219 @@
+package tracepoints
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "ior/internal/types"
+)
+
+// DimensionSelectorConfig holds attach-time syscall-dimension selection inputs.
+// Each field accepts comma-separated values.
+type DimensionSelectorConfig struct {
+ TraceFamilies string
+ TraceKinds string
+ TraceSyscalls string
+ NoTraceFamilies string
+ NoTraceKinds string
+ NoTraceSyscalls string
+}
+
+// ParseSelectorWithDimensions compiles regex-based attach/exclude filters and
+// applies attach-time syscall dimension gating.
+func ParseSelectorWithDimensions(attach, exclude string, dims DimensionSelectorConfig) (Selector, error) {
+ sel, err := ParseSelector(attach, exclude)
+ if err != nil {
+ return Selector{}, err
+ }
+
+ allow, err := buildAllowedSyscalls(dims)
+ if err != nil {
+ return Selector{}, err
+ }
+ sel.RestrictSyscalls = true
+ sel.Syscalls = allow
+ return sel, nil
+}
+
+func buildAllowedSyscalls(dims DimensionSelectorConfig) (map[string]struct{}, error) {
+ knownSyscalls := allKnownSyscalls()
+ knownKinds := allKnownKinds()
+
+ includeFamilies, familyFilterProvided, err := parseFamiliesCSV(dims.TraceFamilies)
+ if err != nil {
+ return nil, err
+ }
+ includeKinds, kindFilterProvided, err := parseKindsCSV(dims.TraceKinds, knownKinds)
+ if err != nil {
+ return nil, err
+ }
+ includeSyscalls, syscallFilterProvided, err := parseSyscallsCSV(dims.TraceSyscalls, knownSyscalls)
+ if err != nil {
+ return nil, err
+ }
+
+ allow := make(map[string]struct{})
+ hasPositive := familyFilterProvided || kindFilterProvided || syscallFilterProvided
+ if hasPositive {
+ for syscall, family := range syscallFamilies {
+ if _, ok := includeFamilies[family]; ok {
+ allow[syscall] = struct{}{}
+ }
+ }
+ for syscall, kind := range syscallKinds {
+ if _, ok := includeKinds[kind]; ok {
+ allow[syscall] = struct{}{}
+ }
+ }
+ for syscall := range includeSyscalls {
+ allow[syscall] = struct{}{}
+ }
+ } else {
+ // Backward compatibility default: keep existing file-I/O coverage on and
+ // leave newly-expanded non-IO families disabled unless explicitly opted in.
+ for syscall, family := range syscallFamilies {
+ if family == string(types.FamilyFS) {
+ allow[syscall] = struct{}{}
+ }
+ }
+ }
+
+ excludeFamilies, _, err := parseFamiliesCSV(dims.NoTraceFamilies)
+ if err != nil {
+ return nil, err
+ }
+ excludeKinds, _, err := parseKindsCSV(dims.NoTraceKinds, knownKinds)
+ if err != nil {
+ return nil, err
+ }
+ excludeSyscalls, _, err := parseSyscallsCSV(dims.NoTraceSyscalls, knownSyscalls)
+ if err != nil {
+ return nil, err
+ }
+
+ for syscall := range allow {
+ if _, ok := excludeSyscalls[syscall]; ok {
+ delete(allow, syscall)
+ continue
+ }
+ if family, ok := syscallFamilies[syscall]; ok {
+ if _, excluded := excludeFamilies[family]; excluded {
+ delete(allow, syscall)
+ continue
+ }
+ }
+ if kind, ok := syscallKinds[syscall]; ok {
+ if _, excluded := excludeKinds[kind]; excluded {
+ delete(allow, syscall)
+ }
+ }
+ }
+
+ return allow, nil
+}
+
+func parseFamiliesCSV(raw string) (map[string]struct{}, bool, error) {
+ values, provided := splitCSV(raw)
+ if !provided {
+ return map[string]struct{}{}, false, nil
+ }
+ out := make(map[string]struct{}, len(values))
+ for _, value := range values {
+ family, ok := types.ParseSyscallFamily(value)
+ if !ok {
+ return nil, false, fmt.Errorf("invalid syscall family in trace selector: %q", value)
+ }
+ out[string(family)] = struct{}{}
+ }
+ return out, true, nil
+}
+
+func parseKindsCSV(raw string, knownKinds map[string]struct{}) (map[string]struct{}, bool, error) {
+ values, provided := splitCSV(raw)
+ if !provided {
+ return map[string]struct{}{}, false, nil
+ }
+ out := make(map[string]struct{}, len(values))
+ for _, value := range values {
+ kind := normalizeKind(value)
+ if _, ok := knownKinds[kind]; !ok {
+ return nil, false, fmt.Errorf("invalid syscall kind in trace selector: %q", value)
+ }
+ out[kind] = struct{}{}
+ }
+ return out, true, nil
+}
+
+func parseSyscallsCSV(raw string, knownSyscalls map[string]struct{}) (map[string]struct{}, bool, error) {
+ values, provided := splitCSV(raw)
+ if !provided {
+ return map[string]struct{}{}, false, nil
+ }
+ out := make(map[string]struct{}, len(values))
+ for _, value := range values {
+ syscall := strings.ToLower(strings.TrimSpace(value))
+ if _, ok := knownSyscalls[syscall]; !ok {
+ return nil, false, fmt.Errorf("invalid syscall in trace selector: %q", value)
+ }
+ out[syscall] = struct{}{}
+ }
+ return out, true, nil
+}
+
+func splitCSV(raw string) ([]string, bool) {
+ raw = strings.TrimSpace(raw)
+ if raw == "" {
+ return nil, false
+ }
+ parts := strings.Split(raw, ",")
+ values := make([]string, 0, len(parts))
+ for _, part := range parts {
+ part = strings.TrimSpace(part)
+ if part == "" {
+ continue
+ }
+ values = append(values, part)
+ }
+ if len(values) == 0 {
+ return nil, false
+ }
+ return values, true
+}
+
+func normalizeKind(raw string) string {
+ normalized := strings.ToLower(strings.TrimSpace(raw))
+ normalized = strings.ReplaceAll(normalized, "_", "-")
+ return normalized
+}
+
+func allKnownSyscalls() map[string]struct{} {
+ out := make(map[string]struct{}, len(syscallFamilies))
+ for syscall := range syscallFamilies {
+ out[syscall] = struct{}{}
+ }
+ return out
+}
+
+func allKnownKinds() map[string]struct{} {
+ out := make(map[string]struct{})
+ for _, kind := range syscallKinds {
+ if kind == "" {
+ continue
+ }
+ out[kind] = struct{}{}
+ }
+ return out
+}
+
+// KnownKinds returns the sorted, normalized attach-time kind names accepted by
+// -trace-kinds and -no-trace-kinds.
+func KnownKinds() []string {
+ kindSet := allKnownKinds()
+ kinds := make([]string, 0, len(kindSet))
+ for kind := range kindSet {
+ kinds = append(kinds, kind)
+ }
+ sort.Strings(kinds)
+ return kinds
+}
diff --git a/internal/tracepoints/dimension_selector_test.go b/internal/tracepoints/dimension_selector_test.go
new file mode 100644
index 0000000..cd7b0f8
--- /dev/null
+++ b/internal/tracepoints/dimension_selector_test.go
@@ -0,0 +1,147 @@
+package tracepoints
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestParseSelectorWithDimensionsDefaultFSOnly(t *testing.T) {
+ sel, err := ParseSelectorWithDimensions("", "", DimensionSelectorConfig{})
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if !sel.ShouldAttach("sys_enter_openat") {
+ t.Fatal("expected FS syscall openat to be attached by default")
+ }
+ if sel.ShouldAttach("sys_enter_nanosleep") {
+ t.Fatal("expected non-FS syscall nanosleep to be excluded by default")
+ }
+}
+
+func TestParseSelectorWithDimensionsFamilyOnly(t *testing.T) {
+ sel, err := ParseSelectorWithDimensions("", "", DimensionSelectorConfig{
+ TraceFamilies: "Time",
+ })
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if !sel.ShouldAttach("sys_enter_nanosleep") {
+ t.Fatal("expected nanosleep to be attached when Time family is enabled")
+ }
+ if sel.ShouldAttach("sys_enter_openat") {
+ t.Fatal("expected openat to be excluded when only Time family is enabled")
+ }
+}
+
+func TestParseSelectorWithDimensionsKindOnly(t *testing.T) {
+ sel, err := ParseSelectorWithDimensions("", "", DimensionSelectorConfig{
+ TraceKinds: "sleep",
+ })
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if !sel.ShouldAttach("sys_enter_nanosleep") {
+ t.Fatal("expected nanosleep to be attached for sleep kind")
+ }
+ if sel.ShouldAttach("sys_enter_openat") {
+ t.Fatal("expected openat to be excluded when only sleep kind is enabled")
+ }
+}
+
+func TestParseSelectorWithDimensionsSyscallOnly(t *testing.T) {
+ sel, err := ParseSelectorWithDimensions("", "", DimensionSelectorConfig{
+ TraceSyscalls: "openat",
+ })
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if !sel.ShouldAttach("sys_enter_openat") || !sel.ShouldAttach("sys_exit_openat") {
+ t.Fatal("expected both openat enter/exit tracepoints to be attached")
+ }
+ if sel.ShouldAttach("sys_enter_write") {
+ t.Fatal("expected write to be excluded when only openat is selected")
+ }
+}
+
+func TestParseSelectorWithDimensionsUnionSemantics(t *testing.T) {
+ sel, err := ParseSelectorWithDimensions("", "", DimensionSelectorConfig{
+ TraceFamilies: "Time",
+ TraceSyscalls: "openat",
+ })
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if !sel.ShouldAttach("sys_enter_openat") {
+ t.Fatal("expected openat from syscall selector")
+ }
+ if !sel.ShouldAttach("sys_enter_nanosleep") {
+ t.Fatal("expected nanosleep from family selector")
+ }
+}
+
+func TestParseSelectorWithDimensionsExclusionsOverridePositives(t *testing.T) {
+ sel, err := ParseSelectorWithDimensions("", "", DimensionSelectorConfig{
+ TraceFamilies: "FS",
+ NoTraceSyscalls: "openat",
+ })
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if sel.ShouldAttach("sys_enter_openat") {
+ t.Fatal("expected openat to be excluded by -no-trace-syscalls")
+ }
+ if !sel.ShouldAttach("sys_enter_read") {
+ t.Fatal("expected other FS syscall (read) to remain attached")
+ }
+}
+
+func TestParseSelectorWithDimensionsRegexStillApplies(t *testing.T) {
+ sel, err := ParseSelectorWithDimensions("^sys_enter_openat$,^sys_exit_openat$", "", DimensionSelectorConfig{
+ TraceFamilies: "FS",
+ })
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if !sel.ShouldAttach("sys_enter_openat") {
+ t.Fatal("expected openat to pass regex+dimension filters")
+ }
+ if sel.ShouldAttach("sys_enter_read") {
+ t.Fatal("expected read to fail regex attach filters")
+ }
+}
+
+func TestParseSelectorWithDimensionsRejectsInvalidFamily(t *testing.T) {
+ _, err := ParseSelectorWithDimensions("", "", DimensionSelectorConfig{
+ TraceFamilies: "Nope",
+ })
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if !strings.Contains(err.Error(), "invalid syscall family") {
+ t.Fatalf("unexpected error: %v", err)
+ }
+}
+
+func TestParseSelectorWithDimensionsRejectsInvalidKind(t *testing.T) {
+ _, err := ParseSelectorWithDimensions("", "", DimensionSelectorConfig{
+ TraceKinds: "not-a-kind",
+ })
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if !strings.Contains(err.Error(), "invalid syscall kind") {
+ t.Fatalf("unexpected error: %v", err)
+ }
+}
+
+func TestParseSelectorWithDimensionsRejectsInvalidSyscall(t *testing.T) {
+ _, err := ParseSelectorWithDimensions("", "", DimensionSelectorConfig{
+ TraceSyscalls: "not_a_syscall",
+ })
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if !strings.Contains(err.Error(), "invalid syscall in trace selector") {
+ t.Fatalf("unexpected error: %v", err)
+ }
+}
diff --git a/internal/tracepoints/generated_tracepoints.go b/internal/tracepoints/generated_tracepoints.go
index 8277cbf..11913c8 100644
--- a/internal/tracepoints/generated_tracepoints.go
+++ b/internal/tracepoints/generated_tracepoints.go
@@ -737,3 +737,743 @@ var List = []string{
"sys_enter_rt_sigreturn",
"sys_exit_rt_sigreturn",
}
+
+var syscallFamilies = map[string]string{
+ "accept": "Network",
+ "accept4": "Network",
+ "access": "FS",
+ "acct": "Misc",
+ "add_key": "Security",
+ "adjtimex": "Misc",
+ "alarm": "Misc",
+ "arch_prctl": "Process",
+ "bind": "Network",
+ "bpf": "Security",
+ "brk": "Memory",
+ "cachestat": "FS",
+ "capget": "Security",
+ "capset": "Security",
+ "chdir": "FS",
+ "chmod": "FS",
+ "chown": "FS",
+ "chroot": "FS",
+ "clock_adjtime": "Time",
+ "clock_getres": "Time",
+ "clock_gettime": "Time",
+ "clock_nanosleep": "Time",
+ "clock_settime": "Time",
+ "clone": "Process",
+ "clone3": "Process",
+ "close": "FS",
+ "close_range": "FS",
+ "connect": "Network",
+ "copy_file_range": "FS",
+ "creat": "FS",
+ "delete_module": "Security",
+ "dup": "FS",
+ "dup2": "FS",
+ "dup3": "FS",
+ "epoll_create": "Polling",
+ "epoll_create1": "Polling",
+ "epoll_ctl": "Polling",
+ "epoll_pwait": "Polling",
+ "epoll_pwait2": "Polling",
+ "epoll_wait": "Polling",
+ "eventfd": "IPC",
+ "eventfd2": "IPC",
+ "execve": "Process",
+ "execveat": "Process",
+ "exit": "Process",
+ "exit_group": "Process",
+ "faccessat": "FS",
+ "faccessat2": "FS",
+ "fadvise64": "FS",
+ "fallocate": "FS",
+ "fanotify_init": "Misc",
+ "fanotify_mark": "Misc",
+ "fchdir": "FS",
+ "fchmod": "FS",
+ "fchmodat": "FS",
+ "fchmodat2": "FS",
+ "fchown": "FS",
+ "fchownat": "FS",
+ "fcntl": "FS",
+ "fdatasync": "FS",
+ "fgetxattr": "FS",
+ "file_getattr": "Misc",
+ "file_setattr": "Misc",
+ "finit_module": "Security",
+ "flistxattr": "FS",
+ "flock": "FS",
+ "fork": "Process",
+ "fremovexattr": "FS",
+ "fsconfig": "FS",
+ "fsetxattr": "FS",
+ "fsmount": "FS",
+ "fsopen": "FS",
+ "fspick": "FS",
+ "fstatfs": "FS",
+ "fsync": "FS",
+ "ftruncate": "FS",
+ "futex": "Misc",
+ "futex_requeue": "Misc",
+ "futex_wait": "Misc",
+ "futex_waitv": "Misc",
+ "futex_wake": "Misc",
+ "futimesat": "FS",
+ "get_mempolicy": "Security",
+ "get_robust_list": "Misc",
+ "getcpu": "Misc",
+ "getcwd": "FS",
+ "getdents": "FS",
+ "getdents64": "FS",
+ "getegid": "Process",
+ "geteuid": "Process",
+ "getgid": "Process",
+ "getgroups": "Process",
+ "getitimer": "Time",
+ "getpeername": "Network",
+ "getpgid": "Process",
+ "getpgrp": "Process",
+ "getpid": "Process",
+ "getppid": "Process",
+ "getpriority": "Process",
+ "getrandom": "Security",
+ "getresgid": "Process",
+ "getresuid": "Process",
+ "getrlimit": "Process",
+ "getrusage": "Process",
+ "getsid": "Process",
+ "getsockname": "Network",
+ "getsockopt": "Network",
+ "gettid": "Process",
+ "gettimeofday": "Time",
+ "getuid": "Process",
+ "getxattr": "FS",
+ "getxattrat": "FS",
+ "init_module": "Security",
+ "inotify_add_watch": "IPC",
+ "inotify_init": "IPC",
+ "inotify_init1": "IPC",
+ "inotify_rm_watch": "IPC",
+ "io_cancel": "AIO",
+ "io_destroy": "AIO",
+ "io_getevents": "AIO",
+ "io_pgetevents": "AIO",
+ "io_setup": "AIO",
+ "io_submit": "AIO",
+ "io_uring_enter": "AIO",
+ "io_uring_register": "AIO",
+ "io_uring_setup": "AIO",
+ "ioctl": "FS",
+ "ioperm": "Misc",
+ "iopl": "Misc",
+ "ioprio_get": "Misc",
+ "ioprio_set": "Misc",
+ "kcmp": "Process",
+ "kexec_file_load": "Security",
+ "kexec_load": "Misc",
+ "keyctl": "Security",
+ "kill": "Signals",
+ "landlock_add_rule": "Security",
+ "landlock_create_ruleset": "Security",
+ "landlock_restrict_self": "Security",
+ "lchown": "FS",
+ "lgetxattr": "FS",
+ "link": "FS",
+ "linkat": "FS",
+ "listen": "Network",
+ "listmount": "FS",
+ "listns": "FS",
+ "listxattr": "FS",
+ "listxattrat": "FS",
+ "llistxattr": "FS",
+ "lremovexattr": "FS",
+ "lseek": "FS",
+ "lsetxattr": "FS",
+ "lsm_get_self_attr": "Misc",
+ "lsm_list_modules": "Misc",
+ "lsm_set_self_attr": "Misc",
+ "madvise": "Memory",
+ "map_shadow_stack": "Memory",
+ "mbind": "Memory",
+ "membarrier": "Memory",
+ "memfd_create": "IPC",
+ "memfd_secret": "IPC",
+ "migrate_pages": "Memory",
+ "mincore": "Memory",
+ "mkdir": "FS",
+ "mkdirat": "FS",
+ "mknod": "FS",
+ "mknodat": "FS",
+ "mlock": "Memory",
+ "mlock2": "Memory",
+ "mlockall": "Memory",
+ "mmap": "Memory",
+ "modify_ldt": "Misc",
+ "mount": "FS",
+ "mount_setattr": "FS",
+ "move_mount": "FS",
+ "move_pages": "Memory",
+ "mprotect": "Memory",
+ "mq_getsetattr": "IPC",
+ "mq_notify": "IPC",
+ "mq_open": "IPC",
+ "mq_timedreceive": "IPC",
+ "mq_timedsend": "IPC",
+ "mq_unlink": "IPC",
+ "mremap": "Memory",
+ "mseal": "Memory",
+ "msgctl": "IPC",
+ "msgget": "IPC",
+ "msgrcv": "IPC",
+ "msgsnd": "IPC",
+ "msync": "FS",
+ "munlock": "Memory",
+ "munlockall": "Memory",
+ "munmap": "Memory",
+ "name_to_handle_at": "FS",
+ "nanosleep": "Time",
+ "newfstat": "FS",
+ "newfstatat": "FS",
+ "newlstat": "FS",
+ "newstat": "FS",
+ "newuname": "Misc",
+ "open": "FS",
+ "open_by_handle_at": "FS",
+ "open_tree": "FS",
+ "open_tree_attr": "FS",
+ "openat": "FS",
+ "openat2": "FS",
+ "pause": "Signals",
+ "perf_event_open": "Security",
+ "personality": "Process",
+ "pidfd_getfd": "IPC",
+ "pidfd_open": "IPC",
+ "pidfd_send_signal": "IPC",
+ "pipe": "IPC",
+ "pipe2": "IPC",
+ "pivot_root": "Process",
+ "pkey_alloc": "Memory",
+ "pkey_free": "Memory",
+ "pkey_mprotect": "Memory",
+ "poll": "Polling",
+ "ppoll": "Polling",
+ "prctl": "Process",
+ "pread64": "FS",
+ "preadv": "FS",
+ "preadv2": "FS",
+ "prlimit64": "Process",
+ "process_madvise": "Memory",
+ "process_mrelease": "Memory",
+ "process_vm_readv": "Memory",
+ "process_vm_writev": "Memory",
+ "pselect6": "Polling",
+ "ptrace": "Security",
+ "pwrite64": "FS",
+ "pwritev": "FS",
+ "pwritev2": "FS",
+ "quotactl": "FS",
+ "quotactl_fd": "FS",
+ "read": "FS",
+ "readahead": "FS",
+ "readlink": "FS",
+ "readlinkat": "FS",
+ "readv": "FS",
+ "reboot": "Process",
+ "recvfrom": "Network",
+ "recvmmsg": "Network",
+ "recvmsg": "Network",
+ "remap_file_pages": "Memory",
+ "removexattr": "FS",
+ "removexattrat": "FS",
+ "rename": "FS",
+ "renameat": "FS",
+ "renameat2": "FS",
+ "request_key": "Security",
+ "restart_syscall": "Process",
+ "rmdir": "FS",
+ "rseq": "Misc",
+ "rt_sigaction": "Signals",
+ "rt_sigpending": "Signals",
+ "rt_sigprocmask": "Signals",
+ "rt_sigqueueinfo": "Signals",
+ "rt_sigreturn": "Signals",
+ "rt_sigsuspend": "Signals",
+ "rt_sigtimedwait": "Signals",
+ "rt_tgsigqueueinfo": "Signals",
+ "sched_get_priority_max": "Sched",
+ "sched_get_priority_min": "Sched",
+ "sched_getaffinity": "Sched",
+ "sched_getattr": "Sched",
+ "sched_getparam": "Sched",
+ "sched_getscheduler": "Sched",
+ "sched_rr_get_interval": "Sched",
+ "sched_setaffinity": "Sched",
+ "sched_setattr": "Sched",
+ "sched_setparam": "Sched",
+ "sched_setscheduler": "Sched",
+ "sched_yield": "Sched",
+ "seccomp": "Security",
+ "select": "Polling",
+ "semctl": "IPC",
+ "semget": "IPC",
+ "semop": "IPC",
+ "semtimedop": "IPC",
+ "sendfile64": "Network",
+ "sendmmsg": "Network",
+ "sendmsg": "Network",
+ "sendto": "Network",
+ "set_mempolicy": "Memory",
+ "set_mempolicy_home_node": "Memory",
+ "set_robust_list": "Misc",
+ "set_tid_address": "Process",
+ "setdomainname": "Misc",
+ "setfsgid": "Process",
+ "setfsuid": "Process",
+ "setgid": "Process",
+ "setgroups": "Process",
+ "sethostname": "Misc",
+ "setitimer": "Time",
+ "setns": "Process",
+ "setpgid": "Process",
+ "setpriority": "Process",
+ "setregid": "Process",
+ "setresgid": "Process",
+ "setresuid": "Process",
+ "setreuid": "Process",
+ "setrlimit": "Process",
+ "setsid": "Process",
+ "setsockopt": "Network",
+ "settimeofday": "Time",
+ "setuid": "Process",
+ "setxattr": "FS",
+ "setxattrat": "FS",
+ "shmat": "IPC",
+ "shmctl": "IPC",
+ "shmdt": "IPC",
+ "shmget": "IPC",
+ "shutdown": "Network",
+ "sigaltstack": "Signals",
+ "signalfd": "IPC",
+ "signalfd4": "IPC",
+ "socket": "Network",
+ "socketpair": "Network",
+ "splice": "Network",
+ "statfs": "FS",
+ "statmount": "FS",
+ "statx": "FS",
+ "swapoff": "FS",
+ "swapon": "FS",
+ "symlink": "FS",
+ "symlinkat": "FS",
+ "sync": "FS",
+ "sync_file_range": "FS",
+ "syncfs": "FS",
+ "sysfs": "Misc",
+ "sysinfo": "Misc",
+ "syslog": "Misc",
+ "tee": "Network",
+ "tgkill": "Signals",
+ "time": "Time",
+ "timer_create": "Time",
+ "timer_delete": "Time",
+ "timer_getoverrun": "Time",
+ "timer_gettime": "Time",
+ "timer_settime": "Time",
+ "timerfd_create": "IPC",
+ "timerfd_gettime": "IPC",
+ "timerfd_settime": "IPC",
+ "times": "Time",
+ "tkill": "Signals",
+ "truncate": "FS",
+ "umask": "Process",
+ "umount": "FS",
+ "unlink": "FS",
+ "unlinkat": "FS",
+ "unshare": "Process",
+ "uprobe": "Misc",
+ "uretprobe": "Misc",
+ "userfaultfd": "IPC",
+ "ustat": "FS",
+ "utime": "Misc",
+ "utimensat": "FS",
+ "utimes": "Misc",
+ "vfork": "Process",
+ "vhangup": "Process",
+ "vmsplice": "Misc",
+ "wait4": "Process",
+ "waitid": "Process",
+ "write": "FS",
+ "writev": "FS",
+}
+
+var syscallKinds = map[string]string{
+ "accept": "accept",
+ "accept4": "accept",
+ "access": "path",
+ "acct": "null",
+ "add_key": "keyctl",
+ "adjtimex": "null",
+ "alarm": "null",
+ "arch_prctl": "null",
+ "bind": "fd",
+ "bpf": "null",
+ "brk": "null",
+ "cachestat": "fd",
+ "capget": "null",
+ "capset": "null",
+ "chdir": "path",
+ "chmod": "path",
+ "chown": "path",
+ "chroot": "path",
+ "clock_adjtime": "null",
+ "clock_getres": "null",
+ "clock_gettime": "null",
+ "clock_nanosleep": "sleep",
+ "clock_settime": "null",
+ "clone": "null",
+ "clone3": "null",
+ "close": "fd",
+ "close_range": "fd",
+ "connect": "fd",
+ "copy_file_range": "fd",
+ "creat": "path",
+ "delete_module": "null",
+ "dup": "fd",
+ "dup2": "fd",
+ "dup3": "dup3",
+ "epoll_create": "null",
+ "epoll_create1": "null",
+ "epoll_ctl": "epoll-ctl",
+ "epoll_pwait": "fd",
+ "epoll_pwait2": "fd",
+ "epoll_wait": "fd",
+ "eventfd": "eventfd",
+ "eventfd2": "eventfd",
+ "execve": "exec",
+ "execveat": "exec",
+ "exit": "null",
+ "exit_group": "null",
+ "faccessat": "path",
+ "faccessat2": "path",
+ "fadvise64": "fd",
+ "fallocate": "fd",
+ "fanotify_init": "null",
+ "fanotify_mark": "path",
+ "fchdir": "fd",
+ "fchmod": "fd",
+ "fchmodat": "path",
+ "fchmodat2": "path",
+ "fchown": "fd",
+ "fchownat": "path",
+ "fcntl": "fcntl",
+ "fdatasync": "fd",
+ "fgetxattr": "fd",
+ "file_getattr": "path",
+ "file_setattr": "path",
+ "finit_module": "fd",
+ "flistxattr": "fd",
+ "flock": "fd",
+ "fork": "null",
+ "fremovexattr": "fd",
+ "fsconfig": "fd",
+ "fsetxattr": "fd",
+ "fsmount": "eventfd",
+ "fsopen": "null",
+ "fspick": "path",
+ "fstatfs": "fd",
+ "fsync": "fd",
+ "ftruncate": "fd",
+ "futex": "null",
+ "futex_requeue": "null",
+ "futex_wait": "null",
+ "futex_waitv": "null",
+ "futex_wake": "null",
+ "futimesat": "path",
+ "get_mempolicy": "null",
+ "get_robust_list": "null",
+ "getcpu": "null",
+ "getcwd": "null",
+ "getdents": "fd",
+ "getdents64": "fd",
+ "getegid": "null",
+ "geteuid": "null",
+ "getgid": "null",
+ "getgroups": "null",
+ "getitimer": "null",
+ "getpeername": "fd",
+ "getpgid": "null",
+ "getpgrp": "null",
+ "getpid": "null",
+ "getppid": "null",
+ "getpriority": "null",
+ "getrandom": "null",
+ "getresgid": "null",
+ "getresuid": "null",
+ "getrlimit": "null",
+ "getrusage": "null",
+ "getsid": "null",
+ "getsockname": "fd",
+ "getsockopt": "fd",
+ "gettid": "null",
+ "gettimeofday": "null",
+ "getuid": "null",
+ "getxattr": "path",
+ "getxattrat": "path",
+ "init_module": "null",
+ "inotify_add_watch": "fd",
+ "inotify_init": "null",
+ "inotify_init1": "null",
+ "inotify_rm_watch": "fd",
+ "io_cancel": "null",
+ "io_destroy": "null",
+ "io_getevents": "null",
+ "io_pgetevents": "null",
+ "io_setup": "null",
+ "io_submit": "null",
+ "io_uring_enter": "fd",
+ "io_uring_register": "fd",
+ "io_uring_setup": "null",
+ "ioctl": "fd",
+ "ioperm": "null",
+ "iopl": "null",
+ "ioprio_get": "null",
+ "ioprio_set": "null",
+ "kcmp": "null",
+ "kexec_file_load": "null",
+ "kexec_load": "null",
+ "keyctl": "keyctl",
+ "kill": "null",
+ "landlock_add_rule": "null",
+ "landlock_create_ruleset": "null",
+ "landlock_restrict_self": "null",
+ "lchown": "path",
+ "lgetxattr": "path",
+ "link": "name",
+ "linkat": "name",
+ "listen": "fd",
+ "listmount": "null",
+ "listns": "null",
+ "listxattr": "path",
+ "listxattrat": "path",
+ "llistxattr": "path",
+ "lremovexattr": "path",
+ "lseek": "fd",
+ "lsetxattr": "path",
+ "lsm_get_self_attr": "null",
+ "lsm_list_modules": "null",
+ "lsm_set_self_attr": "null",
+ "madvise": "null",
+ "map_shadow_stack": "null",
+ "mbind": "null",
+ "membarrier": "null",
+ "memfd_create": "null",
+ "memfd_secret": "null",
+ "migrate_pages": "null",
+ "mincore": "null",
+ "mkdir": "path",
+ "mkdirat": "path",
+ "mknod": "path",
+ "mknodat": "path",
+ "mlock": "null",
+ "mlock2": "null",
+ "mlockall": "null",
+ "mmap": "fd",
+ "modify_ldt": "null",
+ "mount": "path",
+ "mount_setattr": "path",
+ "move_mount": "two-fd",
+ "move_pages": "null",
+ "mprotect": "null",
+ "mq_getsetattr": "fd",
+ "mq_notify": "fd",
+ "mq_open": "open",
+ "mq_timedreceive": "fd",
+ "mq_timedsend": "fd",
+ "mq_unlink": "path",
+ "mremap": "mem",
+ "mseal": "null",
+ "msgctl": "null",
+ "msgget": "null",
+ "msgrcv": "null",
+ "msgsnd": "null",
+ "msync": "null",
+ "munlock": "null",
+ "munlockall": "null",
+ "munmap": "mem",
+ "name_to_handle_at": "path",
+ "nanosleep": "sleep",
+ "newfstat": "fd",
+ "newfstatat": "path",
+ "newlstat": "path",
+ "newstat": "path",
+ "newuname": "null",
+ "open": "open",
+ "open_by_handle_at": "open-by-handle-at",
+ "open_tree": "open",
+ "open_tree_attr": "open",
+ "openat": "open",
+ "openat2": "open",
+ "pause": "null",
+ "perf_event_open": "perf-open",
+ "personality": "null",
+ "pidfd_getfd": "fd",
+ "pidfd_open": "null",
+ "pidfd_send_signal": "null",
+ "pipe": "pipe",
+ "pipe2": "pipe",
+ "pivot_root": "path",
+ "pkey_alloc": "null",
+ "pkey_free": "null",
+ "pkey_mprotect": "null",
+ "poll": "poll",
+ "ppoll": "poll",
+ "prctl": "null",
+ "pread64": "fd",
+ "preadv": "fd",
+ "preadv2": "fd",
+ "prlimit64": "null",
+ "process_madvise": "null",
+ "process_mrelease": "null",
+ "process_vm_readv": "null",
+ "process_vm_writev": "null",
+ "pselect6": "poll",
+ "ptrace": "ptrace",
+ "pwrite64": "fd",
+ "pwritev": "fd",
+ "pwritev2": "fd",
+ "quotactl": "path",
+ "quotactl_fd": "fd",
+ "read": "fd",
+ "readahead": "fd",
+ "readlink": "path",
+ "readlinkat": "path",
+ "readv": "fd",
+ "reboot": "null",
+ "recvfrom": "fd",
+ "recvmmsg": "fd",
+ "recvmsg": "fd",
+ "remap_file_pages": "null",
+ "removexattr": "path",
+ "removexattrat": "path",
+ "rename": "name",
+ "renameat": "name",
+ "renameat2": "name",
+ "request_key": "keyctl",
+ "restart_syscall": "null",
+ "rmdir": "path",
+ "rseq": "null",
+ "rt_sigaction": "null",
+ "rt_sigpending": "null",
+ "rt_sigprocmask": "null",
+ "rt_sigqueueinfo": "null",
+ "rt_sigreturn": "null",
+ "rt_sigsuspend": "null",
+ "rt_sigtimedwait": "null",
+ "rt_tgsigqueueinfo": "null",
+ "sched_get_priority_max": "null",
+ "sched_get_priority_min": "null",
+ "sched_getaffinity": "null",
+ "sched_getattr": "null",
+ "sched_getparam": "null",
+ "sched_getscheduler": "null",
+ "sched_rr_get_interval": "null",
+ "sched_setaffinity": "null",
+ "sched_setattr": "null",
+ "sched_setparam": "null",
+ "sched_setscheduler": "null",
+ "sched_yield": "null",
+ "seccomp": "null",
+ "select": "poll",
+ "semctl": "null",
+ "semget": "null",
+ "semop": "null",
+ "semtimedop": "null",
+ "sendfile64": "null",
+ "sendmmsg": "fd",
+ "sendmsg": "fd",
+ "sendto": "fd",
+ "set_mempolicy": "null",
+ "set_mempolicy_home_node": "null",
+ "set_robust_list": "null",
+ "set_tid_address": "null",
+ "setdomainname": "null",
+ "setfsgid": "null",
+ "setfsuid": "null",
+ "setgid": "null",
+ "setgroups": "null",
+ "sethostname": "null",
+ "setitimer": "null",
+ "setns": "fd",
+ "setpgid": "null",
+ "setpriority": "null",
+ "setregid": "null",
+ "setresgid": "null",
+ "setresuid": "null",
+ "setreuid": "null",
+ "setrlimit": "null",
+ "setsid": "null",
+ "setsockopt": "fd",
+ "settimeofday": "null",
+ "setuid": "null",
+ "setxattr": "path",
+ "setxattrat": "path",
+ "shmat": "null",
+ "shmctl": "null",
+ "shmdt": "null",
+ "shmget": "null",
+ "shutdown": "fd",
+ "sigaltstack": "null",
+ "signalfd": "null",
+ "signalfd4": "null",
+ "socket": "socket",
+ "socketpair": "socketpair",
+ "splice": "null",
+ "statfs": "path",
+ "statmount": "null",
+ "statx": "path",
+ "swapoff": "path",
+ "swapon": "path",
+ "symlink": "name",
+ "symlinkat": "name",
+ "sync": "null",
+ "sync_file_range": "fd",
+ "syncfs": "fd",
+ "sysfs": "null",
+ "sysinfo": "null",
+ "syslog": "null",
+ "tee": "null",
+ "tgkill": "null",
+ "time": "null",
+ "timer_create": "null",
+ "timer_delete": "null",
+ "timer_getoverrun": "null",
+ "timer_gettime": "null",
+ "timer_settime": "null",
+ "timerfd_create": "null",
+ "timerfd_gettime": "null",
+ "timerfd_settime": "null",
+ "times": "null",
+ "tkill": "null",
+ "truncate": "path",
+ "umask": "null",
+ "umount": "path",
+ "unlink": "path",
+ "unlinkat": "path",
+ "unshare": "null",
+ "uprobe": "null",
+ "uretprobe": "null",
+ "userfaultfd": "null",
+ "ustat": "null",
+ "utime": "path",
+ "utimensat": "path",
+ "utimes": "path",
+ "vfork": "null",
+ "vhangup": "null",
+ "vmsplice": "fd",
+ "wait4": "null",
+ "waitid": "null",
+ "write": "fd",
+ "writev": "fd",
+}
diff --git a/internal/tracepoints/selector.go b/internal/tracepoints/selector.go
index af2f39e..91df58f 100644
--- a/internal/tracepoints/selector.go
+++ b/internal/tracepoints/selector.go
@@ -2,6 +2,7 @@ package tracepoints
import (
"fmt"
+ "maps"
"regexp"
"slices"
"strings"
@@ -18,6 +19,12 @@ type Selector struct {
// Exclude is the list of compiled regexes that suppress specific
// tracepoints even when they match the Attach list.
Exclude []*regexp.Regexp
+ // Syscalls optionally restricts attach to an explicit syscall allowlist.
+ // Keys are bare syscall names (for example "openat", not "sys_enter_openat").
+ // When RestrictSyscalls is true, only entries in this map are attached.
+ Syscalls map[string]struct{}
+ // RestrictSyscalls gates whether Syscalls should be enforced.
+ RestrictSyscalls bool
}
// ParseSelector parses the comma-separated regex strings for the -tps and
@@ -65,11 +72,27 @@ func (s Selector) ShouldAttach(tracepointName string) bool {
}
}
if len(s.Attach) == 0 {
- return true
+ if !s.RestrictSyscalls {
+ return true
+ }
+ syscall, ok := SyscallNameFromTracepoint(tracepointName)
+ if !ok {
+ return false
+ }
+ _, allowed := s.Syscalls[syscall]
+ return allowed
}
for _, re := range s.Attach {
if re.MatchString(tracepointName) {
- return true
+ if !s.RestrictSyscalls {
+ return true
+ }
+ syscall, ok := SyscallNameFromTracepoint(tracepointName)
+ if !ok {
+ return false
+ }
+ _, allowed := s.Syscalls[syscall]
+ return allowed
}
}
return false
@@ -79,7 +102,22 @@ func (s Selector) ShouldAttach(tracepointName string) bool {
// copy's slices do not affect the original.
func (s Selector) Clone() Selector {
return Selector{
- Attach: slices.Clone(s.Attach),
- Exclude: slices.Clone(s.Exclude),
+ Attach: slices.Clone(s.Attach),
+ Exclude: slices.Clone(s.Exclude),
+ Syscalls: maps.Clone(s.Syscalls),
+ RestrictSyscalls: s.RestrictSyscalls,
+ }
+}
+
+// SyscallNameFromTracepoint returns the bare syscall name for a tracepoint
+// (for example "openat" from "sys_enter_openat").
+func SyscallNameFromTracepoint(tracepointName string) (string, bool) {
+ switch {
+ case strings.HasPrefix(tracepointName, "sys_enter_"):
+ return strings.TrimPrefix(tracepointName, "sys_enter_"), true
+ case strings.HasPrefix(tracepointName, "sys_exit_"):
+ return strings.TrimPrefix(tracepointName, "sys_exit_"), true
+ default:
+ return "", false
}
}
diff --git a/internal/tracepoints/selector_test.go b/internal/tracepoints/selector_test.go
index d12f24b..dd9084b 100644
--- a/internal/tracepoints/selector_test.go
+++ b/internal/tracepoints/selector_test.go
@@ -82,3 +82,17 @@ func TestSelectorCloneIsIndependent(t *testing.T) {
t.Error("original Selector was mutated through clone")
}
}
+
+func TestSelectorCloneCopiesSyscallAllowlist(t *testing.T) {
+ sel := Selector{
+ Syscalls: map[string]struct{}{
+ "openat": {},
+ },
+ RestrictSyscalls: true,
+ }
+ clone := sel.Clone()
+ delete(clone.Syscalls, "openat")
+ if !sel.ShouldAttach("sys_enter_openat") {
+ t.Fatal("original syscall allowlist mutated through clone")
+ }
+}