diff --git a/LICENSE-3rdparty.csv b/LICENSE-3rdparty.csv index 455f9e6bfb..2c7d2162be 100644 --- a/LICENSE-3rdparty.csv +++ b/LICENSE-3rdparty.csv @@ -197,7 +197,6 @@ github.com/Microsoft/hcsshim,github.com/Microsoft/hcsshim/internal/winapi,MIT github.com/Microsoft/hcsshim,github.com/Microsoft/hcsshim/osversion,MIT github.com/Microsoft/hcsshim,github.com/Microsoft/hcsshim/pkg/ociwclayer,MIT github.com/aquasecurity/libbpfgo,github.com/aquasecurity/libbpfgo,Apache-2.0 -github.com/aquasecurity/libbpfgo/helpers,github.com/aquasecurity/libbpfgo/helpers,Apache-2.0 github.com/avast/retry-go,github.com/avast/retry-go,MIT github.com/beorn7/perks,github.com/beorn7/perks/quantile,MIT github.com/cenkalti/backoff,github.com/cenkalti/backoff,MIT diff --git a/bin/injector/Dockerfile b/bin/injector/Dockerfile index f0e5dade54..63bde62b07 100644 --- a/bin/injector/Dockerfile +++ b/bin/injector/Dockerfile @@ -85,7 +85,7 @@ FROM gcr.io/distroless/python3-debian13:latest ARG TARGETARCH # binaries used by the chaos-injector, ran as commmands -COPY --from=binaries /usr/bin/uname /usr/bin/df /usr/bin/ls /usr/bin/test /usr/bin/ +COPY --from=binaries /usr/bin/uname /usr/bin/bash /usr/bin/ls /usr/bin/cat /usr/bin/df /usr/bin/ls /usr/bin/test /usr/bin/ COPY --from=binaries /usr/sbin/iptables /usr/sbin/ COPY --from=binaries /usr/sbin/tc /sbin/tc COPY --from=binaries /usr/bin/bpftool-${TARGETARCH} /usr/bin/bpftool diff --git a/builderstest/chaospod.go b/builderstest/chaospod.go index 734e7451d5..70af51d6c8 100644 --- a/builderstest/chaospod.go +++ b/builderstest/chaospod.go @@ -292,6 +292,10 @@ func (b *ChaosPodBuilder) WithChaosSpec(targetNodeName string, terminationGraceP MountPath: "/boot", ReadOnly: true, }, + { + Name: "tracefs", + MountPath: "/mnt/tracefs", + }, }, }, }, @@ -359,6 +363,15 @@ func (b *ChaosPodBuilder) WithChaosSpec(targetNodeName string, terminationGraceP }, }, }, + { + Name: "tracefs", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: "/sys/kernel/debug/tracing", + Type: &hostPathDirectory, + }, + }, + }, }, } }) diff --git a/cgroup/manager.go b/cgroup/manager.go index 27862241b9..2c69cf17b9 100644 --- a/cgroup/manager.go +++ b/cgroup/manager.go @@ -30,6 +30,10 @@ type Manager interface { IsCgroupV2() bool // RelativePath returns the controller relative path RelativePath(controller string) string + // CgroupV2Path returns the absolute cgroupv2 unified hierarchy path for the cgroup, + // or empty string on cgroupv1. Used to populate BPF_MAP_TYPE_CGROUP_ARRAY for + // bpf_current_task_under_cgroup() ancestor checking (covers kubectl exec sub-cgroups). + CgroupV2Path() string } type instCGroupManager interface { @@ -131,3 +135,12 @@ func (m manager) IsCgroupV2() bool { func (m manager) RelativePath(controller string) string { return strings.TrimPrefix(m.cgroups.Path(controller), m.mountPath) } + +// CgroupV2Path returns the absolute cgroupv2 unified hierarchy path, or "" on cgroupv1. +func (m manager) CgroupV2Path() string { + if !m.isV2 { + return "" + } + + return m.cgroups.Path("") +} diff --git a/cgroup/manager_mock.go b/cgroup/manager_mock.go index cf2f870f61..41e66e3fde 100644 --- a/cgroup/manager_mock.go +++ b/cgroup/manager_mock.go @@ -25,6 +25,51 @@ func (_m *ManagerMock) EXPECT() *ManagerMock_Expecter { return &ManagerMock_Expecter{mock: &_m.Mock} } +// CgroupV2Path provides a mock function with no fields +func (_m *ManagerMock) CgroupV2Path() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for CgroupV2Path") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// ManagerMock_CgroupV2Path_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CgroupV2Path' +type ManagerMock_CgroupV2Path_Call struct { + *mock.Call +} + +// CgroupV2Path is a helper method to define mock.On call +func (_e *ManagerMock_Expecter) CgroupV2Path() *ManagerMock_CgroupV2Path_Call { + return &ManagerMock_CgroupV2Path_Call{Call: _e.mock.On("CgroupV2Path")} +} + +func (_c *ManagerMock_CgroupV2Path_Call) Run(run func()) *ManagerMock_CgroupV2Path_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ManagerMock_CgroupV2Path_Call) Return(_a0 string) *ManagerMock_CgroupV2Path_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ManagerMock_CgroupV2Path_Call) RunAndReturn(run func() string) *ManagerMock_CgroupV2Path_Call { + _c.Call.Return(run) + return _c +} + // IsCgroupV2 provides a mock function with no fields func (_m *ManagerMock) IsCgroupV2() bool { ret := _m.Called() diff --git a/ebpf/const-x64.go b/ebpf/const-x64.go deleted file mode 100644 index 3c73bb35b9..0000000000 --- a/ebpf/const-x64.go +++ /dev/null @@ -1,11 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are licensed -// under the Apache License Version 2.0. -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2026 Datadog, Inc. - -//go:build amd64 -// +build amd64 - -package ebpf - -const SysOpenat = "__x64_sys_openat" diff --git a/ebpf/disk-failure/injection.bpf.c b/ebpf/disk-failure/injection.bpf.c index 3b41431f71..96548d577f 100644 --- a/ebpf/disk-failure/injection.bpf.c +++ b/ebpf/disk-failure/injection.bpf.c @@ -8,7 +8,75 @@ const volatile pid_t target_pid = 0; const volatile pid_t exclude_pid; +const volatile int use_cgroup_filter = 0; +// Network namespace inode of the target container. +// All processes in a container — including those started via kubectl exec — +// share the same netns, making this the most reliable container filter when +// bpf_current_task_under_cgroup() fails (e.g. on this cluster ~99.8% miss rate). +const volatile u64 target_netns_ino = 0; const volatile char filter_path[61]; +// Inode of filter_path's parent directory. When non-zero, enables filtering of +// relative openat calls by comparing the process CWD inode against this value. +// Works correctly inside containers because Kubernetes volumes are bind-mounted: +// the host inode and the in-container inode are identical. +const volatile u64 filter_dir_inode = 0; +// Device ID paired with filter_dir_inode. Inodes are only unique within a device, +// so checking both prevents false matches on bind-mounted or multi-filesystem targets. +const volatile u32 filter_dir_dev = 0; +// Second inode/device pair: set when filter_path is itself a directory. When the +// CWD matches this inode/device, any relative open (except ".." escapes) is +// in-scope. This handles "cd /mnt/data && cat file" alongside the parent+basename +// case covered by filter_dir_inode (i.e. "cwd=/mnt && cat data/file"). +const volatile u64 filter_dir_inode2 = 0; +const volatile u32 filter_dir_dev2 = 0; + +// Populated from userspace with the container's cgroupv2 directory fd. +// bpf_current_task_under_cgroup() matches the process itself AND any sub-cgroup +// (e.g. containerd exec- sub-cgroups created by kubectl exec). +struct { + __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY); + __uint(max_entries, 1); + __type(key, u32); + __type(value, u32); +} target_cgroup SEC(".maps"); + +// Debug counters read periodically by the Go loader to diagnose path filter +// behaviour without relying on tracefs (which is often blocked by node policy). +// 0: abs path matched; 1: abs path missed; 2: rel path, no inode filter; +// 3: rel path, inode matched (disrupted); 4: rel path, inode missed; +// 5: rel path, dirfd inode == filter_dir_inode but basename mismatch; +// 6: rel path, fdtable lookup returned null fd (silent drop). +// 7: cgroup filter returned 1 (in cgroup); +// 8: cgroup filter returned 0 (not in cgroup); +// 9: cgroup filter returned error (negative); +// 10: netns inode matched (disrupted via netns fallback); +// 11: netns inode not matched. +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 12); + __type(key, u32); + __type(value, u64); +} debug_counters SEC(".maps"); + +#define DBG_ABS_HIT 0 +#define DBG_ABS_MISS 1 +#define DBG_REL_NO_FILTER 2 +#define DBG_REL_HIT 3 +#define DBG_REL_MISS 4 +#define DBG_REL_INO_MATCH 5 +#define DBG_REL_NULL_FD 6 +#define DBG_CGROUP_HIT 7 +#define DBG_CGROUP_MISS 8 +#define DBG_CGROUP_ERR 9 +#define DBG_NETNS_HIT 10 +#define DBG_NETNS_MISS 11 + +static __always_inline void dbg_inc(u32 idx) +{ + u64 *val = bpf_map_lookup_elem(&debug_counters, &idx); + if (val) __sync_fetch_and_add(val, 1); +} + const volatile pid_t exit_code = ENOENT; const volatile int probability = 100; @@ -17,8 +85,10 @@ unsigned int disruptedHits = 0; struct data_t { u32 ppid; - u32 pid; - u32 tid; + // tid is the kernel thread ID (what userspace calls TID via gettid()). + // tgid is the kernel thread-group ID (what userspace calls PID via getpid()). + u32 tid; + u32 tgid; u32 id; char comm[100]; }; @@ -30,80 +100,293 @@ struct { __type(value, u32); } events SEC(".maps"); -SEC("kprobe/sys_openat") +// AT_FDCWD sentinel: openat resolves relative paths against CWD only when +// this value is passed as dirfd. +#ifndef AT_FDCWD +#define AT_FDCWD -100 +#endif + +// check_basename_prefix returns 1 if rel_buf starts with the basename of filter_path. +static __always_inline int check_basename_prefix(const char *rel_buf) +{ + int last_slash = 0; + for (int i = 0; i < 60; i++) { + if (filter_path[i] == '\0') break; + if (filter_path[i] == '/') last_slash = i; + } + for (int i = 0; i < 60; i++) { + int fi = last_slash + 1 + i; + if (fi >= 61) break; + if (filter_path[fi & 0x3f] == '\0') break; + if (rel_buf[i] != filter_path[fi & 0x3f]) return 0; + } + return 1; +} + +// check_relative_path returns 1 if a relative openat should be disrupted. +// Handles both AT_FDCWD (match against CWD inode) and explicit dirfd (match +// against the inode of the directory the fd points to). Using inodes works +// inside containers because Kubernetes volumes are bind-mounted: the host inode +// and the in-container inode are identical. +static int check_relative_path(int dirfd, const char *rel_path) +{ + if (filter_dir_inode == 0 && filter_dir_inode2 == 0) { + dbg_inc(DBG_REL_NO_FILTER); + return 0; + } + + u64 ino = 0; + u32 dev = 0; + + if (dirfd == AT_FDCWD) { + struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + struct fs_struct *fs_ptr; + bpf_probe_read_kernel(&fs_ptr, sizeof(fs_ptr), &task->fs); + struct path pwd; + bpf_probe_read_kernel(&pwd, sizeof(pwd), &fs_ptr->pwd); + struct inode *inode_ptr; + bpf_probe_read_kernel(&inode_ptr, sizeof(inode_ptr), &pwd.dentry->d_inode); + bpf_probe_read_kernel(&ino, sizeof(ino), &inode_ptr->i_ino); + struct super_block *sb_ptr = NULL; + bpf_probe_read_kernel(&sb_ptr, sizeof(sb_ptr), &inode_ptr->i_sb); + bpf_probe_read_kernel(&dev, sizeof(dev), &sb_ptr->s_dev); + } else if (dirfd >= 0) { + // Look up the inode of the directory referenced by the explicit dirfd. + u32 ufd = (u32)dirfd; + if (ufd >= 1024) return 0; + + struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + struct files_struct *files_ptr; + bpf_probe_read_kernel(&files_ptr, sizeof(files_ptr), &task->files); + if (!files_ptr) return 0; + struct fdtable *fdt_ptr; + bpf_probe_read_kernel(&fdt_ptr, sizeof(fdt_ptr), &files_ptr->fdt); + if (!fdt_ptr) return 0; + struct file **fd_arr; + bpf_probe_read_kernel(&fd_arr, sizeof(fd_arr), &fdt_ptr->fd); + if (!fd_arr) return 0; + struct file *f = NULL; + bpf_probe_read_kernel(&f, sizeof(f), (void *)((__u64)fd_arr + (__u64)ufd * sizeof(struct file *))); + if (!f) { + dbg_inc(DBG_REL_NULL_FD); + return 0; + } + struct inode *inode_ptr; + bpf_probe_read_kernel(&inode_ptr, sizeof(inode_ptr), &f->f_inode); + if (!inode_ptr) return 0; + bpf_probe_read_kernel(&ino, sizeof(ino), &inode_ptr->i_ino); + struct super_block *sb_ptr = NULL; + bpf_probe_read_kernel(&sb_ptr, sizeof(sb_ptr), &inode_ptr->i_sb); + if (!sb_ptr) return 0; + bpf_probe_read_kernel(&dev, sizeof(dev), &sb_ptr->s_dev); + } else { + return 0; + } + + char rel_buf[62] = {}; + bpf_probe_read(rel_buf, sizeof(rel_buf) - 1, rel_path); + + // Track when our dirfd's inode matches the filter inode (regardless of basename) + // to distinguish "wrong directory" from "right directory but wrong filename". + if ((filter_dir_inode != 0 && ino == filter_dir_inode) || + (filter_dir_inode2 != 0 && ino == filter_dir_inode2)) + dbg_inc(DBG_REL_INO_MATCH); + + // Check 1: dir == parent of filter_path AND rel_path starts with its basename. + if (filter_dir_inode != 0 && ino == filter_dir_inode && + (filter_dir_dev == 0 || dev == filter_dir_dev) && + check_basename_prefix(rel_buf)) { + dbg_inc(DBG_REL_HIT); + return 1; + } + + // Check 2: dir == filter_path itself (directory target) AND rel_path doesn't escape. + if (filter_dir_inode2 != 0 && ino == filter_dir_inode2 && + (filter_dir_dev2 == 0 || dev == filter_dir_dev2) && + !(rel_buf[0] == '.' && rel_buf[1] == '.')) { + dbg_inc(DBG_REL_HIT); + return 1; + } + + dbg_inc(DBG_REL_MISS); + return 0; +} + +// is_in_target_netns checks whether the current task's network namespace inode +// matches target_netns_ino. All processes in a container — including those +// started via kubectl exec — share the same netns, so this catches exec sessions +// that are not descendants of the container init in the host process tree. +static __always_inline int is_in_target_netns(void) +{ + if (target_netns_ino == 0) + return 0; + + struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + struct nsproxy *nsproxy = NULL; + bpf_probe_read_kernel(&nsproxy, sizeof(nsproxy), &task->nsproxy); + if (!nsproxy) + return 0; + + struct net *net = NULL; + bpf_probe_read_kernel(&net, sizeof(net), &nsproxy->net_ns); + if (!net) + return 0; + + unsigned int ino = 0; + bpf_probe_read_kernel(&ino, sizeof(ino), &net->ns.inum); + + return (ino == (unsigned int)target_netns_ino) ? 1 : 0; +} + +// is_in_target_tree walks up to 10 levels of the process ancestry chain. +// Returns 1 if the current process or any ancestor has TGID == target. +// This covers processes spawned via kubectl exec where the hierarchy is: +// container_init (target_pid) → exec_agent → shell → dd (3 levels deep). +static __always_inline int is_in_target_tree(pid_t target) +{ + if (target == 0) + return 0; + + struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + + #pragma unroll + for (int i = 0; i < 10; i++) { + if (!task) return 0; + u32 cur_tgid = 0; + bpf_probe_read(&cur_tgid, sizeof(cur_tgid), &task->tgid); + if (cur_tgid == (u32)target) return 1; + if (cur_tgid <= 1) return 0; // reached init or kernel thread + struct task_struct *parent = NULL; + bpf_probe_read(&parent, sizeof(parent), &task->real_parent); + task = parent; + } + return 0; +} + +// do_filter_by_process returns 1 if the current process should be excluded (filtered out), +// 0 if it should be disrupted. +// Strategy (in order): +// 1. cgroup FD check — fast O(1), handles all processes in the container's cgroup tree. +// 2. netns inode check — catches kubectl exec sessions: they share the container's +// network namespace but are NOT descendants of the container init in the host PID tree. +// 3. process ancestry walk — last-resort for environments where both cgroup and netns +// filters are unavailable. +static __always_inline int do_filter_by_process(void) +{ + if (use_cgroup_filter) { + int in_cgroup = bpf_current_task_under_cgroup(&target_cgroup, 0); + if (in_cgroup == 1) { + dbg_inc(DBG_CGROUP_HIT); + return 0; // in cgroup → disrupt + } + if (in_cgroup < 0) { + dbg_inc(DBG_CGROUP_ERR); + } else { + dbg_inc(DBG_CGROUP_MISS); + } + // Fallback 1: netns inode — reliable for kubectl exec and all container processes. + if (is_in_target_netns()) { + dbg_inc(DBG_NETNS_HIT); + return 0; + } + dbg_inc(DBG_NETNS_MISS); + // Fallback 2: ancestry walk — catches container workload processes. + if (is_in_target_tree(target_pid)) + return 0; + return 1; // exclude + } else if (target_pid != 0) { + return is_in_target_tree(target_pid) ? 0 : 1; + } + return 0; +} + +// do_probability_check returns 1 if the event should be skipped due to probability sampling. +static __always_inline int do_probability_check() +{ + if (probability == 100) return 0; + if (hits != 0) { + unsigned long long scaled = disruptedHits * 100; + if ((scaled / hits) > probability) { + hits++; + return 1; + } + } + hits++; + disruptedHits++; + return 0; +} + +#if defined(__TARGET_ARCH_arm64) +SEC("fmod_ret/__arm64_sys_openat") +#else +SEC("fmod_ret/__x64_sys_openat") +#endif int injection_disk_failure(struct pt_regs *ctx) { struct data_t data = {}; - // Get data of the current process u32 ppid = 0; - u32 pid = bpf_get_current_pid_tgid(); - if (pid == exclude_pid) { + // bpf_get_current_pid_tgid() returns (tgid << 32 | tid). + // Lower 32 bits = kernel TID (thread ID); upper 32 bits = kernel TGID (process ID). + u64 pid_tgid = bpf_get_current_pid_tgid(); + u32 tid = (u32)pid_tgid; // kernel TID == userspace TID (gettid) + u32 tgid = (u32)(pid_tgid >> 32); // kernel TGID == userspace PID (getpid) + // Exclude the bpf-disk-failure binary itself (and all its threads) to prevent + // the injector from disrupting its own file operations. + if (tgid == exclude_pid) { return 0; } - u32 tid = bpf_get_current_pid_tgid() >> 32; u32 gid = bpf_get_current_uid_gid(); - if (pid != 1) { - // Get parent pid + if (tgid != 1) { + // Get parent pid (needed for cgroupv1 PID filter and exclude_pid check below) struct task_struct *task; struct task_struct *real_parent; task = (struct task_struct *)bpf_get_current_task(); bpf_probe_read(&real_parent, sizeof(real_parent), &task->real_parent); bpf_probe_read(&ppid, sizeof(ppid), &real_parent->tgid); - - // Allow only children and parent process. - if (target_pid != 0 && ppid != target_pid && pid != target_pid) { - return 0; - } } - if (ppid == exclude_pid || tid == exclude_pid) { - return 0; - } + if (do_filter_by_process()) return 0; -// Exclude this part of code if the following variables are not defined. -// It allows the go program to compile without error. -#if defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) - // Allow only file with the desired prefix. - struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(ctx); - char *path = (char *)PT_REGS_PARM2_CORE(real_regs); - char cmp_path_name[62]; - bpf_probe_read(&cmp_path_name, sizeof(cmp_path_name), path); - char cmp_expected_path[62]; - bpf_probe_read(cmp_expected_path, sizeof(cmp_expected_path), (const void *)filter_path); - int filter_len = (int) (sizeof(filter_path) / sizeof(filter_path[0])) - 1; - - if (filter_len > 62) { + if (ppid == exclude_pid || tgid == exclude_pid) { return 0; } - for (int i = 0; i < filter_len; ++i) { - if (cmp_expected_path[i] == NULL) - break; - if (cmp_path_name[i] != cmp_expected_path[i]) - return 0; - } -#endif + // Read openat arguments from inner pt_regs. Both __arm64_sys_openat and + // __x64_sys_openat wrap syscall args in a (const struct pt_regs *) passed + // as their only argument, so PARM1(ctx) is the inner regs pointer. + struct pt_regs *inner_regs = (struct pt_regs *)(unsigned long)PT_REGS_PARM1_CORE(ctx); + int dirfd = (int)(long)PT_REGS_PARM1_CORE(inner_regs); + const char *path = (const char *)PT_REGS_PARM2_CORE(inner_regs); - if (probability != 100) { - if (hits != 0) { - unsigned long long scaled_disruptedHits = disruptedHits * 100; - unsigned long long scaled_hits = hits; + char cmp_path_name[62]; + bpf_probe_read(cmp_path_name, sizeof(cmp_path_name), path); - if ((scaled_disruptedHits / scaled_hits) > probability) { - hits++; - return 0; - } + if (cmp_path_name[0] == '/') { + char cmp_expected_path[62]; + bpf_probe_read(cmp_expected_path, sizeof(cmp_expected_path), (const void *)filter_path); + int filter_len = (int)(sizeof(filter_path) / sizeof(filter_path[0])) - 1; + if (filter_len > 62) return 0; + int abs_match = 1; + for (int i = 0; i < filter_len; ++i) { + if (cmp_expected_path[i] == '\0') break; + if (cmp_path_name[i] != cmp_expected_path[i]) { abs_match = 0; break; } } - - hits++; - disruptedHits++; + if (!abs_match) { + dbg_inc(DBG_ABS_MISS); + return 0; + } + dbg_inc(DBG_ABS_HIT); + } else { + if (!check_relative_path(dirfd, path)) return 0; } + if (do_probability_check()) return 0; + data.ppid = ppid; - data.pid = pid; data.tid = tid; + data.tgid = tgid; data.id = gid; // Get command name @@ -112,9 +395,7 @@ int injection_disk_failure(struct pt_regs *ctx) // Add the event to the ring buffer bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &data, 100); - // Override return of process with an -ENOENT error. - bpf_override_return(ctx, -exit_code); + printt("disk-failure: disrupted tgid=%d rc=-%d\n", tgid, (int)exit_code); - return 0; + return -(int)exit_code; } - diff --git a/ebpf/disk-failure/main.go b/ebpf/disk-failure/main.go index 40defe5681..9f2bd05e44 100644 --- a/ebpf/disk-failure/main.go +++ b/ebpf/disk-failure/main.go @@ -10,20 +10,28 @@ package main import ( "C" + "bufio" "bytes" "encoding/binary" "flag" "os" "os/signal" + "syscall" + "time" + "unsafe" - "github.com/DataDog/chaos-controller/ebpf" "github.com/DataDog/chaos-controller/log" bpf "github.com/aquasecurity/libbpfgo" - "github.com/aquasecurity/libbpfgo/helpers" "go.uber.org/zap" ) var nPid = flag.Uint64("process", 0, "Process to disrupt") +var nCgroupPath = flag.String("cgroup-path", "", "Cgroupv2 directory path for ancestor-based filtering (covers kubectl exec sub-cgroups)") +var nNetnsIno = flag.Uint64("netns-ino", 0, "Network namespace inode of the target container; catches kubectl exec sessions that are not PID-tree descendants of container init") +var nFilterDirInode = flag.Uint64("filter-dir-inode", 0, "Inode of filter path parent directory; enables relative-path disruption (e.g. after cd+cat)") +var nFilterDirDev = flag.Uint64("filter-dir-dev", 0, "Device ID of filter path parent directory; disambiguates same-inode numbers across different mounts") +var nFilterDirInode2 = flag.Uint64("filter-dir-inode2", 0, "Inode of filter path itself when it is a directory; enables exact-CWD match for relative opens") +var nFilterDirDev2 = flag.Uint64("filter-dir-dev2", 0, "Device ID paired with filter-dir-inode2") var nPath = flag.String("path", "/", "Filter path") var nProbability = flag.Uint64("probability", 100, "Probability to disrupt") var nExitCode = flag.Uint64("exit-code", 1, "Exit code") @@ -64,16 +72,26 @@ func main() { err = bpfModule.BPFLoadObject() must(err) - // reads data from the trace pipe that bpf_trace_printk() writes to, - // (/sys/kernel/debug/tracing/trace_pipe). - go helpers.TracePipeListen() + // Populate cgroup filter map after loading (maps are only accessible post-load). + if *nCgroupPath != "" { + initCgroupMap(bpfModule) + } + + // Forward bpf_trace_printk() output to the zap logger so it appears in kubectl logs. + // The chaos pod mounts /sys/kernel/debug/tracing at /mnt/tracefs so the container + // rootfs has a valid target path. TracePipeListen() uses a hardcoded non-existent + // path, so we read trace_pipe directly here instead. + go listenTracePipe(logger) + + // Log debug_counters map every 10 s so path filter behaviour is visible in + // kubectl logs even when tracefs is unavailable (e.g. blocked by node policy). + go logDebugCounters(bpfModule, logger) // Load the BPF program prog, err := bpfModule.GetProgram("injection_disk_failure") must(err) - // Attach the kprope to catch sys openat syscall - _, err = prog.AttachKprobe(ebpf.SysOpenat) + _, err = prog.AttachGeneric() must(err) // Create the ring buffer to store events @@ -97,25 +115,61 @@ func main() { func printEvent(data []byte) { ppid := int(binary.LittleEndian.Uint32(data[0:4])) - pid := int(binary.LittleEndian.Uint32(data[4:8])) - tid := int(binary.LittleEndian.Uint32(data[8:12])) + // tid = kernel TID (userspace thread ID via gettid()) + tid := int(binary.LittleEndian.Uint32(data[4:8])) + // tgid = kernel TGID (userspace process ID via getpid()) — use this to identify the process in ps/kubectl + tgid := int(binary.LittleEndian.Uint32(data[8:12])) gid := int(binary.LittleEndian.Uint32(data[12:16])) comm := string(bytes.TrimRight(data[16:], "\x00")) - logger.Infof("Disrupt Ppid %d, Pid %d, Tid: %d, Gid: %d, Command: %s", ppid, pid, tid, gid, comm) + logger.Infof("Disrupt Ppid(host) %d, Tgid(host-pid) %d, Tid %d, Gid: %d, Command: %s", ppid, tgid, tid, gid, comm) } -// The global variables are shared against the userspace application and the BPF application (loaded into the kernel). -// This global variables allow the user application to parametrise the BPF application. +// initGlobalVariables sets BPF global variables from command-line flags. func initGlobalVariables(bpfModule *bpf.Module) { flag.Parse() - // Set the PID var pid uint32 pid = uint32(*nPid) if err := bpfModule.InitGlobalVariable("target_pid", pid); err != nil { must(err) } + // Enable cgroup-based filtering when a cgroup path is provided. + var useCgroupFilter int32 + if *nCgroupPath != "" { + useCgroupFilter = 1 + } + if err := bpfModule.InitGlobalVariable("use_cgroup_filter", useCgroupFilter); err != nil { + must(err) + } + + netnsIno := *nNetnsIno + if err := bpfModule.InitGlobalVariable("target_netns_ino", netnsIno); err != nil { + must(err) + } + + // Filter directory inode for relative-path disruption. + filterDirInode := *nFilterDirInode + if err := bpfModule.InitGlobalVariable("filter_dir_inode", filterDirInode); err != nil { + must(err) + } + + // Filter directory device ID — disambiguates same-inode numbers across mounts. + filterDirDev := uint32(*nFilterDirDev) + if err := bpfModule.InitGlobalVariable("filter_dir_dev", filterDirDev); err != nil { + must(err) + } + + // Second inode/device for exact-CWD matching when filter path is a directory. + filterDirInode2 := *nFilterDirInode2 + if err := bpfModule.InitGlobalVariable("filter_dir_inode2", filterDirInode2); err != nil { + must(err) + } + filterDirDev2 := uint32(*nFilterDirDev2) + if err := bpfModule.InitGlobalVariable("filter_dir_dev2", filterDirDev2); err != nil { + must(err) + } + path := []byte(*nPath) if err := bpfModule.InitGlobalVariable("filter_path", path); err != nil { must(err) @@ -139,6 +193,68 @@ func initGlobalVariables(bpfModule *bpf.Module) { } } +// initCgroupMap opens the cgroupv2 directory and pins its fd into the target_cgroup +// BPF_MAP_TYPE_CGROUP_ARRAY so the eBPF program can use bpf_current_task_under_cgroup(). +func initCgroupMap(bpfModule *bpf.Module) { + fd, err := syscall.Open(*nCgroupPath, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_CLOEXEC, 0) + must(err) + defer syscall.Close(fd) + + cgroupMap, err := bpfModule.GetMap("target_cgroup") + must(err) + + key := uint32(0) + fdUint := uint32(fd) + must(cgroupMap.Update(unsafe.Pointer(&key), unsafe.Pointer(&fdUint))) +} + +// listenTracePipe reads bpf_trace_printk() output from the tracefs trace pipe and +// forwards each line through the zap logger so it appears in kubectl logs. +// The chaos pod mounts /sys/kernel/debug/tracing at /mnt/tracefs; if the mount is +// absent (e.g. older deployments) the function logs a warning and returns. +func listenTracePipe(log *zap.SugaredLogger) { + f, err := os.Open("/mnt/tracefs/trace_pipe") + if err != nil { + log.Warnw("trace pipe unavailable; bpf_trace_printk output will not appear in pod logs", "err", err) + return + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + log.Infow("bpf trace", "line", scanner.Text()) + } +} + +// logDebugCounters reads the debug_counters BPF map every 10 s and logs the +// values so path filter behaviour is observable via kubectl logs even when +// tracefs is unavailable (blocked by node security policy). +func logDebugCounters(bpfModule *bpf.Module, log *zap.SugaredLogger) { + m, err := bpfModule.GetMap("debug_counters") + if err != nil { + log.Warnw("debug_counters map unavailable", "err", err) + return + } + + names := []string{"abs_hit", "abs_miss", "rel_no_filter", "rel_hit", "rel_miss", "rel_ino_match", "rel_null_fd", "cgroup_hit", "cgroup_miss", "cgroup_err", "netns_hit", "netns_miss"} + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + + for range ticker.C { + for idx, name := range names { + key := uint32(idx) + val, err := m.GetValue(unsafe.Pointer(&key)) + if err != nil { + continue + } + count := binary.LittleEndian.Uint64(val) + if count > 0 { + log.Infow("path filter counter", "counter", name, "count", count) + } + } + } +} + func must(err error) { if err != nil { panic(err) diff --git a/go.mod b/go.mod index 820098593b..83e13378d7 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( github.com/DataDog/datadog-go v4.8.3+incompatible github.com/DataDog/jsonapi v0.13.0 github.com/aquasecurity/libbpfgo v0.5.1-libbpf-1.2 - github.com/aquasecurity/libbpfgo/helpers v0.4.5 github.com/avast/retry-go v3.0.0+incompatible github.com/cenkalti/backoff v2.2.1+incompatible github.com/containerd/containerd v1.7.30 diff --git a/go.sum b/go.sum index 97920415f1..d04d9854b8 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,6 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63n github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/aquasecurity/libbpfgo v0.5.1-libbpf-1.2 h1:Y7QB6jUsMyr0Bd+rAj67X2/ezNYLuxwp3kkjw5M3Q+4= github.com/aquasecurity/libbpfgo v0.5.1-libbpf-1.2/go.mod h1:0rEApF1YBHGuZ4C8OYI9q5oDBVpgqtRqYATePl9mCDk= -github.com/aquasecurity/libbpfgo/helpers v0.4.5 h1:eCoLclL3yqv4N9jqGL3T/ckrLPms2r13C4V2xtU75yc= -github.com/aquasecurity/libbpfgo/helpers v0.4.5/go.mod h1:j/TQLmsZpOIdF3CnJODzYngG4yu1YoDCoRMELxkQSSA= github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= diff --git a/injector/disk_failure.go b/injector/disk_failure.go index c2b076594f..be4d1a699d 100644 --- a/injector/disk_failure.go +++ b/injector/disk_failure.go @@ -8,8 +8,10 @@ package injector import ( "context" "fmt" + "path/filepath" "strconv" "strings" + "syscall" "github.com/DataDog/chaos-controller/api/v1beta1" "github.com/DataDog/chaos-controller/command" @@ -29,6 +31,9 @@ type DiskFailureInjectorConfig struct { CmdFactory command.Factory ProcessManager process.Manager BPFConfigInformer ebpf.ConfigInformer + // ProcRoot is the root of the proc filesystem used to resolve container paths + // (default "/proc"). Override in tests to avoid host-dependent /proc reads. + ProcRoot string } const EBPFDiskFailureCmd = "bpf-disk-failure" @@ -71,13 +76,40 @@ func (i *DiskFailureInjector) Inject() error { return fmt.Errorf("the disk failure needs a kernel supporting eBPF programs: %w", err) } - if !i.config.BPFConfigInformer.GetMapTypes().HavePerfEventArrayMapType { + mapTypes := i.config.BPFConfigInformer.GetMapTypes() + + if !mapTypes.HavePerfEventArrayMapType { return fmt.Errorf("the disk failure needs the perf event array map type, but the current kernel does not support this type of map") } pid := 0 + cgroupPath := "" + if i.config.Disruption.Level == types.DisruptionLevelPod { pid = int(i.config.TargetContainer.PID()) + + if i.config.Cgroup != nil { + cgroupPath = i.config.Cgroup.CgroupV2Path() + } + } + + // cgroupv2 filter is optional: only required when a cgroup path is available. + // On cgroupv1 clusters (or when the path can't be resolved) we fall back to the + // PID-based filter which covers direct children of the container init process. + if cgroupPath != "" && !mapTypes.HaveCgroupArrayMapType { + return fmt.Errorf("cgroupv2 filter requested but kernel lacks BPF_MAP_TYPE_CGROUP_ARRAY support") + } + + // Verify the cgroup path is actually accessible before passing it to the eBPF + // program. If not (e.g. the container restarted and the old cgroup directory is + // gone), fall back to PID-based filtering rather than loading a stale FD into + // BPF_MAP_TYPE_CGROUP_ARRAY, which would silently filter nothing. + if cgroupPath != "" { + var cgroupStat syscall.Stat_t + if err := syscall.Stat(cgroupPath, &cgroupStat); err != nil { + i.config.Log.Warnw("cgroupv2 path not accessible, falling back to PID filter", "cgroupPath", cgroupPath, "pid", pid) + cgroupPath = "" + } } exitCode := 0 @@ -89,6 +121,54 @@ func (i *DiskFailureInjector) Inject() error { for _, path := range i.spec.Paths { args := []string{"-process", strconv.Itoa(pid)} + if cgroupPath != "" { + args = append(args, "-cgroup-path", cgroupPath) + } + + if pid != 0 { + procRoot := i.config.ProcRoot + if procRoot == "" { + procRoot = "/proc" + } + + // Pass the network namespace inode so the BPF program can reliably + // identify all container processes — including those started via + // kubectl exec, which are not descendants of the container init. + netnsPath := fmt.Sprintf("%s/%d/ns/net", procRoot, pid) + var netnsStat syscall.Stat_t + if err := syscall.Stat(netnsPath, &netnsStat); err == nil { + args = append(args, "-netns-ino", strconv.FormatUint(netnsStat.Ino, 10)) + } else { + i.config.Log.Warnw("could not stat netns, netns-based filtering disabled", "netnsPath", netnsPath, "err", err) + } + + // Resolve the filter directory's inode so the eBPF program can handle relative + // paths (e.g. "cd /mnt/data && cat disk-read-file"). We stat the directory inside + // the target container's filesystem via //root/. + if path != "" { + // Always pass the parent directory inode for the basename-prefix check + // (e.g. "cwd=/parent && openat(AT_FDCWD, 'dir/file')"). + parentPath := filepath.Dir(path) + containerParentPath := fmt.Sprintf("%s/%d/root%s", procRoot, pid, parentPath) + + var stParent syscall.Stat_t + if err := syscall.Stat(containerParentPath, &stParent); err == nil { + args = append(args, "-filter-dir-inode", strconv.FormatUint(stParent.Ino, 10)) + args = append(args, "-filter-dir-dev", strconv.FormatUint(uint64(devToKernel(&stParent)), 10)) + } + + // When path is itself a directory, also pass its own inode for the exact-CWD + // check (e.g. "cwd=/mnt/data && openat(AT_FDCWD, 'file')"). + containerPath := fmt.Sprintf("%s/%d/root%s", procRoot, pid, path) + + var stPath syscall.Stat_t + if err := syscall.Stat(containerPath, &stPath); err == nil && (stPath.Mode&syscall.S_IFMT) == syscall.S_IFDIR { + args = append(args, "-filter-dir-inode2", strconv.FormatUint(stPath.Ino, 10)) + args = append(args, "-filter-dir-dev2", strconv.FormatUint(uint64(devToKernel(&stPath)), 10)) + } + } + } + if path != "" { args = append(args, "-path", path) } @@ -99,6 +179,8 @@ func (i *DiskFailureInjector) Inject() error { args = append(args, "-probability", strings.TrimSuffix(i.spec.Probability, "%")) + i.config.Log.Infow("starting bpf-disk-failure", "path", path, "pid", pid, "cgroupPath", cgroupPath, "exitCode", exitCode, "args", args) + cmd := i.config.CmdFactory.NewCmd(context.Background(), EBPFDiskFailureCmd, args) bgCmd := command.NewBackgroundCmd(cmd, i.config.Log, i.config.ProcessManager) diff --git a/injector/disk_failure_dev_linux.go b/injector/disk_failure_dev_linux.go new file mode 100644 index 0000000000..aa9a07a262 --- /dev/null +++ b/injector/disk_failure_dev_linux.go @@ -0,0 +1,20 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2026 Datadog, Inc. + +package injector + +import "syscall" + +// devToKernel converts a userspace st_dev (glibc encode_dev encoding) to the +// kernel dev_t value (MKDEV: major<<20 | minor) stored in super_block.s_dev. +// The BPF filter_dir_dev variables are compared against s_dev, so the injector +// must pass the kernel-encoded value, not the raw st_dev. +func devToKernel(st *syscall.Stat_t) uint32 { + d := st.Dev + major := uint32((d&0x00000000000fff00)>>8) | uint32((d&0xfffff00000000000)>>32) + minor := uint32((d&0x00000000000000ff)>>0) | uint32((d&0x00000ffffff00000)>>12) + + return (major << 20) | minor +} diff --git a/ebpf/const-arm.go b/injector/disk_failure_dev_other.go similarity index 52% rename from ebpf/const-arm.go rename to injector/disk_failure_dev_other.go index 10c4318297..81aec47b13 100644 --- a/ebpf/const-arm.go +++ b/injector/disk_failure_dev_other.go @@ -3,9 +3,14 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2026 Datadog, Inc. -//go:build arm64 -// +build arm64 +//go:build !linux -package ebpf +package injector -const SysOpenat = "__arm64_sys_openat" +import "syscall" + +// devToKernel is a no-op stub on non-Linux platforms where the eBPF injector +// does not run. +func devToKernel(st *syscall.Stat_t) uint32 { + return uint32(st.Dev) +} diff --git a/injector/disk_failure_test.go b/injector/disk_failure_test.go index 52df8a794a..07998a77db 100644 --- a/injector/disk_failure_test.go +++ b/injector/disk_failure_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/chaos-controller/api" "github.com/DataDog/chaos-controller/api/v1beta1" + "github.com/DataDog/chaos-controller/cgroup" "github.com/DataDog/chaos-controller/command" "github.com/DataDog/chaos-controller/container" "github.com/DataDog/chaos-controller/ebpf" @@ -33,6 +34,7 @@ var _ = Describe("Disk Failure", func() { cmdFactoryMock *command.FactoryMock containerMock *container.ContainerMock BPFConfigInformerMock *ebpf.ConfigInformerMock + cgroupManagerMock *cgroup.ManagerMock ) const PID = 1 @@ -41,10 +43,11 @@ var _ = Describe("Disk Failure", func() { proc = &os.Process{Pid: PID} containerMock = container.NewContainerMock(GinkgoT()) + cgroupManagerMock = cgroup.NewManagerMock(GinkgoT()) BPFConfigInformerMock = ebpf.NewConfigInformerMock(GinkgoT()) BPFConfigInformerMock.EXPECT().ValidateRequiredSystemConfig().Return(nil).Maybe() - BPFConfigInformerMock.EXPECT().GetMapTypes().Return(ebpf.MapTypes{HavePerfEventArrayMapType: true}).Maybe() + BPFConfigInformerMock.EXPECT().GetMapTypes().Return(ebpf.MapTypes{HavePerfEventArrayMapType: true, HaveCgroupArrayMapType: true}).Maybe() cmd := command.NewCmdMock(GinkgoT()) cmd.EXPECT().DryRun().Return(false).Maybe() @@ -58,6 +61,9 @@ var _ = Describe("Disk Failure", func() { config = DiskFailureInjectorConfig{ BPFConfigInformer: BPFConfigInformerMock, CmdFactory: cmdFactoryMock, + // Point ProcRoot at a nonexistent path so syscall.Stat always fails and + // no host-dependent -filter-dir-* flags are appended during tests. + ProcRoot: "/nonexistent-proc", Config: Config{ Log: log, MetricsSink: ms, @@ -102,29 +108,8 @@ var _ = Describe("Disk Failure", func() { BPFConfigInformerMock = ebpf.NewConfigInformerMock(GinkgoT()) BPFConfigInformerMock.EXPECT().ValidateRequiredSystemConfig().Return(nil).Once() BPFConfigInformerMock.EXPECT().GetMapTypes().Return(ebpf.MapTypes{ - HaveHashMapType: true, - HaveArrayMapType: true, - HaveProgArrayMapType: true, - HavePerfEventArrayMapType: false, - HavePercpuHashMapType: true, - HavePercpuArrayMapType: true, - HaveStackTraceMapType: true, - HaveCgroupArrayMapType: true, - HaveLruHashMapType: true, - HaveLruPercpuHashMapType: true, - HaveLpmTrieMapType: true, - HaveArrayOfMapsMapType: true, - HaveHashOfMapsMapType: true, - HaveDevmapMapType: true, - HaveSockmapMapType: true, - HaveCpumapMapType: true, - HaveXskmapMapType: true, - HaveSockhashMapType: true, - HaveCgroupStorageMapType: true, - HaveReuseportSockarrayMapType: true, - HavePercpuCgroupStorageMapType: true, - HaveQueueMapType: true, - HaveStackMapType: true, + HavePerfEventArrayMapType: false, + HaveCgroupArrayMapType: true, }) config.BPFConfigInformer = BPFConfigInformerMock }) @@ -134,6 +119,28 @@ var _ = Describe("Disk Failure", func() { Expect(err).To(MatchError("the disk failure needs the perf event array map type, but the current kernel does not support this type of map")) }) }) + + When("the bpf map type cgroup array is not supported but cgroupv2 path is requested", func() { + BeforeEach(func() { + BPFConfigInformerMock = ebpf.NewConfigInformerMock(GinkgoT()) + BPFConfigInformerMock.EXPECT().ValidateRequiredSystemConfig().Return(nil).Once() + BPFConfigInformerMock.EXPECT().GetMapTypes().Return(ebpf.MapTypes{ + HavePerfEventArrayMapType: true, + HaveCgroupArrayMapType: false, + }) + config.BPFConfigInformer = BPFConfigInformerMock + // cgroupv2 path is needed to trigger the cgroup array map requirement + config.Disruption.Level = types.DisruptionLevelPod + containerMock.EXPECT().PID().Return(PID).Once() + cgroupManagerMock.EXPECT().CgroupV2Path().Return(GinkgoT().TempDir()).Once() + config.Config.Cgroup = cgroupManagerMock + }) + + It("should return an error", func() { + Expect(err).Should(HaveOccurred()) + Expect(err).To(MatchError("cgroupv2 filter requested but kernel lacks BPF_MAP_TYPE_CGROUP_ARRAY support")) + }) + }) }) Describe("success cases", func() { @@ -223,6 +230,62 @@ var _ = Describe("Disk Failure", func() { }) }) }) + + Context("with cgroupv2 enabled", func() { + var cgroupPathValue string + + BeforeEach(func() { + // Use a real directory so the syscall.Stat existence check passes. + cgroupPathValue = GinkgoT().TempDir() + cgroupManagerMock.EXPECT().CgroupV2Path().Return(cgroupPathValue).Once() + config.Config.Cgroup = cgroupManagerMock + }) + + It("should pass -cgroup-path flag to the eBPF program", func() { + Expect(err).ShouldNot(HaveOccurred()) + + cmdFactoryMock.AssertCalled(GinkgoT(), "NewCmd", mock.Anything, EBPFDiskFailureCmd, []string{ + "-process", strconv.Itoa(proc.Pid), + "-cgroup-path", cgroupPathValue, + "-path", "/", + "-probability", "100", + }) + }) + }) + + Context("with cgroupv1 (CgroupV2Path returns empty)", func() { + BeforeEach(func() { + cgroupManagerMock.EXPECT().CgroupV2Path().Return("").Once() + config.Config.Cgroup = cgroupManagerMock + }) + + It("should not pass -cgroup-path flag", func() { + Expect(err).ShouldNot(HaveOccurred()) + + cmdFactoryMock.AssertCalled(GinkgoT(), "NewCmd", mock.Anything, EBPFDiskFailureCmd, []string{ + "-process", strconv.Itoa(proc.Pid), + "-path", "/", + "-probability", "100", + }) + }) + }) + + Context("with a stale cgroupv2 path (directory no longer exists)", func() { + BeforeEach(func() { + cgroupManagerMock.EXPECT().CgroupV2Path().Return("/nonexistent/cgroup/path").Once() + config.Config.Cgroup = cgroupManagerMock + }) + + It("should fall back to PID-based filter without -cgroup-path", func() { + Expect(err).ShouldNot(HaveOccurred()) + + cmdFactoryMock.AssertCalled(GinkgoT(), "NewCmd", mock.Anything, EBPFDiskFailureCmd, []string{ + "-process", strconv.Itoa(proc.Pid), + "-path", "/", + "-probability", "100", + }) + }) + }) }) Context("with a node level", func() { diff --git a/services/chaospod.go b/services/chaospod.go index af9f0cda9c..113d65a382 100644 --- a/services/chaospod.go +++ b/services/chaospod.go @@ -585,6 +585,13 @@ func (m *chaosPodService) generateChaosPodSpec(targetNodeName string, terminatio MountPath: "/boot", ReadOnly: true, }, + { + // /sys/kernel/debug/tracing doesn't exist in the container rootfs so + // runc cannot create the bind-mount target there. Mount under /mnt + // where the directory can be created by the container runtime. + Name: "tracefs", + MountPath: "/mnt/tracefs", + }, }, }, }, @@ -652,6 +659,18 @@ func (m *chaosPodService) generateChaosPodSpec(targetNodeName string, terminatio }, }, }, + { + // tracefs is required for bpf_trace_printk() output to reach the pod's + // stdout via TracePipeListen(). Without this mount the trace pipe open + // fails silently and no bpf_trace_printk log lines appear in kubectl logs. + Name: "tracefs", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/sys/kernel/debug/tracing", + Type: &hostPathDirectory, + }, + }, + }, }, } diff --git a/vendor/github.com/aquasecurity/libbpfgo/helpers/LICENSE b/vendor/github.com/aquasecurity/libbpfgo/helpers/LICENSE deleted file mode 100644 index d645695673..0000000000 --- a/vendor/github.com/aquasecurity/libbpfgo/helpers/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/aquasecurity/libbpfgo/helpers/argumentParsers.go b/vendor/github.com/aquasecurity/libbpfgo/helpers/argumentParsers.go deleted file mode 100644 index a33e3277a7..0000000000 --- a/vendor/github.com/aquasecurity/libbpfgo/helpers/argumentParsers.go +++ /dev/null @@ -1,1950 +0,0 @@ -package helpers - -import ( - "encoding/binary" - "fmt" - "golang.org/x/sys/unix" - "net" - "strconv" - "strings" -) - -type SystemFunctionArgument interface { - fmt.Stringer - Value() uint64 -} - -// OptionAreContainedInArgument checks whether the argument (rawArgument) -// contains all of the 'options' such as with flags passed to the clone flag. -// This function takes an arbitrary number of SystemCallArguments.It will -// only return true if each and every option is present in rawArgument. -// Typically linux syscalls have multiple options specified in a single -// argument via bitmasks = which this function checks for. -func OptionAreContainedInArgument(rawArgument uint64, options ...SystemFunctionArgument) bool { - var isPresent = true - for _, option := range options { - isPresent = isPresent && (option.Value()&rawArgument == option.Value()) - } - return isPresent -} - -type CloneFlagArgument struct { - rawValue uint64 - stringValue string -} - -var ( - // These values are copied from uapi/linux/sched.h - CLONE_VM CloneFlagArgument = CloneFlagArgument{rawValue: 0x00000100, stringValue: "CLONE_VM"} - CLONE_FS CloneFlagArgument = CloneFlagArgument{rawValue: 0x00000200, stringValue: "CLONE_FS"} - CLONE_FILES CloneFlagArgument = CloneFlagArgument{rawValue: 0x00000400, stringValue: "CLONE_FILES"} - CLONE_SIGHAND CloneFlagArgument = CloneFlagArgument{rawValue: 0x00000800, stringValue: "CLONE_SIGHAND"} - CLONE_PIDFD CloneFlagArgument = CloneFlagArgument{rawValue: 0x00001000, stringValue: "CLONE_PIDFD"} - CLONE_PTRACE CloneFlagArgument = CloneFlagArgument{rawValue: 0x00002000, stringValue: "CLONE_PTRACE"} - CLONE_VFORK CloneFlagArgument = CloneFlagArgument{rawValue: 0x00004000, stringValue: "CLONE_VFORK"} - CLONE_PARENT CloneFlagArgument = CloneFlagArgument{rawValue: 0x00008000, stringValue: "CLONE_PARENT"} - CLONE_THREAD CloneFlagArgument = CloneFlagArgument{rawValue: 0x00010000, stringValue: "CLONE_THREAD"} - CLONE_NEWNS CloneFlagArgument = CloneFlagArgument{rawValue: 0x00020000, stringValue: "CLONE_NEWNS"} - CLONE_SYSVSEM CloneFlagArgument = CloneFlagArgument{rawValue: 0x00040000, stringValue: "CLONE_SYSVSEM"} - CLONE_SETTLS CloneFlagArgument = CloneFlagArgument{rawValue: 0x00080000, stringValue: "CLONE_SETTLS"} - CLONE_PARENT_SETTID CloneFlagArgument = CloneFlagArgument{rawValue: 0x00100000, stringValue: "CLONE_PARENT_SETTID"} - CLONE_CHILD_CLEARTID CloneFlagArgument = CloneFlagArgument{rawValue: 0x00200000, stringValue: "CLONE_CHILD_CLEARTID"} - CLONE_DETACHED CloneFlagArgument = CloneFlagArgument{rawValue: 0x00400000, stringValue: "CLONE_DETACHED"} - CLONE_UNTRACED CloneFlagArgument = CloneFlagArgument{rawValue: 0x00800000, stringValue: "CLONE_UNTRACED"} - CLONE_CHILD_SETTID CloneFlagArgument = CloneFlagArgument{rawValue: 0x01000000, stringValue: "CLONE_CHILD_SETTID"} - CLONE_NEWCGROUP CloneFlagArgument = CloneFlagArgument{rawValue: 0x02000000, stringValue: "CLONE_NEWCGROUP"} - CLONE_NEWUTS CloneFlagArgument = CloneFlagArgument{rawValue: 0x04000000, stringValue: "CLONE_NEWUTS"} - CLONE_NEWIPC CloneFlagArgument = CloneFlagArgument{rawValue: 0x08000000, stringValue: "CLONE_NEWIPC"} - CLONE_NEWUSER CloneFlagArgument = CloneFlagArgument{rawValue: 0x10000000, stringValue: "CLONE_NEWUSER"} - CLONE_NEWPID CloneFlagArgument = CloneFlagArgument{rawValue: 0x20000000, stringValue: "CLONE_NEWPID"} - CLONE_NEWNET CloneFlagArgument = CloneFlagArgument{rawValue: 0x40000000, stringValue: "CLONE_NEWNET"} - CLONE_IO CloneFlagArgument = CloneFlagArgument{rawValue: 0x80000000, stringValue: "CLONE_IO"} -) - -func (c CloneFlagArgument) Value() uint64 { return c.rawValue } -func (c CloneFlagArgument) String() string { return c.stringValue } - -func ParseCloneFlags(rawValue uint64) (CloneFlagArgument, error) { - - if rawValue == 0 { - return CloneFlagArgument{}, nil - } - - var f []string - if OptionAreContainedInArgument(rawValue, CLONE_VM) { - f = append(f, CLONE_VM.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_FS) { - f = append(f, CLONE_FS.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_FILES) { - f = append(f, CLONE_FILES.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_SIGHAND) { - f = append(f, CLONE_SIGHAND.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_PIDFD) { - f = append(f, CLONE_PIDFD.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_PTRACE) { - f = append(f, CLONE_PTRACE.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_VFORK) { - f = append(f, CLONE_VFORK.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_PARENT) { - f = append(f, CLONE_PARENT.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_THREAD) { - f = append(f, CLONE_THREAD.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_NEWNS) { - f = append(f, CLONE_NEWNS.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_SYSVSEM) { - f = append(f, CLONE_SYSVSEM.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_SETTLS) { - f = append(f, CLONE_SETTLS.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_PARENT_SETTID) { - f = append(f, CLONE_PARENT_SETTID.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_CHILD_CLEARTID) { - f = append(f, CLONE_CHILD_CLEARTID.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_DETACHED) { - f = append(f, CLONE_DETACHED.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_UNTRACED) { - f = append(f, CLONE_UNTRACED.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_CHILD_SETTID) { - f = append(f, CLONE_CHILD_SETTID.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_NEWCGROUP) { - f = append(f, CLONE_NEWCGROUP.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_NEWUTS) { - f = append(f, CLONE_NEWUTS.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_NEWIPC) { - f = append(f, CLONE_NEWIPC.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_NEWUSER) { - f = append(f, CLONE_NEWUSER.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_NEWPID) { - f = append(f, CLONE_NEWPID.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_NEWNET) { - f = append(f, CLONE_NEWNET.String()) - } - if OptionAreContainedInArgument(rawValue, CLONE_IO) { - f = append(f, CLONE_IO.String()) - } - if len(f) == 0 { - return CloneFlagArgument{}, fmt.Errorf("no valid clone flag values present in raw value: 0x%x", rawValue) - } - - return CloneFlagArgument{stringValue: strings.Join(f, "|"), rawValue: rawValue}, nil -} - -type OpenFlagArgument struct { - rawValue uint64 - stringValue string -} - -var ( - // These values are copied from uapi/asm-generic/fcntl.h - O_ACCMODE OpenFlagArgument = OpenFlagArgument{rawValue: 00000003, stringValue: "O_ACCMODE"} - O_RDONLY OpenFlagArgument = OpenFlagArgument{rawValue: 00000000, stringValue: "O_RDONLY"} - O_WRONLY OpenFlagArgument = OpenFlagArgument{rawValue: 00000001, stringValue: "O_WRONLY"} - O_RDWR OpenFlagArgument = OpenFlagArgument{rawValue: 00000002, stringValue: "O_RDWR"} - O_CREAT OpenFlagArgument = OpenFlagArgument{rawValue: 00000100, stringValue: "O_CREAT"} - O_EXCL OpenFlagArgument = OpenFlagArgument{rawValue: 00000200, stringValue: "O_EXCL"} - O_NOCTTY OpenFlagArgument = OpenFlagArgument{rawValue: 00000400, stringValue: "O_NOCTTY"} - O_TRUNC OpenFlagArgument = OpenFlagArgument{rawValue: 00001000, stringValue: "O_TRUNC"} - O_APPEND OpenFlagArgument = OpenFlagArgument{rawValue: 00002000, stringValue: "O_APPEND"} - O_NONBLOCK OpenFlagArgument = OpenFlagArgument{rawValue: 00004000, stringValue: "O_NONBLOCK"} - O_DSYNC OpenFlagArgument = OpenFlagArgument{rawValue: 00010000, stringValue: "O_DSYNC"} - O_SYNC OpenFlagArgument = OpenFlagArgument{rawValue: 04010000, stringValue: "O_SYNC"} - FASYNC OpenFlagArgument = OpenFlagArgument{rawValue: 00020000, stringValue: "FASYNC"} - O_DIRECT OpenFlagArgument = OpenFlagArgument{rawValue: 00040000, stringValue: "O_DIRECT"} - O_LARGEFILE OpenFlagArgument = OpenFlagArgument{rawValue: 00100000, stringValue: "O_LARGEFILE"} - O_DIRECTORY OpenFlagArgument = OpenFlagArgument{rawValue: 00200000, stringValue: "O_DIRECTORY"} - O_NOFOLLOW OpenFlagArgument = OpenFlagArgument{rawValue: 00400000, stringValue: "O_NOFOLLOW"} - O_NOATIME OpenFlagArgument = OpenFlagArgument{rawValue: 01000000, stringValue: "O_NOATIME"} - O_CLOEXEC OpenFlagArgument = OpenFlagArgument{rawValue: 02000000, stringValue: "O_CLOEXEC"} - O_PATH OpenFlagArgument = OpenFlagArgument{rawValue: 040000000, stringValue: "O_PATH"} - O_TMPFILE OpenFlagArgument = OpenFlagArgument{rawValue: 020000000, stringValue: "O_TMPFILE"} -) - -func (o OpenFlagArgument) Value() uint64 { return o.rawValue } -func (o OpenFlagArgument) String() string { return o.stringValue } - -// ParseOpenFlagArgument parses the `flags` bitmask argument of the `open` syscall -// http://man7.org/linux/man-pages/man2/open.2.html -// https://elixir.bootlin.com/linux/v5.5.3/source/include/uapi/asm-generic/fcntl.h -func ParseOpenFlagArgument(rawValue uint64) (OpenFlagArgument, error) { - if rawValue == 0 { - return OpenFlagArgument{}, nil - } - var f []string - - // access mode - switch { - case OptionAreContainedInArgument(rawValue, O_WRONLY): - f = append(f, O_WRONLY.String()) - case OptionAreContainedInArgument(rawValue, O_RDWR): - f = append(f, O_RDWR.String()) - default: - f = append(f, O_RDONLY.String()) - } - - // file creation and status flags - if OptionAreContainedInArgument(rawValue, O_CREAT) { - f = append(f, O_CREAT.String()) - } - if OptionAreContainedInArgument(rawValue, O_EXCL) { - f = append(f, O_EXCL.String()) - } - if OptionAreContainedInArgument(rawValue, O_NOCTTY) { - f = append(f, O_NOCTTY.String()) - } - if OptionAreContainedInArgument(rawValue, O_TRUNC) { - f = append(f, O_TRUNC.String()) - } - if OptionAreContainedInArgument(rawValue, O_APPEND) { - f = append(f, O_APPEND.String()) - } - if OptionAreContainedInArgument(rawValue, O_NONBLOCK) { - f = append(f, O_NONBLOCK.String()) - } - if OptionAreContainedInArgument(rawValue, O_SYNC) { - f = append(f, O_SYNC.String()) - } - if OptionAreContainedInArgument(rawValue, FASYNC) { - f = append(f, FASYNC.String()) - } - if OptionAreContainedInArgument(rawValue, O_LARGEFILE) { - f = append(f, O_LARGEFILE.String()) - } - if OptionAreContainedInArgument(rawValue, O_DIRECTORY) { - f = append(f, O_DIRECTORY.String()) - } - if OptionAreContainedInArgument(rawValue, O_NOFOLLOW) { - f = append(f, O_NOFOLLOW.String()) - } - if OptionAreContainedInArgument(rawValue, O_CLOEXEC) { - f = append(f, O_CLOEXEC.String()) - } - if OptionAreContainedInArgument(rawValue, O_DIRECT) { - f = append(f, O_DIRECT.String()) - } - if OptionAreContainedInArgument(rawValue, O_NOATIME) { - f = append(f, O_NOATIME.String()) - } - if OptionAreContainedInArgument(rawValue, O_PATH) { - f = append(f, O_PATH.String()) - } - if OptionAreContainedInArgument(rawValue, O_TMPFILE) { - f = append(f, O_TMPFILE.String()) - } - - if len(f) == 0 { - return OpenFlagArgument{}, fmt.Errorf("no valid open flag values present in raw value: 0x%x", rawValue) - } - - return OpenFlagArgument{rawValue: rawValue, stringValue: strings.Join(f, "|")}, nil -} - -type AccessModeArgument struct { - rawValue uint64 - stringValue string -} - -var ( - F_OK AccessModeArgument = AccessModeArgument{rawValue: 0, stringValue: "F_OK"} - X_OK AccessModeArgument = AccessModeArgument{rawValue: 1, stringValue: "X_OK"} - W_OK AccessModeArgument = AccessModeArgument{rawValue: 2, stringValue: "W_OK"} - R_OK AccessModeArgument = AccessModeArgument{rawValue: 4, stringValue: "R_OK"} -) - -func (a AccessModeArgument) Value() uint64 { return a.rawValue } - -func (a AccessModeArgument) String() string { return a.stringValue } - -// ParseAccessMode parses the mode from the `access` system call -// http://man7.org/linux/man-pages/man2/access.2.html -func ParseAccessMode(rawValue uint64) (AccessModeArgument, error) { - if rawValue == 0 { - return AccessModeArgument{}, nil - } - var f []string - if rawValue == 0x0 { - f = append(f, F_OK.String()) - } else { - if OptionAreContainedInArgument(rawValue, R_OK) { - f = append(f, R_OK.String()) - } - if OptionAreContainedInArgument(rawValue, W_OK) { - f = append(f, W_OK.String()) - } - if OptionAreContainedInArgument(rawValue, X_OK) { - f = append(f, X_OK.String()) - } - } - - if len(f) == 0 { - return AccessModeArgument{}, fmt.Errorf("no valid access mode values present in raw value: 0x%x", rawValue) - } - - return AccessModeArgument{stringValue: strings.Join(f, "|"), rawValue: rawValue}, nil -} - -type ExecFlagArgument struct { - rawValue uint64 - stringValue string -} - -var ( - AT_SYMLINK_NOFOLLOW ExecFlagArgument = ExecFlagArgument{stringValue: "AT_SYMLINK_NOFOLLOW", rawValue: 0x100} - AT_EACCESS ExecFlagArgument = ExecFlagArgument{stringValue: "AT_EACCESS", rawValue: 0x200} - AT_REMOVEDIR ExecFlagArgument = ExecFlagArgument{stringValue: "AT_REMOVEDIR", rawValue: 0x200} - AT_SYMLINK_FOLLOW ExecFlagArgument = ExecFlagArgument{stringValue: "AT_SYMLINK_FOLLOW", rawValue: 0x400} - AT_NO_AUTOMOUNT ExecFlagArgument = ExecFlagArgument{stringValue: "AT_NO_AUTOMOUNT", rawValue: 0x800} - AT_EMPTY_PATH ExecFlagArgument = ExecFlagArgument{stringValue: "AT_EMPTY_PATH", rawValue: 0x1000} - AT_STATX_SYNC_TYPE ExecFlagArgument = ExecFlagArgument{stringValue: "AT_STATX_SYNC_TYPE", rawValue: 0x6000} - AT_STATX_SYNC_AS_STAT ExecFlagArgument = ExecFlagArgument{stringValue: "AT_STATX_SYNC_AS_STAT", rawValue: 0x0000} - AT_STATX_FORCE_SYNC ExecFlagArgument = ExecFlagArgument{stringValue: "AT_STATX_FORCE_SYNC", rawValue: 0x2000} - AT_STATX_DONT_SYNC ExecFlagArgument = ExecFlagArgument{stringValue: "AT_STATX_DONT_SYNC", rawValue: 0x4000} - AT_RECURSIVE ExecFlagArgument = ExecFlagArgument{stringValue: "AT_RECURSIVE", rawValue: 0x8000} -) - -func (e ExecFlagArgument) Value() uint64 { return e.rawValue } -func (e ExecFlagArgument) String() string { return e.stringValue } - -func ParseExecFlag(rawValue uint64) (ExecFlagArgument, error) { - - if rawValue == 0 { - return ExecFlagArgument{}, nil - } - - var f []string - if OptionAreContainedInArgument(rawValue, AT_EMPTY_PATH) { - f = append(f, AT_EMPTY_PATH.String()) - } - if OptionAreContainedInArgument(rawValue, AT_SYMLINK_NOFOLLOW) { - f = append(f, AT_SYMLINK_NOFOLLOW.String()) - } - if OptionAreContainedInArgument(rawValue, AT_EACCESS) { - f = append(f, AT_EACCESS.String()) - } - if OptionAreContainedInArgument(rawValue, AT_REMOVEDIR) { - f = append(f, AT_REMOVEDIR.String()) - } - if OptionAreContainedInArgument(rawValue, AT_NO_AUTOMOUNT) { - f = append(f, AT_NO_AUTOMOUNT.String()) - } - if OptionAreContainedInArgument(rawValue, AT_STATX_SYNC_TYPE) { - f = append(f, AT_STATX_SYNC_TYPE.String()) - } - if OptionAreContainedInArgument(rawValue, AT_STATX_FORCE_SYNC) { - f = append(f, AT_STATX_FORCE_SYNC.String()) - } - if OptionAreContainedInArgument(rawValue, AT_STATX_DONT_SYNC) { - f = append(f, AT_STATX_DONT_SYNC.String()) - } - if OptionAreContainedInArgument(rawValue, AT_RECURSIVE) { - f = append(f, AT_RECURSIVE.String()) - } - if len(f) == 0 { - return ExecFlagArgument{}, fmt.Errorf("no valid exec flag values present in raw value: 0x%x", rawValue) - } - return ExecFlagArgument{stringValue: strings.Join(f, "|"), rawValue: rawValue}, nil -} - -type CapabilityFlagArgument uint64 - -const ( - CAP_CHOWN CapabilityFlagArgument = iota - CAP_DAC_OVERRIDE - CAP_DAC_READ_SEARCH - CAP_FOWNER - CAP_FSETID - CAP_KILL - CAP_SETGID - CAP_SETUID - CAP_SETPCAP - CAP_LINUX_IMMUTABLE - CAP_NET_BIND_SERVICE - CAP_NET_BROADCAST - CAP_NET_ADMIN - CAP_NET_RAW - CAP_IPC_LOCK - CAP_IPC_OWNER - CAP_SYS_MODULE - CAP_SYS_RAWIO - CAP_SYS_CHROOT - CAP_SYS_PTRACE - CAP_SYS_PACCT - CAP_SYS_ADMIN - CAP_SYS_BOOT - CAP_SYS_NICE - CAP_SYS_RESOURCE - CAP_SYS_TIME - CAP_SYS_TTY_CONFIG - CAP_MKNOD - CAP_LEASE - CAP_AUDIT_WRITE - CAP_AUDIT_CONTROL - CAP_SETFCAP - CAP_MAC_OVERRIDE - CAP_MAC_ADMIN - CAP_SYSLOG - CAP_WAKE_ALARM - CAP_BLOCK_SUSPEND - CAP_AUDIT_READ -) - -func (c CapabilityFlagArgument) Value() uint64 { return uint64(c) } - -var capFlagStringMap = map[CapabilityFlagArgument]string{ - CAP_CHOWN: "CAP_CHOWN", - CAP_DAC_OVERRIDE: "CAP_DAC_OVERRIDE", - CAP_DAC_READ_SEARCH: "CAP_DAC_READ_SEARCH", - CAP_FOWNER: "CAP_FOWNER", - CAP_FSETID: "CAP_FSETID", - CAP_KILL: "CAP_KILL", - CAP_SETGID: "CAP_SETGID", - CAP_SETUID: "CAP_SETUID", - CAP_SETPCAP: "CAP_SETPCAP", - CAP_LINUX_IMMUTABLE: "CAP_LINUX_IMMUTABLE", - CAP_NET_BIND_SERVICE: "CAP_NET_BIND_SERVICE", - CAP_NET_BROADCAST: "CAP_NET_BROADCAST", - CAP_NET_ADMIN: "CAP_NET_ADMIN", - CAP_NET_RAW: "CAP_NET_RAW", - CAP_IPC_LOCK: "CAP_IPC_LOCK", - CAP_IPC_OWNER: "CAP_IPC_OWNER", - CAP_SYS_MODULE: "CAP_SYS_MODULE", - CAP_SYS_RAWIO: "CAP_SYS_RAWIO", - CAP_SYS_CHROOT: "CAP_SYS_CHROOT", - CAP_SYS_PTRACE: "CAP_SYS_PTRACE", - CAP_SYS_PACCT: "CAP_SYS_PACCT", - CAP_SYS_ADMIN: "CAP_SYS_ADMIN", - CAP_SYS_BOOT: "CAP_SYS_BOOT", - CAP_SYS_NICE: "CAP_SYS_NICE", - CAP_SYS_RESOURCE: "CAP_SYS_RESOURCE", - CAP_SYS_TIME: "CAP_SYS_TIME", - CAP_SYS_TTY_CONFIG: "CAP_SYS_TTY_CONFIG", - CAP_MKNOD: "CAP_MKNOD", - CAP_LEASE: "CAP_LEASE", - CAP_AUDIT_WRITE: "CAP_AUDIT_WRITE", - CAP_AUDIT_CONTROL: "CAP_AUDIT_CONTROL", - CAP_SETFCAP: "CAP_SETFCAP", - CAP_MAC_OVERRIDE: "CAP_MAC_OVERRIDE", - CAP_MAC_ADMIN: "CAP_MAC_ADMIN", - CAP_SYSLOG: "CAP_SYSLOG", - CAP_WAKE_ALARM: "CAP_WAKE_ALARM", - CAP_BLOCK_SUSPEND: "CAP_BLOCK_SUSPEND", - CAP_AUDIT_READ: "CAP_AUDIT_READ", -} - -func (c CapabilityFlagArgument) String() string { - var res string - - if capName, ok := capFlagStringMap[c]; ok { - res = capName - } else { - res = strconv.Itoa(int(c)) - } - return res -} - -var capabilitiesMap = map[uint64]CapabilityFlagArgument{ - CAP_CHOWN.Value(): CAP_CHOWN, - CAP_DAC_OVERRIDE.Value(): CAP_DAC_OVERRIDE, - CAP_DAC_READ_SEARCH.Value(): CAP_DAC_READ_SEARCH, - CAP_FOWNER.Value(): CAP_FOWNER, - CAP_FSETID.Value(): CAP_FSETID, - CAP_KILL.Value(): CAP_KILL, - CAP_SETGID.Value(): CAP_SETGID, - CAP_SETUID.Value(): CAP_SETUID, - CAP_SETPCAP.Value(): CAP_SETPCAP, - CAP_LINUX_IMMUTABLE.Value(): CAP_LINUX_IMMUTABLE, - CAP_NET_BIND_SERVICE.Value(): CAP_NET_BIND_SERVICE, - CAP_NET_BROADCAST.Value(): CAP_NET_BROADCAST, - CAP_NET_ADMIN.Value(): CAP_NET_ADMIN, - CAP_NET_RAW.Value(): CAP_NET_RAW, - CAP_IPC_LOCK.Value(): CAP_IPC_LOCK, - CAP_IPC_OWNER.Value(): CAP_IPC_OWNER, - CAP_SYS_MODULE.Value(): CAP_SYS_MODULE, - CAP_SYS_RAWIO.Value(): CAP_SYS_RAWIO, - CAP_SYS_CHROOT.Value(): CAP_SYS_CHROOT, - CAP_SYS_PTRACE.Value(): CAP_SYS_PTRACE, - CAP_SYS_PACCT.Value(): CAP_SYS_PACCT, - CAP_SYS_ADMIN.Value(): CAP_SYS_ADMIN, - CAP_SYS_BOOT.Value(): CAP_SYS_BOOT, - CAP_SYS_NICE.Value(): CAP_SYS_NICE, - CAP_SYS_RESOURCE.Value(): CAP_SYS_RESOURCE, - CAP_SYS_TIME.Value(): CAP_SYS_TIME, - CAP_SYS_TTY_CONFIG.Value(): CAP_SYS_TTY_CONFIG, - CAP_MKNOD.Value(): CAP_MKNOD, - CAP_LEASE.Value(): CAP_LEASE, - CAP_AUDIT_WRITE.Value(): CAP_AUDIT_WRITE, - CAP_AUDIT_CONTROL.Value(): CAP_AUDIT_CONTROL, - CAP_SETFCAP.Value(): CAP_SETFCAP, - CAP_MAC_OVERRIDE.Value(): CAP_MAC_OVERRIDE, - CAP_MAC_ADMIN.Value(): CAP_MAC_ADMIN, - CAP_SYSLOG.Value(): CAP_SYSLOG, - CAP_WAKE_ALARM.Value(): CAP_WAKE_ALARM, - CAP_BLOCK_SUSPEND.Value(): CAP_BLOCK_SUSPEND, - CAP_AUDIT_READ.Value(): CAP_AUDIT_READ, -} - -// ParseCapability parses the `capability` bitmask argument of the -// `cap_capable` function -func ParseCapability(rawValue uint64) (CapabilityFlagArgument, error) { - v, ok := capabilitiesMap[rawValue] - if !ok { - return 0, fmt.Errorf("not a valid capability value: %d", rawValue) - } - return v, nil -} - -type PrctlOptionArgument uint64 - -const ( - PR_SET_PDEATHSIG PrctlOptionArgument = iota + 1 - PR_GET_PDEATHSIG - PR_GET_DUMPABLE - PR_SET_DUMPABLE - PR_GET_UNALIGN - PR_SET_UNALIGN - PR_GET_KEEPCAPS - PR_SET_KEEPCAPS - PR_GET_FPEMU - PR_SET_FPEMU - PR_GET_FPEXC - PR_SET_FPEXC - PR_GET_TIMING - PR_SET_TIMING - PR_SET_NAME - PR_GET_NAME - PR_GET_ENDIAN - PR_SET_ENDIAN - PR_GET_SECCOMP - PR_SET_SECCOMP - PR_CAPBSET_READ - PR_CAPBSET_DROP - PR_GET_TSC - PR_SET_TSC - PR_GET_SECUREBITS - PR_SET_SECUREBITS - PR_SET_TIMERSLACK - PR_GET_TIMERSLACK - PR_TASK_PERF_EVENTS_DISABLE - PR_TASK_PERF_EVENTS_ENABLE - PR_MCE_KILL - PR_MCE_KILL_GET - PR_SET_MM - PR_SET_CHILD_SUBREAPER - PR_GET_CHILD_SUBREAPER - PR_SET_NO_NEW_PRIVS - PR_GET_NO_NEW_PRIVS - PR_GET_TID_ADDRESS - PR_SET_THP_DISABLE - PR_GET_THP_DISABLE - PR_MPX_ENABLE_MANAGEMENT - PR_MPX_DISABLE_MANAGEMENT - PR_SET_FP_MODE - PR_GET_FP_MODE - PR_CAP_AMBIENT - PR_SVE_SET_VL - PR_SVE_GET_VL - PR_GET_SPECULATION_CTRL - PR_SET_SPECULATION_CTRL - PR_PAC_RESET_KEYS - PR_SET_TAGGED_ADDR_CTRL - PR_GET_TAGGED_ADDR_CTRL -) - -func (p PrctlOptionArgument) Value() uint64 { return uint64(p) } - -var prctlOptionStringMap = map[PrctlOptionArgument]string{ - PR_SET_PDEATHSIG: "PR_SET_PDEATHSIG", - PR_GET_PDEATHSIG: "PR_GET_PDEATHSIG", - PR_GET_DUMPABLE: "PR_GET_DUMPABLE", - PR_SET_DUMPABLE: "PR_SET_DUMPABLE", - PR_GET_UNALIGN: "PR_GET_UNALIGN", - PR_SET_UNALIGN: "PR_SET_UNALIGN", - PR_GET_KEEPCAPS: "PR_GET_KEEPCAPS", - PR_SET_KEEPCAPS: "PR_SET_KEEPCAPS", - PR_GET_FPEMU: "PR_GET_FPEMU", - PR_SET_FPEMU: "PR_SET_FPEMU", - PR_GET_FPEXC: "PR_GET_FPEXC", - PR_SET_FPEXC: "PR_SET_FPEXC", - PR_GET_TIMING: "PR_GET_TIMING", - PR_SET_TIMING: "PR_SET_TIMING", - PR_SET_NAME: "PR_SET_NAME", - PR_GET_NAME: "PR_GET_NAME", - PR_GET_ENDIAN: "PR_GET_ENDIAN", - PR_SET_ENDIAN: "PR_SET_ENDIAN", - PR_GET_SECCOMP: "PR_GET_SECCOMP", - PR_SET_SECCOMP: "PR_SET_SECCOMP", - PR_CAPBSET_READ: "PR_CAPBSET_READ", - PR_CAPBSET_DROP: "PR_CAPBSET_DROP", - PR_GET_TSC: "PR_GET_TSC", - PR_SET_TSC: "PR_SET_TSC", - PR_GET_SECUREBITS: "PR_GET_SECUREBITS", - PR_SET_SECUREBITS: "PR_SET_SECUREBITS", - PR_SET_TIMERSLACK: "PR_SET_TIMERSLACK", - PR_GET_TIMERSLACK: "PR_GET_TIMERSLACK", - PR_TASK_PERF_EVENTS_DISABLE: "PR_TASK_PERF_EVENTS_DISABLE", - PR_TASK_PERF_EVENTS_ENABLE: "PR_TASK_PERF_EVENTS_ENABLE", - PR_MCE_KILL: "PR_MCE_KILL", - PR_MCE_KILL_GET: "PR_MCE_KILL_GET", - PR_SET_MM: "PR_SET_MM", - PR_SET_CHILD_SUBREAPER: "PR_SET_CHILD_SUBREAPER", - PR_GET_CHILD_SUBREAPER: "PR_GET_CHILD_SUBREAPER", - PR_SET_NO_NEW_PRIVS: "PR_SET_NO_NEW_PRIVS", - PR_GET_NO_NEW_PRIVS: "PR_GET_NO_NEW_PRIVS", - PR_GET_TID_ADDRESS: "PR_GET_TID_ADDRESS", - PR_SET_THP_DISABLE: "PR_SET_THP_DISABLE", - PR_GET_THP_DISABLE: "PR_GET_THP_DISABLE", - PR_MPX_ENABLE_MANAGEMENT: "PR_MPX_ENABLE_MANAGEMENT", - PR_MPX_DISABLE_MANAGEMENT: "PR_MPX_DISABLE_MANAGEMENT", - PR_SET_FP_MODE: "PR_SET_FP_MODE", - PR_GET_FP_MODE: "PR_GET_FP_MODE", - PR_CAP_AMBIENT: "PR_CAP_AMBIENT", - PR_SVE_SET_VL: "PR_SVE_SET_VL", - PR_SVE_GET_VL: "PR_SVE_GET_VL", - PR_GET_SPECULATION_CTRL: "PR_GET_SPECULATION_CTRL", - PR_SET_SPECULATION_CTRL: "PR_SET_SPECULATION_CTRL", - PR_PAC_RESET_KEYS: "PR_PAC_RESET_KEYS", - PR_SET_TAGGED_ADDR_CTRL: "PR_SET_TAGGED_ADDR_CTRL", - PR_GET_TAGGED_ADDR_CTRL: "PR_GET_TAGGED_ADDR_CTRL", -} - -func (p PrctlOptionArgument) String() string { - - var res string - if opName, ok := prctlOptionStringMap[p]; ok { - res = opName - } else { - res = strconv.Itoa(int(p)) - } - - return res -} - -var prctlOptionsMap = map[uint64]PrctlOptionArgument{ - PR_SET_PDEATHSIG.Value(): PR_SET_PDEATHSIG, - PR_GET_PDEATHSIG.Value(): PR_GET_PDEATHSIG, - PR_GET_DUMPABLE.Value(): PR_GET_DUMPABLE, - PR_SET_DUMPABLE.Value(): PR_SET_DUMPABLE, - PR_GET_UNALIGN.Value(): PR_GET_UNALIGN, - PR_SET_UNALIGN.Value(): PR_SET_UNALIGN, - PR_GET_KEEPCAPS.Value(): PR_GET_KEEPCAPS, - PR_SET_KEEPCAPS.Value(): PR_SET_KEEPCAPS, - PR_GET_FPEMU.Value(): PR_GET_FPEMU, - PR_SET_FPEMU.Value(): PR_SET_FPEMU, - PR_GET_FPEXC.Value(): PR_GET_FPEXC, - PR_SET_FPEXC.Value(): PR_SET_FPEXC, - PR_GET_TIMING.Value(): PR_GET_TIMING, - PR_SET_TIMING.Value(): PR_SET_TIMING, - PR_SET_NAME.Value(): PR_SET_NAME, - PR_GET_NAME.Value(): PR_GET_NAME, - PR_GET_ENDIAN.Value(): PR_GET_ENDIAN, - PR_SET_ENDIAN.Value(): PR_SET_ENDIAN, - PR_GET_SECCOMP.Value(): PR_GET_SECCOMP, - PR_SET_SECCOMP.Value(): PR_SET_SECCOMP, - PR_CAPBSET_READ.Value(): PR_CAPBSET_READ, - PR_CAPBSET_DROP.Value(): PR_CAPBSET_DROP, - PR_GET_TSC.Value(): PR_GET_TSC, - PR_SET_TSC.Value(): PR_SET_TSC, - PR_GET_SECUREBITS.Value(): PR_GET_SECUREBITS, - PR_SET_SECUREBITS.Value(): PR_SET_SECUREBITS, - PR_SET_TIMERSLACK.Value(): PR_SET_TIMERSLACK, - PR_GET_TIMERSLACK.Value(): PR_GET_TIMERSLACK, - PR_TASK_PERF_EVENTS_DISABLE.Value(): PR_TASK_PERF_EVENTS_DISABLE, - PR_TASK_PERF_EVENTS_ENABLE.Value(): PR_TASK_PERF_EVENTS_ENABLE, - PR_MCE_KILL.Value(): PR_MCE_KILL, - PR_MCE_KILL_GET.Value(): PR_MCE_KILL_GET, - PR_SET_MM.Value(): PR_SET_MM, - PR_SET_CHILD_SUBREAPER.Value(): PR_SET_CHILD_SUBREAPER, - PR_GET_CHILD_SUBREAPER.Value(): PR_GET_CHILD_SUBREAPER, - PR_SET_NO_NEW_PRIVS.Value(): PR_SET_NO_NEW_PRIVS, - PR_GET_NO_NEW_PRIVS.Value(): PR_GET_NO_NEW_PRIVS, - PR_GET_TID_ADDRESS.Value(): PR_GET_TID_ADDRESS, - PR_SET_THP_DISABLE.Value(): PR_SET_THP_DISABLE, - PR_GET_THP_DISABLE.Value(): PR_GET_THP_DISABLE, - PR_MPX_ENABLE_MANAGEMENT.Value(): PR_MPX_ENABLE_MANAGEMENT, - PR_MPX_DISABLE_MANAGEMENT.Value(): PR_MPX_DISABLE_MANAGEMENT, - PR_SET_FP_MODE.Value(): PR_SET_FP_MODE, - PR_GET_FP_MODE.Value(): PR_GET_FP_MODE, - PR_CAP_AMBIENT.Value(): PR_CAP_AMBIENT, - PR_SVE_SET_VL.Value(): PR_SVE_SET_VL, - PR_SVE_GET_VL.Value(): PR_SVE_GET_VL, - PR_GET_SPECULATION_CTRL.Value(): PR_GET_SPECULATION_CTRL, - PR_SET_SPECULATION_CTRL.Value(): PR_SET_SPECULATION_CTRL, - PR_PAC_RESET_KEYS.Value(): PR_PAC_RESET_KEYS, - PR_SET_TAGGED_ADDR_CTRL.Value(): PR_SET_TAGGED_ADDR_CTRL, - PR_GET_TAGGED_ADDR_CTRL.Value(): PR_GET_TAGGED_ADDR_CTRL, -} - -// ParsePrctlOption parses the `option` argument of the `prctl` syscall -// http://man7.org/linux/man-pages/man2/prctl.2.html -func ParsePrctlOption(rawValue uint64) (PrctlOptionArgument, error) { - - v, ok := prctlOptionsMap[rawValue] - if !ok { - return 0, fmt.Errorf("not a valid prctl option value: %d", rawValue) - } - return v, nil -} - -type BPFCommandArgument uint64 - -const ( - BPF_MAP_CREATE BPFCommandArgument = iota - BPF_MAP_LOOKUP_ELEM - BPF_MAP_UPDATE_ELEM - BPF_MAP_DELETE_ELEM - BPF_MAP_GET_NEXT_KEY - BPF_PROG_LOAD - BPF_OBJ_PIN - BPF_OBJ_GET - BPF_PROG_ATTACH - BPF_PROG_DETACH - BPF_PROG_TEST_RUN - BPF_PROG_GET_NEXT_ID - BPF_MAP_GET_NEXT_ID - BPF_PROG_GET_FD_BY_ID - BPF_MAP_GET_FD_BY_ID - BPF_OBJ_GET_INFO_BY_FD - BPF_PROG_QUERY - BPF_RAW_TRACEPOINT_OPEN - BPF_BTF_LOAD - BPF_BTF_GET_FD_BY_ID - BPF_TASK_FD_QUERY - BPF_MAP_LOOKUP_AND_DELETE_ELEM - BPF_MAP_FREEZE - BPF_BTF_GET_NEXT_ID - BPF_MAP_LOOKUP_BATCH - BPF_MAP_LOOKUP_AND_DELETE_BATCH - BPF_MAP_UPDATE_BATCH - BPF_MAP_DELETE_BATCH - BPF_LINK_CREATE - BPF_LINK_UPDATE - BPF_LINK_GET_FD_BY_ID - BPF_LINK_GET_NEXT_ID - BPF_ENABLE_STATS - BPF_ITER_CREATE - BPF_LINK_DETACH -) - -func (b BPFCommandArgument) Value() uint64 { return uint64(b) } - -var bpfCmdStringMap = map[BPFCommandArgument]string{ - BPF_MAP_CREATE: "BPF_MAP_CREATE", - BPF_MAP_LOOKUP_ELEM: "BPF_MAP_LOOKUP_ELEM", - BPF_MAP_UPDATE_ELEM: "BPF_MAP_UPDATE_ELEM", - BPF_MAP_DELETE_ELEM: "BPF_MAP_DELETE_ELEM", - BPF_MAP_GET_NEXT_KEY: "BPF_MAP_GET_NEXT_KEY", - BPF_PROG_LOAD: "BPF_PROG_LOAD", - BPF_OBJ_PIN: "BPF_OBJ_PIN", - BPF_OBJ_GET: "BPF_OBJ_GET", - BPF_PROG_ATTACH: "BPF_PROG_ATTACH", - BPF_PROG_DETACH: "BPF_PROG_DETACH", - BPF_PROG_TEST_RUN: "BPF_PROG_TEST_RUN", - BPF_PROG_GET_NEXT_ID: "BPF_PROG_GET_NEXT_ID", - BPF_MAP_GET_NEXT_ID: "BPF_MAP_GET_NEXT_ID", - BPF_PROG_GET_FD_BY_ID: "BPF_PROG_GET_FD_BY_ID", - BPF_MAP_GET_FD_BY_ID: "BPF_MAP_GET_FD_BY_ID", - BPF_OBJ_GET_INFO_BY_FD: "BPF_OBJ_GET_INFO_BY_FD", - BPF_PROG_QUERY: "BPF_PROG_QUERY", - BPF_RAW_TRACEPOINT_OPEN: "BPF_RAW_TRACEPOINT_OPEN", - BPF_BTF_LOAD: "BPF_BTF_LOAD", - BPF_BTF_GET_FD_BY_ID: "BPF_BTF_GET_FD_BY_ID", - BPF_TASK_FD_QUERY: "BPF_TASK_FD_QUERY", - BPF_MAP_LOOKUP_AND_DELETE_ELEM: "BPF_MAP_LOOKUP_AND_DELETE_ELEM", - BPF_MAP_FREEZE: "BPF_MAP_FREEZE", - BPF_BTF_GET_NEXT_ID: "BPF_BTF_GET_NEXT_ID", - BPF_MAP_LOOKUP_BATCH: "BPF_MAP_LOOKUP_BATCH", - BPF_MAP_LOOKUP_AND_DELETE_BATCH: "BPF_MAP_LOOKUP_AND_DELETE_BATCH", - BPF_MAP_UPDATE_BATCH: "BPF_MAP_UPDATE_BATCH", - BPF_MAP_DELETE_BATCH: "BPF_MAP_DELETE_BATCH", - BPF_LINK_CREATE: "BPF_LINK_CREATE", - BPF_LINK_UPDATE: "BPF_LINK_UPDATE", - BPF_LINK_GET_FD_BY_ID: "BPF_LINK_GET_FD_BY_ID", - BPF_LINK_GET_NEXT_ID: "BPF_LINK_GET_NEXT_ID", - BPF_ENABLE_STATS: "BPF_ENABLE_STATS", - BPF_ITER_CREATE: "BPF_ITER_CREATE", - BPF_LINK_DETACH: "BPF_LINK_DETACH", -} - -// String parses the `cmd` argument of the `bpf` syscall -// https://man7.org/linux/man-pages/man2/bpf.2.html -func (b BPFCommandArgument) String() string { - - var res string - if cmdName, ok := bpfCmdStringMap[b]; ok { - res = cmdName - } else { - res = strconv.Itoa(int(b)) - } - - return res -} - -var bpfCmdMap = map[uint64]BPFCommandArgument{ - BPF_MAP_CREATE.Value(): BPF_MAP_CREATE, - BPF_MAP_LOOKUP_ELEM.Value(): BPF_MAP_LOOKUP_ELEM, - BPF_MAP_UPDATE_ELEM.Value(): BPF_MAP_UPDATE_ELEM, - BPF_MAP_DELETE_ELEM.Value(): BPF_MAP_DELETE_ELEM, - BPF_MAP_GET_NEXT_KEY.Value(): BPF_MAP_GET_NEXT_KEY, - BPF_PROG_LOAD.Value(): BPF_PROG_LOAD, - BPF_OBJ_PIN.Value(): BPF_OBJ_PIN, - BPF_OBJ_GET.Value(): BPF_OBJ_GET, - BPF_PROG_ATTACH.Value(): BPF_PROG_ATTACH, - BPF_PROG_DETACH.Value(): BPF_PROG_DETACH, - BPF_PROG_TEST_RUN.Value(): BPF_PROG_TEST_RUN, - BPF_PROG_GET_NEXT_ID.Value(): BPF_PROG_GET_NEXT_ID, - BPF_MAP_GET_NEXT_ID.Value(): BPF_MAP_GET_NEXT_ID, - BPF_PROG_GET_FD_BY_ID.Value(): BPF_PROG_GET_FD_BY_ID, - BPF_MAP_GET_FD_BY_ID.Value(): BPF_MAP_GET_FD_BY_ID, - BPF_OBJ_GET_INFO_BY_FD.Value(): BPF_OBJ_GET_INFO_BY_FD, - BPF_PROG_QUERY.Value(): BPF_PROG_QUERY, - BPF_RAW_TRACEPOINT_OPEN.Value(): BPF_RAW_TRACEPOINT_OPEN, - BPF_BTF_LOAD.Value(): BPF_BTF_LOAD, - BPF_BTF_GET_FD_BY_ID.Value(): BPF_BTF_GET_FD_BY_ID, - BPF_TASK_FD_QUERY.Value(): BPF_TASK_FD_QUERY, - BPF_MAP_LOOKUP_AND_DELETE_ELEM.Value(): BPF_MAP_LOOKUP_AND_DELETE_ELEM, - BPF_MAP_FREEZE.Value(): BPF_MAP_FREEZE, - BPF_BTF_GET_NEXT_ID.Value(): BPF_BTF_GET_NEXT_ID, - BPF_MAP_LOOKUP_BATCH.Value(): BPF_MAP_LOOKUP_BATCH, - BPF_MAP_LOOKUP_AND_DELETE_BATCH.Value(): BPF_MAP_LOOKUP_AND_DELETE_BATCH, - BPF_MAP_UPDATE_BATCH.Value(): BPF_MAP_UPDATE_BATCH, - BPF_MAP_DELETE_BATCH.Value(): BPF_MAP_DELETE_BATCH, - BPF_LINK_CREATE.Value(): BPF_LINK_CREATE, - BPF_LINK_UPDATE.Value(): BPF_LINK_UPDATE, - BPF_LINK_GET_FD_BY_ID.Value(): BPF_LINK_GET_FD_BY_ID, - BPF_LINK_GET_NEXT_ID.Value(): BPF_LINK_GET_NEXT_ID, - BPF_ENABLE_STATS.Value(): BPF_ENABLE_STATS, - BPF_ITER_CREATE.Value(): BPF_ITER_CREATE, - BPF_LINK_DETACH.Value(): BPF_LINK_DETACH, -} - -// ParseBPFCmd parses the raw value of the `cmd` argument of the `bpf` syscall -// https://man7.org/linux/man-pages/man2/bpf.2.html -func ParseBPFCmd(cmd uint64) (BPFCommandArgument, error) { - v, ok := bpfCmdMap[cmd] - if !ok { - return 0, fmt.Errorf("not a valid BPF command argument: %d", cmd) - } - return v, nil -} - -type PtraceRequestArgument uint64 - -var ( - PTRACE_TRACEME PtraceRequestArgument = 0 - PTRACE_PEEKTEXT PtraceRequestArgument = 1 - PTRACE_PEEKDATA PtraceRequestArgument = 2 - PTRACE_PEEKUSER PtraceRequestArgument = 3 - PTRACE_POKETEXT PtraceRequestArgument = 4 - PTRACE_POKEDATA PtraceRequestArgument = 5 - PTRACE_POKEUSER PtraceRequestArgument = 6 - PTRACE_CONT PtraceRequestArgument = 7 - PTRACE_KILL PtraceRequestArgument = 8 - PTRACE_SINGLESTEP PtraceRequestArgument = 9 - PTRACE_GETREGS PtraceRequestArgument = 12 - PTRACE_SETREGS PtraceRequestArgument = 13 - PTRACE_GETFPREGS PtraceRequestArgument = 14 - PTRACE_SETFPREGS PtraceRequestArgument = 15 - PTRACE_ATTACH PtraceRequestArgument = 16 - PTRACE_DETACH PtraceRequestArgument = 17 - PTRACE_GETFPXREGS PtraceRequestArgument = 18 - PTRACE_SETFPXREGS PtraceRequestArgument = 19 - PTRACE_SYSCALL PtraceRequestArgument = 24 - PTRACE_SETOPTIONS PtraceRequestArgument = 0x4200 - PTRACE_GETEVENTMSG PtraceRequestArgument = 0x4201 - PTRACE_GETSIGINFO PtraceRequestArgument = 0x4202 - PTRACE_SETSIGINFO PtraceRequestArgument = 0x4203 - PTRACE_GETREGSET PtraceRequestArgument = 0x4204 - PTRACE_SETREGSET PtraceRequestArgument = 0x4205 - PTRACE_SEIZE PtraceRequestArgument = 0x4206 - PTRACE_INTERRUPT PtraceRequestArgument = 0x4207 - PTRACE_LISTEN PtraceRequestArgument = 0x4208 - PTRACE_PEEKSIGINFO PtraceRequestArgument = 0x4209 - PTRACE_GETSIGMASK PtraceRequestArgument = 0x420a - PTRACE_SETSIGMASK PtraceRequestArgument = 0x420b - PTRACE_SECCOMP_GET_FILTER PtraceRequestArgument = 0x420c - PTRACE_SECCOMP_GET_METADATA PtraceRequestArgument = 0x420d - PTRACE_GET_SYSCALL_INFO PtraceRequestArgument = 0x420e -) - -func (p PtraceRequestArgument) Value() uint64 { return uint64(p) } - -var ptraceRequestStringMap = map[PtraceRequestArgument]string{ - PTRACE_TRACEME: "PTRACE_TRACEME", - PTRACE_PEEKTEXT: "PTRACE_PEEKTEXT", - PTRACE_PEEKDATA: "PTRACE_PEEKDATA", - PTRACE_PEEKUSER: "PTRACE_PEEKUSER", - PTRACE_POKETEXT: "PTRACE_POKETEXT", - PTRACE_POKEDATA: "PTRACE_POKEDATA", - PTRACE_POKEUSER: "PTRACE_POKEUSER", - PTRACE_CONT: "PTRACE_CONT", - PTRACE_KILL: "PTRACE_KILL", - PTRACE_SINGLESTEP: "PTRACE_SINGLESTEP", - PTRACE_GETREGS: "PTRACE_GETREGS", - PTRACE_SETREGS: "PTRACE_SETREGS", - PTRACE_GETFPREGS: "PTRACE_GETFPREGS", - PTRACE_SETFPREGS: "PTRACE_SETFPREGS", - PTRACE_ATTACH: "PTRACE_ATTACH", - PTRACE_DETACH: "PTRACE_DETACH", - PTRACE_GETFPXREGS: "PTRACE_GETFPXREGS", - PTRACE_SETFPXREGS: "PTRACE_SETFPXREGS", - PTRACE_SYSCALL: "PTRACE_SYSCALL", - PTRACE_SETOPTIONS: "PTRACE_SETOPTIONS", - PTRACE_GETEVENTMSG: "PTRACE_GETEVENTMSG", - PTRACE_GETSIGINFO: "PTRACE_GETSIGINFO", - PTRACE_SETSIGINFO: "PTRACE_SETSIGINFO", - PTRACE_GETREGSET: "PTRACE_GETREGSET", - PTRACE_SETREGSET: "PTRACE_SETREGSET", - PTRACE_SEIZE: "PTRACE_SEIZE", - PTRACE_INTERRUPT: "PTRACE_INTERRUPT", - PTRACE_LISTEN: "PTRACE_LISTEN", - PTRACE_PEEKSIGINFO: "PTRACE_PEEKSIGINFO", - PTRACE_GETSIGMASK: "PTRACE_GETSIGMASK", - PTRACE_SETSIGMASK: "PTRACE_SETSIGMASK", - PTRACE_SECCOMP_GET_FILTER: "PTRACE_SECCOMP_GET_FILTER", - PTRACE_SECCOMP_GET_METADATA: "PTRACE_SECCOMP_GET_METADATA", - PTRACE_GET_SYSCALL_INFO: "PTRACE_GET_SYSCALL_INFO", -} - -func (p PtraceRequestArgument) String() string { - var res string - if reqName, ok := ptraceRequestStringMap[p]; ok { - res = reqName - } else { - res = strconv.Itoa(int(p)) - } - - return res -} - -var ptraceRequestArgMap = map[uint64]PtraceRequestArgument{ - PTRACE_TRACEME.Value(): PTRACE_TRACEME, - PTRACE_PEEKTEXT.Value(): PTRACE_PEEKTEXT, - PTRACE_PEEKDATA.Value(): PTRACE_PEEKDATA, - PTRACE_PEEKUSER.Value(): PTRACE_PEEKUSER, - PTRACE_POKETEXT.Value(): PTRACE_POKETEXT, - PTRACE_POKEDATA.Value(): PTRACE_POKEDATA, - PTRACE_POKEUSER.Value(): PTRACE_POKEUSER, - PTRACE_CONT.Value(): PTRACE_CONT, - PTRACE_KILL.Value(): PTRACE_KILL, - PTRACE_SINGLESTEP.Value(): PTRACE_SINGLESTEP, - PTRACE_GETREGS.Value(): PTRACE_GETREGS, - PTRACE_SETREGS.Value(): PTRACE_SETREGS, - PTRACE_GETFPREGS.Value(): PTRACE_GETFPREGS, - PTRACE_SETFPREGS.Value(): PTRACE_SETFPREGS, - PTRACE_ATTACH.Value(): PTRACE_ATTACH, - PTRACE_DETACH.Value(): PTRACE_DETACH, - PTRACE_GETFPXREGS.Value(): PTRACE_GETFPXREGS, - PTRACE_SETFPXREGS.Value(): PTRACE_SETFPXREGS, - PTRACE_SYSCALL.Value(): PTRACE_SYSCALL, - PTRACE_SETOPTIONS.Value(): PTRACE_SETOPTIONS, - PTRACE_GETEVENTMSG.Value(): PTRACE_GETEVENTMSG, - PTRACE_GETSIGINFO.Value(): PTRACE_GETSIGINFO, - PTRACE_SETSIGINFO.Value(): PTRACE_SETSIGINFO, - PTRACE_GETREGSET.Value(): PTRACE_GETREGSET, - PTRACE_SETREGSET.Value(): PTRACE_SETREGSET, - PTRACE_SEIZE.Value(): PTRACE_SEIZE, - PTRACE_INTERRUPT.Value(): PTRACE_INTERRUPT, - PTRACE_LISTEN.Value(): PTRACE_LISTEN, - PTRACE_PEEKSIGINFO.Value(): PTRACE_PEEKSIGINFO, - PTRACE_GETSIGMASK.Value(): PTRACE_GETSIGMASK, - PTRACE_SETSIGMASK.Value(): PTRACE_SETSIGMASK, - PTRACE_SECCOMP_GET_FILTER.Value(): PTRACE_SECCOMP_GET_FILTER, - PTRACE_SECCOMP_GET_METADATA.Value(): PTRACE_SECCOMP_GET_METADATA, - PTRACE_GET_SYSCALL_INFO.Value(): PTRACE_GET_SYSCALL_INFO, -} - -func ParsePtraceRequestArgument(rawValue uint64) (PtraceRequestArgument, error) { - - if reqName, ok := ptraceRequestArgMap[rawValue]; ok { - return reqName, nil - } - return 0, fmt.Errorf("not a valid ptrace request value: %d", rawValue) -} - -type SocketDomainArgument uint64 - -const ( - AF_UNSPEC SocketDomainArgument = iota - AF_UNIX - AF_INET - AF_AX25 - AF_IPX - AF_APPLETALK - AF_NETROM - AF_BRIDGE - AF_ATMPVC - AF_X25 - AF_INET6 - AF_ROSE - AF_DECnet - AF_NETBEUI - AF_SECURITY - AF_KEY - AF_NETLINK - AF_PACKET - AF_ASH - AF_ECONET - AF_ATMSVC - AF_RDS - AF_SNA - AF_IRDA - AF_PPPOX - AF_WANPIPE - AF_LLC - AF_IB - AF_MPLS - AF_CAN - AF_TIPC - AF_BLUETOOTH - AF_IUCV - AF_RXRPC - AF_ISDN - AF_PHONET - AF_IEEE802154 - AF_CAIF - AF_ALG - AF_NFC - AF_VSOCK - AF_KCM - AF_QIPCRTR - AF_SMC - AF_XDP -) - -func (s SocketDomainArgument) Value() uint64 { return uint64(s) } - -var socketDomainStringMap = map[SocketDomainArgument]string{ - AF_UNSPEC: "AF_UNSPEC", - AF_UNIX: "AF_UNIX", - AF_INET: "AF_INET", - AF_AX25: "AF_AX25", - AF_IPX: "AF_IPX", - AF_APPLETALK: "AF_APPLETALK", - AF_NETROM: "AF_NETROM", - AF_BRIDGE: "AF_BRIDGE", - AF_ATMPVC: "AF_ATMPVC", - AF_X25: "AF_X25", - AF_INET6: "AF_INET6", - AF_ROSE: "AF_ROSE", - AF_DECnet: "AF_DECnet", - AF_NETBEUI: "AF_NETBEUI", - AF_SECURITY: "AF_SECURITY", - AF_KEY: "AF_KEY", - AF_NETLINK: "AF_NETLINK", - AF_PACKET: "AF_PACKET", - AF_ASH: "AF_ASH", - AF_ECONET: "AF_ECONET", - AF_ATMSVC: "AF_ATMSVC", - AF_RDS: "AF_RDS", - AF_SNA: "AF_SNA", - AF_IRDA: "AF_IRDA", - AF_PPPOX: "AF_PPPOX", - AF_WANPIPE: "AF_WANPIPE", - AF_LLC: "AF_LLC", - AF_IB: "AF_IB", - AF_MPLS: "AF_MPLS", - AF_CAN: "AF_CAN", - AF_TIPC: "AF_TIPC", - AF_BLUETOOTH: "AF_BLUETOOTH", - AF_IUCV: "AF_IUCV", - AF_RXRPC: "AF_RXRPC", - AF_ISDN: "AF_ISDN", - AF_PHONET: "AF_PHONET", - AF_IEEE802154: "AF_IEEE802154", - AF_CAIF: "AF_CAIF", - AF_ALG: "AF_ALG", - AF_NFC: "AF_NFC", - AF_VSOCK: "AF_VSOCK", - AF_KCM: "AF_KCM", - AF_QIPCRTR: "AF_QIPCRTR", - AF_SMC: "AF_SMC", - AF_XDP: "AF_XDP", -} - -// String parses the `domain` bitmask argument of the `socket` syscall -// http://man7.org/linux/man-pages/man2/socket.2.html -func (s SocketDomainArgument) String() string { - var res string - - if sdName, ok := socketDomainStringMap[s]; ok { - res = sdName - } else { - res = strconv.Itoa(int(s)) - } - - return res -} - -var socketDomainMap = map[uint64]SocketDomainArgument{ - AF_UNSPEC.Value(): AF_UNSPEC, - AF_UNIX.Value(): AF_UNIX, - AF_INET.Value(): AF_INET, - AF_AX25.Value(): AF_AX25, - AF_IPX.Value(): AF_IPX, - AF_APPLETALK.Value(): AF_APPLETALK, - AF_NETROM.Value(): AF_NETROM, - AF_BRIDGE.Value(): AF_BRIDGE, - AF_ATMPVC.Value(): AF_ATMPVC, - AF_X25.Value(): AF_X25, - AF_INET6.Value(): AF_INET6, - AF_ROSE.Value(): AF_ROSE, - AF_DECnet.Value(): AF_DECnet, - AF_NETBEUI.Value(): AF_NETBEUI, - AF_SECURITY.Value(): AF_SECURITY, - AF_KEY.Value(): AF_KEY, - AF_NETLINK.Value(): AF_NETLINK, - AF_PACKET.Value(): AF_PACKET, - AF_ASH.Value(): AF_ASH, - AF_ECONET.Value(): AF_ECONET, - AF_ATMSVC.Value(): AF_ATMSVC, - AF_RDS.Value(): AF_RDS, - AF_SNA.Value(): AF_SNA, - AF_IRDA.Value(): AF_IRDA, - AF_PPPOX.Value(): AF_PPPOX, - AF_WANPIPE.Value(): AF_WANPIPE, - AF_LLC.Value(): AF_LLC, - AF_IB.Value(): AF_IB, - AF_MPLS.Value(): AF_MPLS, - AF_CAN.Value(): AF_CAN, - AF_TIPC.Value(): AF_TIPC, - AF_BLUETOOTH.Value(): AF_BLUETOOTH, - AF_IUCV.Value(): AF_IUCV, - AF_RXRPC.Value(): AF_RXRPC, - AF_ISDN.Value(): AF_ISDN, - AF_PHONET.Value(): AF_PHONET, - AF_IEEE802154.Value(): AF_IEEE802154, - AF_CAIF.Value(): AF_CAIF, - AF_ALG.Value(): AF_ALG, - AF_NFC.Value(): AF_NFC, - AF_VSOCK.Value(): AF_VSOCK, - AF_KCM.Value(): AF_KCM, - AF_QIPCRTR.Value(): AF_QIPCRTR, - AF_SMC.Value(): AF_SMC, - AF_XDP.Value(): AF_XDP, -} - -func ParseSocketDomainArgument(rawValue uint64) (SocketDomainArgument, error) { - - v, ok := socketDomainMap[rawValue] - if !ok { - return 0, fmt.Errorf("not a valid argument: %d", rawValue) - } - return v, nil -} - -type SocketTypeArgument struct { - rawValue uint64 - stringValue string -} - -var ( - SOCK_STREAM SocketTypeArgument = SocketTypeArgument{rawValue: 1, stringValue: "SOCK_STREAM"} - SOCK_DGRAM SocketTypeArgument = SocketTypeArgument{rawValue: 2, stringValue: "SOCK_DGRAM"} - SOCK_RAW SocketTypeArgument = SocketTypeArgument{rawValue: 3, stringValue: "SOCK_RAW"} - SOCK_RDM SocketTypeArgument = SocketTypeArgument{rawValue: 4, stringValue: "SOCK_RDM"} - SOCK_SEQPACKET SocketTypeArgument = SocketTypeArgument{rawValue: 5, stringValue: "SOCK_SEQPACKET"} - SOCK_DCCP SocketTypeArgument = SocketTypeArgument{rawValue: 6, stringValue: "SOCK_DCCP"} - SOCK_PACKET SocketTypeArgument = SocketTypeArgument{rawValue: 10, stringValue: "SOCK_PACKET"} - SOCK_NONBLOCK SocketTypeArgument = SocketTypeArgument{rawValue: 000004000, stringValue: "SOCK_NONBLOCK"} - SOCK_CLOEXEC SocketTypeArgument = SocketTypeArgument{rawValue: 002000000, stringValue: "SOCK_CLOEXEC"} -) - -func (s SocketTypeArgument) Value() uint64 { return s.rawValue } -func (s SocketTypeArgument) String() string { return s.stringValue } - -var socketTypeMap = map[uint64]SocketTypeArgument{ - SOCK_STREAM.Value(): SOCK_STREAM, - SOCK_DGRAM.Value(): SOCK_DGRAM, - SOCK_RAW.Value(): SOCK_RAW, - SOCK_RDM.Value(): SOCK_RDM, - SOCK_SEQPACKET.Value(): SOCK_SEQPACKET, - SOCK_DCCP.Value(): SOCK_DCCP, - SOCK_PACKET.Value(): SOCK_PACKET, -} - -// ParseSocketType parses the `type` bitmask argument of the `socket` syscall -// http://man7.org/linux/man-pages/man2/socket.2.html -func ParseSocketType(rawValue uint64) (SocketTypeArgument, error) { - var f []string - - if stName, ok := socketTypeMap[rawValue&0xf]; ok { - f = append(f, stName.String()) - } else { - f = append(f, strconv.Itoa(int(rawValue))) - } - - if OptionAreContainedInArgument(rawValue, SOCK_NONBLOCK) { - f = append(f, "SOCK_NONBLOCK") - } - if OptionAreContainedInArgument(rawValue, SOCK_CLOEXEC) { - f = append(f, "SOCK_CLOEXEC") - } - - return SocketTypeArgument{stringValue: strings.Join(f, "|"), rawValue: rawValue}, nil -} - -type InodeModeArgument struct { - rawValue uint64 - stringValue string -} - -var ( - S_IFSOCK InodeModeArgument = InodeModeArgument{stringValue: "S_IFSOCK", rawValue: 0140000} - S_IFLNK InodeModeArgument = InodeModeArgument{stringValue: "S_IFLNK", rawValue: 0120000} - S_IFREG InodeModeArgument = InodeModeArgument{stringValue: "S_IFREG", rawValue: 0100000} - S_IFBLK InodeModeArgument = InodeModeArgument{stringValue: "S_IFBLK", rawValue: 060000} - S_IFDIR InodeModeArgument = InodeModeArgument{stringValue: "S_IFDIR", rawValue: 040000} - S_IFCHR InodeModeArgument = InodeModeArgument{stringValue: "S_IFCHR", rawValue: 020000} - S_IFIFO InodeModeArgument = InodeModeArgument{stringValue: "S_IFIFO", rawValue: 010000} - S_IRWXU InodeModeArgument = InodeModeArgument{stringValue: "S_IRWXU", rawValue: 00700} - S_IRUSR InodeModeArgument = InodeModeArgument{stringValue: "S_IRUSR", rawValue: 00400} - S_IWUSR InodeModeArgument = InodeModeArgument{stringValue: "S_IWUSR", rawValue: 00200} - S_IXUSR InodeModeArgument = InodeModeArgument{stringValue: "S_IXUSR", rawValue: 00100} - S_IRWXG InodeModeArgument = InodeModeArgument{stringValue: "S_IRWXG", rawValue: 00070} - S_IRGRP InodeModeArgument = InodeModeArgument{stringValue: "S_IRGRP", rawValue: 00040} - S_IWGRP InodeModeArgument = InodeModeArgument{stringValue: "S_IWGRP", rawValue: 00020} - S_IXGRP InodeModeArgument = InodeModeArgument{stringValue: "S_IXGRP", rawValue: 00010} - S_IRWXO InodeModeArgument = InodeModeArgument{stringValue: "S_IRWXO", rawValue: 00007} - S_IROTH InodeModeArgument = InodeModeArgument{stringValue: "S_IROTH", rawValue: 00004} - S_IWOTH InodeModeArgument = InodeModeArgument{stringValue: "S_IWOTH", rawValue: 00002} - S_IXOTH InodeModeArgument = InodeModeArgument{stringValue: "S_IXOTH", rawValue: 00001} -) - -func (mode InodeModeArgument) Value() uint64 { return mode.rawValue } -func (mode InodeModeArgument) String() string { return mode.stringValue } - -func ParseInodeMode(rawValue uint64) (InodeModeArgument, error) { - var f []string - - // File Type - switch { - case OptionAreContainedInArgument(rawValue, S_IFSOCK): - f = append(f, S_IFSOCK.String()) - case OptionAreContainedInArgument(rawValue, S_IFLNK): - f = append(f, S_IFLNK.String()) - case OptionAreContainedInArgument(rawValue, S_IFREG): - f = append(f, S_IFREG.String()) - case OptionAreContainedInArgument(rawValue, S_IFBLK): - f = append(f, S_IFBLK.String()) - case OptionAreContainedInArgument(rawValue, S_IFDIR): - f = append(f, S_IFDIR.String()) - case OptionAreContainedInArgument(rawValue, S_IFCHR): - f = append(f, S_IFCHR.String()) - case OptionAreContainedInArgument(rawValue, S_IFIFO): - f = append(f, S_IFIFO.String()) - } - - // File Mode - // Owner - if OptionAreContainedInArgument(rawValue, S_IRWXU) { - f = append(f, S_IRWXU.String()) - } else { - if OptionAreContainedInArgument(rawValue, S_IRUSR) { - f = append(f, S_IRUSR.String()) - } - if OptionAreContainedInArgument(rawValue, S_IWUSR) { - f = append(f, S_IWUSR.String()) - } - if OptionAreContainedInArgument(rawValue, S_IXUSR) { - f = append(f, S_IXUSR.String()) - } - } - // Group - if OptionAreContainedInArgument(rawValue, S_IRWXG) { - f = append(f, S_IRWXG.String()) - } else { - if OptionAreContainedInArgument(rawValue, S_IRGRP) { - f = append(f, S_IRGRP.String()) - } - if OptionAreContainedInArgument(rawValue, S_IWGRP) { - f = append(f, S_IWGRP.String()) - } - if OptionAreContainedInArgument(rawValue, S_IXGRP) { - f = append(f, S_IXGRP.String()) - } - } - // Others - if OptionAreContainedInArgument(rawValue, S_IRWXO) { - f = append(f, S_IRWXO.String()) - } else { - if OptionAreContainedInArgument(rawValue, S_IROTH) { - f = append(f, S_IROTH.String()) - } - if OptionAreContainedInArgument(rawValue, S_IWOTH) { - f = append(f, S_IWOTH.String()) - } - if OptionAreContainedInArgument(rawValue, S_IXOTH) { - f = append(f, S_IXOTH.String()) - } - } - - return InodeModeArgument{stringValue: strings.Join(f, "|"), rawValue: rawValue}, nil -} - -type MmapProtArgument struct { - rawValue uint64 - stringValue string -} - -var ( - PROT_READ MmapProtArgument = MmapProtArgument{stringValue: "PROT_READ", rawValue: 0x1} - PROT_WRITE MmapProtArgument = MmapProtArgument{stringValue: "PROT_WRITE", rawValue: 0x2} - PROT_EXEC MmapProtArgument = MmapProtArgument{stringValue: "PROT_EXEC", rawValue: 0x4} - PROT_SEM MmapProtArgument = MmapProtArgument{stringValue: "PROT_SEM", rawValue: 0x8} - PROT_NONE MmapProtArgument = MmapProtArgument{stringValue: "PROT_NONE", rawValue: 0x0} - PROT_GROWSDOWN MmapProtArgument = MmapProtArgument{stringValue: "PROT_GROWSDOWN", rawValue: 0x01000000} - PROT_GROWSUP MmapProtArgument = MmapProtArgument{stringValue: "PROT_GROWSUP", rawValue: 0x02000000} -) - -func (p MmapProtArgument) Value() uint64 { return p.rawValue } -func (p MmapProtArgument) String() string { return p.stringValue } - -// ParseMmapProt parses the `prot` bitmask argument of the `mmap` syscall -// http://man7.org/linux/man-pages/man2/mmap.2.html -// https://elixir.bootlin.com/linux/v5.5.3/source/include/uapi/asm-generic/mman-common.h#L10 -func ParseMmapProt(rawValue uint64) MmapProtArgument { - var f []string - if rawValue == PROT_NONE.Value() { - f = append(f, PROT_NONE.String()) - } else { - if OptionAreContainedInArgument(rawValue, PROT_READ) { - f = append(f, PROT_READ.String()) - } - if OptionAreContainedInArgument(rawValue, PROT_WRITE) { - f = append(f, PROT_WRITE.String()) - } - if OptionAreContainedInArgument(rawValue, PROT_EXEC) { - f = append(f, PROT_EXEC.String()) - } - if OptionAreContainedInArgument(rawValue, PROT_SEM) { - f = append(f, PROT_SEM.String()) - } - if OptionAreContainedInArgument(rawValue, PROT_GROWSDOWN) { - f = append(f, PROT_GROWSDOWN.String()) - } - if OptionAreContainedInArgument(rawValue, PROT_GROWSUP) { - f = append(f, PROT_GROWSUP.String()) - } - } - - return MmapProtArgument{stringValue: strings.Join(f, "|"), rawValue: rawValue} -} - -// ParseUint32IP parses the IP address encoded as a uint32 -func ParseUint32IP(in uint32) string { - ip := make(net.IP, net.IPv4len) - binary.BigEndian.PutUint32(ip, in) - - return ip.String() -} - -// Parse16BytesSliceIP parses the IP address encoded as 16 bytes long -// PrintBytesSliceIP. It would be more correct to accept a [16]byte instead of -// variable lenth slice, but that would case unnecessary memory copying and -// type conversions. -func Parse16BytesSliceIP(in []byte) string { - ip := net.IP(in) - - return ip.String() -} - -type SocketLevelArgument uint64 - -const ( - SOL_SOCKET SocketLevelArgument = unix.SOL_SOCKET - SOL_AAL SocketLevelArgument = unix.SOL_AAL - SOL_ALG SocketLevelArgument = unix.SOL_ALG - SOL_ATM SocketLevelArgument = unix.SOL_ATM - SOL_CAIF SocketLevelArgument = unix.SOL_CAIF - SOL_CAN_BASE SocketLevelArgument = unix.SOL_CAN_BASE - SOL_CAN_RAW SocketLevelArgument = unix.SOL_CAN_RAW - SOL_DCCP SocketLevelArgument = unix.SOL_DCCP - SOL_DECNET SocketLevelArgument = unix.SOL_DECNET - SOL_ICMPV6 SocketLevelArgument = unix.SOL_ICMPV6 - SOL_IP SocketLevelArgument = unix.SOL_IP - SOL_IPV6 SocketLevelArgument = unix.SOL_IPV6 - SOL_IRDA SocketLevelArgument = unix.SOL_IRDA - SOL_IUCV SocketLevelArgument = unix.SOL_IUCV - SOL_KCM SocketLevelArgument = unix.SOL_KCM - SOL_LLC SocketLevelArgument = unix.SOL_LLC - SOL_NETBEUI SocketLevelArgument = unix.SOL_NETBEUI - SOL_NETLINK SocketLevelArgument = unix.SOL_NETLINK - SOL_NFC SocketLevelArgument = unix.SOL_NFC - SOL_PACKET SocketLevelArgument = unix.SOL_PACKET - SOL_PNPIPE SocketLevelArgument = unix.SOL_PNPIPE - SOL_PPPOL2TP SocketLevelArgument = unix.SOL_PPPOL2TP - SOL_RAW SocketLevelArgument = unix.SOL_RAW - SOL_RDS SocketLevelArgument = unix.SOL_RDS - SOL_RXRPC SocketLevelArgument = unix.SOL_RXRPC - SOL_TCP SocketLevelArgument = unix.SOL_TCP - SOL_TIPC SocketLevelArgument = unix.SOL_TIPC - SOL_TLS SocketLevelArgument = unix.SOL_TLS - SOL_X25 SocketLevelArgument = unix.SOL_X25 - SOL_XDP SocketLevelArgument = unix.SOL_XDP - - // The following are newer, so aren't included in the unix package - SOL_MCTCP SocketLevelArgument = 284 - SOL_MCTP SocketLevelArgument = 285 - SOL_SMC SocketLevelArgument = 286 -) - -func (socketLevel SocketLevelArgument) Value() uint64 { return uint64(socketLevel) } - -var socketLevelStringMap = map[SocketLevelArgument]string{ - SOL_SOCKET: "SOL_SOCKET", - SOL_AAL: "SOL_AAL", - SOL_ALG: "SOL_ALG", - SOL_ATM: "SOL_ATM", - SOL_CAIF: "SOL_CAIF", - SOL_CAN_BASE: "SOL_CAN_BASE", - SOL_CAN_RAW: "SOL_CAN_RAW", - SOL_DCCP: "SOL_DCCP", - SOL_DECNET: "SOL_DECNET", - SOL_ICMPV6: "SOL_ICMPV6", - SOL_IP: "SOL_IP", - SOL_IPV6: "SOL_IPV6", - SOL_IRDA: "SOL_IRDA", - SOL_IUCV: "SOL_IUCV", - SOL_KCM: "SOL_KCM", - SOL_LLC: "SOL_LLC", - SOL_NETBEUI: "SOL_NETBEUI", - SOL_NETLINK: "SOL_NETLINK", - SOL_NFC: "SOL_NFC", - SOL_PACKET: "SOL_PACKET", - SOL_PNPIPE: "SOL_PNPIPE", - SOL_PPPOL2TP: "SOL_PPPOL2TP", - SOL_RAW: "SOL_RAW", - SOL_RDS: "SOL_RDS", - SOL_RXRPC: "SOL_RXRPC", - SOL_TCP: "SOL_TCP", - SOL_TIPC: "SOL_TIPC", - SOL_TLS: "SOL_TLS", - SOL_X25: "SOL_X25", - SOL_XDP: "SOL_XDP", - SOL_MCTCP: "SOL_MCTCP", - SOL_MCTP: "SOL_MCTP", - SOL_SMC: "SOL_SMC", -} - -func (socketLevel SocketLevelArgument) String() string { - var res string - - if sdName, ok := socketLevelStringMap[socketLevel]; ok { - res = sdName - } else { - res = strconv.Itoa(int(socketLevel)) - } - - return res -} - -var socketLevelMap = map[uint64]SocketLevelArgument{ - SOL_SOCKET.Value(): SOL_SOCKET, - SOL_AAL.Value(): SOL_AAL, - SOL_ALG.Value(): SOL_ALG, - SOL_ATM.Value(): SOL_ATM, - SOL_CAIF.Value(): SOL_CAIF, - SOL_CAN_BASE.Value(): SOL_CAN_BASE, - SOL_CAN_RAW.Value(): SOL_CAN_RAW, - SOL_DCCP.Value(): SOL_DCCP, - SOL_DECNET.Value(): SOL_DECNET, - SOL_ICMPV6.Value(): SOL_ICMPV6, - SOL_IP.Value(): SOL_IP, - SOL_IPV6.Value(): SOL_IPV6, - SOL_IRDA.Value(): SOL_IRDA, - SOL_IUCV.Value(): SOL_IUCV, - SOL_KCM.Value(): SOL_KCM, - SOL_LLC.Value(): SOL_LLC, - SOL_NETBEUI.Value(): SOL_NETBEUI, - SOL_NETLINK.Value(): SOL_NETLINK, - SOL_NFC.Value(): SOL_NFC, - SOL_PACKET.Value(): SOL_PACKET, - SOL_PNPIPE.Value(): SOL_PNPIPE, - SOL_PPPOL2TP.Value(): SOL_PPPOL2TP, - SOL_RAW.Value(): SOL_RAW, - SOL_RDS.Value(): SOL_RDS, - SOL_RXRPC.Value(): SOL_RXRPC, - SOL_TCP.Value(): SOL_TCP, - SOL_TIPC.Value(): SOL_TIPC, - SOL_TLS.Value(): SOL_TLS, - SOL_X25.Value(): SOL_X25, - SOL_XDP.Value(): SOL_XDP, - SOL_MCTCP.Value(): SOL_MCTCP, - SOL_MCTP.Value(): SOL_MCTP, - SOL_SMC.Value(): SOL_SMC, -} - -// ParseSocketLevel parses the `level` argument of the `setsockopt` and `getsockopt` syscalls. -// https://man7.org/linux/man-pages/man2/setsockopt.2.html -// https://elixir.bootlin.com/linux/latest/source/include/linux/socket.h -func ParseSocketLevel(rawValue uint64) (SocketLevelArgument, error) { - - v, ok := socketLevelMap[rawValue] - if !ok { - return 0, fmt.Errorf("not a valid argument: %d", rawValue) - } - return v, nil -} - -type SocketOptionArgument struct { - value uint64 - name string -} - -var ( - SO_DEBUG = SocketOptionArgument{unix.SO_DEBUG, "SO_DEBUG"} - SO_REUSEADDR = SocketOptionArgument{unix.SO_REUSEADDR, "SO_REUSEADDR"} - SO_TYPE = SocketOptionArgument{unix.SO_TYPE, "SO_TYPE"} - SO_ERROR = SocketOptionArgument{unix.SO_ERROR, "SO_ERROR"} - SO_DONTROUTE = SocketOptionArgument{unix.SO_DONTROUTE, "SO_DONTROUTE"} - SO_BROADCAST = SocketOptionArgument{unix.SO_BROADCAST, "SO_BROADCAST"} - SO_SNDBUF = SocketOptionArgument{unix.SO_SNDBUF, "SO_SNDBUF"} - SO_RCVBUF = SocketOptionArgument{unix.SO_RCVBUF, "SO_RCVBUF"} - SO_SNDBUFFORCE = SocketOptionArgument{unix.SO_SNDBUFFORCE, "SO_SNDBUFFORCE"} - SO_RCVBUFFORCE = SocketOptionArgument{unix.SO_RCVBUFFORCE, "SO_RCVBUFFORCE"} - SO_KEEPALIVE = SocketOptionArgument{unix.SO_KEEPALIVE, "SO_KEEPALIVE"} - SO_OOBINLINE = SocketOptionArgument{unix.SO_OOBINLINE, "SO_OOBINLINE"} - SO_NO_CHECK = SocketOptionArgument{unix.SO_NO_CHECK, "SO_NO_CHECK"} - SO_PRIORITY = SocketOptionArgument{unix.SO_PRIORITY, "SO_PRIORITY"} - SO_LINGER = SocketOptionArgument{unix.SO_LINGER, "SO_LINGER"} - SO_BSDCOMPAT = SocketOptionArgument{unix.SO_BSDCOMPAT, "SO_BSDCOMPAT"} - SO_REUSEPORT = SocketOptionArgument{unix.SO_REUSEPORT, "SO_REUSEPORT"} - SO_PASSCRED = SocketOptionArgument{unix.SO_PASSCRED, "SO_PASSCRED"} - SO_PEERCRED = SocketOptionArgument{unix.SO_PEERCRED, "SO_PEERCRED"} - SO_RCVLOWAT = SocketOptionArgument{unix.SO_RCVLOWAT, "SO_RCVLOWAT"} - SO_SNDLOWAT = SocketOptionArgument{unix.SO_SNDLOWAT, "SO_SNDLOWAT"} - SO_SECURITY_AUTHENTICATION = SocketOptionArgument{unix.SO_SECURITY_AUTHENTICATION, "SO_SECURITY_AUTHENTICATION"} - SO_SECURITY_ENCRYPTION_TRANSPORT = SocketOptionArgument{unix.SO_SECURITY_ENCRYPTION_TRANSPORT, "SO_SECURITY_ENCRYPTION_TRANSPORT"} - SO_SECURITY_ENCRYPTION_NETWORK = SocketOptionArgument{unix.SO_SECURITY_ENCRYPTION_NETWORK, "SO_SECURITY_ENCRYPTION_NETWORK"} - SO_BINDTODEVICE = SocketOptionArgument{unix.SO_BINDTODEVICE, "SO_BINDTODEVICE"} - SO_ATTACH_FILTER = SocketOptionArgument{unix.SO_ATTACH_FILTER, "SO_ATTACH_FILTER"} - SO_GET_FILTER = SocketOptionArgument{unix.SO_GET_FILTER, "SO_GET_FILTER"} - SO_DETACH_FILTER = SocketOptionArgument{unix.SO_DETACH_FILTER, "SO_DETACH_FILTER"} - SO_PEERNAME = SocketOptionArgument{unix.SO_PEERNAME, "SO_PEERNAME"} - SO_ACCEPTCONN = SocketOptionArgument{unix.SO_ACCEPTCONN, "SO_ACCEPTCONN"} - SO_PEERSEC = SocketOptionArgument{unix.SO_PEERSEC, "SO_PEERSEC"} - SO_PASSSEC = SocketOptionArgument{unix.SO_PASSSEC, "SO_PASSSEC"} - SO_MARK = SocketOptionArgument{unix.SO_MARK, "SO_MARK"} - SO_PROTOCOL = SocketOptionArgument{unix.SO_PROTOCOL, "SO_PROTOCOL"} - SO_DOMAIN = SocketOptionArgument{unix.SO_DOMAIN, "SO_DOMAIN"} - SO_RXQ_OVFL = SocketOptionArgument{unix.SO_RXQ_OVFL, "SO_RXQ_OVFL"} - SO_WIFI_STATUS = SocketOptionArgument{unix.SO_WIFI_STATUS, "SO_WIFI_STATUS"} - SO_PEEK_OFF = SocketOptionArgument{unix.SO_PEEK_OFF, "SO_PEEK_OFF"} - SO_NOFCS = SocketOptionArgument{unix.SO_NOFCS, "SO_NOFCS"} - SO_LOCK_FILTER = SocketOptionArgument{unix.SO_LOCK_FILTER, "SO_LOCK_FILTER"} - SO_SELECT_ERR_QUEUE = SocketOptionArgument{unix.SO_SELECT_ERR_QUEUE, "SO_SELECT_ERR_QUEUE"} - SO_BUSY_POLL = SocketOptionArgument{unix.SO_BUSY_POLL, "SO_BUSY_POLL"} - SO_MAX_PACING_RATE = SocketOptionArgument{unix.SO_MAX_PACING_RATE, "SO_MAX_PACING_RATE"} - SO_BPF_EXTENSIONS = SocketOptionArgument{unix.SO_BPF_EXTENSIONS, "SO_BPF_EXTENSIONS"} - SO_INCOMING_CPU = SocketOptionArgument{unix.SO_INCOMING_CPU, "SO_INCOMING_CPU"} - SO_ATTACH_BPF = SocketOptionArgument{unix.SO_ATTACH_BPF, "SO_ATTACH_BPF"} - SO_ATTACH_REUSEPORT_CBPF = SocketOptionArgument{unix.SO_ATTACH_REUSEPORT_CBPF, "SO_ATTACH_REUSEPORT_CBPF"} - SO_ATTACH_REUSEPORT_EBPF = SocketOptionArgument{unix.SO_ATTACH_REUSEPORT_EBPF, "SO_ATTACH_REUSEPORT_EBPF"} - SO_CNX_ADVICE = SocketOptionArgument{unix.SO_CNX_ADVICE, "SO_CNX_ADVICE"} - SCM_TIMESTAMPING_OPT_STATS = SocketOptionArgument{unix.SCM_TIMESTAMPING_OPT_STATS, "SCM_TIMESTAMPING_OPT_STATS"} - SO_MEMINFO = SocketOptionArgument{unix.SO_MEMINFO, "SO_MEMINFO"} - SO_INCOMING_NAPI_ID = SocketOptionArgument{unix.SO_INCOMING_NAPI_ID, "SO_INCOMING_NAPI_ID"} - SO_COOKIE = SocketOptionArgument{unix.SO_COOKIE, "SO_COOKIE"} - SCM_TIMESTAMPING_PKTINFO = SocketOptionArgument{unix.SCM_TIMESTAMPING_PKTINFO, "SCM_TIMESTAMPING_PKTINFO"} - SO_PEERGROUPS = SocketOptionArgument{unix.SO_PEERGROUPS, "SO_PEERGROUPS"} - SO_ZEROCOPY = SocketOptionArgument{unix.SO_ZEROCOPY, "SO_ZEROCOPY"} - SO_TXTIME = SocketOptionArgument{unix.SO_TXTIME, "SO_TXTIME"} - SO_BINDTOIFINDEX = SocketOptionArgument{unix.SO_BINDTOIFINDEX, "SO_BINDTOIFINDEX"} - SO_TIMESTAMP_NEW = SocketOptionArgument{unix.SO_TIMESTAMP_NEW, "SO_TIMESTAMP_NEW"} - SO_TIMESTAMPNS_NEW = SocketOptionArgument{unix.SO_TIMESTAMPNS_NEW, "SO_TIMESTAMPNS_NEW"} - SO_TIMESTAMPING_NEW = SocketOptionArgument{unix.SO_TIMESTAMPING_NEW, "SO_TIMESTAMPING_NEW"} - SO_RCVTIMEO_NEW = SocketOptionArgument{unix.SO_RCVTIMEO_NEW, "SO_RCVTIMEO_NEW"} - SO_SNDTIMEO_NEW = SocketOptionArgument{unix.SO_SNDTIMEO_NEW, "SO_SNDTIMEO_NEW"} - SO_DETACH_REUSEPORT_BPF = SocketOptionArgument{unix.SO_DETACH_REUSEPORT_BPF, "SO_DETACH_REUSEPORT_BPF"} - SO_PREFER_BUSY_POLL = SocketOptionArgument{unix.SO_PREFER_BUSY_POLL, "SO_PREFER_BUSY_POLL"} - SO_BUSY_POLL_BUDGET = SocketOptionArgument{unix.SO_BUSY_POLL_BUDGET, "SO_BUSY_POLL_BUDGET"} - SO_TIMESTAMP = SocketOptionArgument{unix.SO_TIMESTAMP, "SO_TIMESTAMP"} - SO_TIMESTAMPNS = SocketOptionArgument{unix.SO_TIMESTAMPNS, "SO_TIMESTAMPNS"} - SO_TIMESTAMPING = SocketOptionArgument{unix.SO_TIMESTAMPING, "SO_TIMESTAMPING"} - SO_RCVTIMEO = SocketOptionArgument{unix.SO_RCVTIMEO, "SO_RCVTIMEO"} - SO_SNDTIMEO = SocketOptionArgument{unix.SO_SNDTIMEO, "SO_SNDTIMEO"} - - // The following are newer, so aren't included in the unix package - SO_NETNS_COOKIE SocketOptionArgument = SocketOptionArgument{71, "SO_NETNS_COOKIE"} - SO_BUF_LOCK SocketOptionArgument = SocketOptionArgument{72, "SO_BUF_LOCK"} - SO_RESERVE_MEM SocketOptionArgument = SocketOptionArgument{73, "SO_RESERVE_MEM"} - SO_TXREHASH SocketOptionArgument = SocketOptionArgument{74, "SO_TXREHASH"} -) - -func (socketOption SocketOptionArgument) Value() uint64 { return socketOption.value } - -func (socketOption SocketOptionArgument) String() string { - return socketOption.name -} - -var setSocketOptionMap = map[uint64]SocketOptionArgument{ - SO_DEBUG.Value(): SO_DEBUG, - SO_REUSEADDR.Value(): SO_REUSEADDR, - SO_TYPE.Value(): SO_TYPE, - SO_ERROR.Value(): SO_ERROR, - SO_DONTROUTE.Value(): SO_DONTROUTE, - SO_BROADCAST.Value(): SO_BROADCAST, - SO_SNDBUF.Value(): SO_SNDBUF, - SO_RCVBUF.Value(): SO_RCVBUF, - SO_SNDBUFFORCE.Value(): SO_SNDBUFFORCE, - SO_RCVBUFFORCE.Value(): SO_RCVBUFFORCE, - SO_KEEPALIVE.Value(): SO_KEEPALIVE, - SO_OOBINLINE.Value(): SO_OOBINLINE, - SO_NO_CHECK.Value(): SO_NO_CHECK, - SO_PRIORITY.Value(): SO_PRIORITY, - SO_LINGER.Value(): SO_LINGER, - SO_BSDCOMPAT.Value(): SO_BSDCOMPAT, - SO_REUSEPORT.Value(): SO_REUSEPORT, - SO_PASSCRED.Value(): SO_PASSCRED, - SO_PEERCRED.Value(): SO_PEERCRED, - SO_RCVLOWAT.Value(): SO_RCVLOWAT, - SO_SNDLOWAT.Value(): SO_SNDLOWAT, - SO_SECURITY_AUTHENTICATION.Value(): SO_SECURITY_AUTHENTICATION, - SO_SECURITY_ENCRYPTION_TRANSPORT.Value(): SO_SECURITY_ENCRYPTION_TRANSPORT, - SO_SECURITY_ENCRYPTION_NETWORK.Value(): SO_SECURITY_ENCRYPTION_NETWORK, - SO_BINDTODEVICE.Value(): SO_BINDTODEVICE, - SO_ATTACH_FILTER.Value(): SO_ATTACH_FILTER, - SO_DETACH_FILTER.Value(): SO_DETACH_FILTER, - SO_PEERNAME.Value(): SO_PEERNAME, - SO_ACCEPTCONN.Value(): SO_ACCEPTCONN, - SO_PEERSEC.Value(): SO_PEERSEC, - SO_PASSSEC.Value(): SO_PASSSEC, - SO_MARK.Value(): SO_MARK, - SO_PROTOCOL.Value(): SO_PROTOCOL, - SO_DOMAIN.Value(): SO_DOMAIN, - SO_RXQ_OVFL.Value(): SO_RXQ_OVFL, - SO_WIFI_STATUS.Value(): SO_WIFI_STATUS, - SO_PEEK_OFF.Value(): SO_PEEK_OFF, - SO_NOFCS.Value(): SO_NOFCS, - SO_LOCK_FILTER.Value(): SO_LOCK_FILTER, - SO_SELECT_ERR_QUEUE.Value(): SO_SELECT_ERR_QUEUE, - SO_BUSY_POLL.Value(): SO_BUSY_POLL, - SO_MAX_PACING_RATE.Value(): SO_MAX_PACING_RATE, - SO_BPF_EXTENSIONS.Value(): SO_BPF_EXTENSIONS, - SO_INCOMING_CPU.Value(): SO_INCOMING_CPU, - SO_ATTACH_BPF.Value(): SO_ATTACH_BPF, - SO_ATTACH_REUSEPORT_CBPF.Value(): SO_ATTACH_REUSEPORT_CBPF, - SO_ATTACH_REUSEPORT_EBPF.Value(): SO_ATTACH_REUSEPORT_EBPF, - SO_CNX_ADVICE.Value(): SO_CNX_ADVICE, - SCM_TIMESTAMPING_OPT_STATS.Value(): SCM_TIMESTAMPING_OPT_STATS, - SO_MEMINFO.Value(): SO_MEMINFO, - SO_INCOMING_NAPI_ID.Value(): SO_INCOMING_NAPI_ID, - SO_COOKIE.Value(): SO_COOKIE, - SCM_TIMESTAMPING_PKTINFO.Value(): SCM_TIMESTAMPING_PKTINFO, - SO_PEERGROUPS.Value(): SO_PEERGROUPS, - SO_ZEROCOPY.Value(): SO_ZEROCOPY, - SO_TXTIME.Value(): SO_TXTIME, - SO_BINDTOIFINDEX.Value(): SO_BINDTOIFINDEX, - SO_TIMESTAMP_NEW.Value(): SO_TIMESTAMP_NEW, - SO_TIMESTAMPNS_NEW.Value(): SO_TIMESTAMPNS_NEW, - SO_TIMESTAMPING_NEW.Value(): SO_TIMESTAMPING_NEW, - SO_RCVTIMEO_NEW.Value(): SO_RCVTIMEO_NEW, - SO_SNDTIMEO_NEW.Value(): SO_SNDTIMEO_NEW, - SO_DETACH_REUSEPORT_BPF.Value(): SO_DETACH_REUSEPORT_BPF, - SO_PREFER_BUSY_POLL.Value(): SO_PREFER_BUSY_POLL, - SO_BUSY_POLL_BUDGET.Value(): SO_BUSY_POLL_BUDGET, - SO_NETNS_COOKIE.Value(): SO_NETNS_COOKIE, - SO_BUF_LOCK.Value(): SO_BUF_LOCK, - SO_RESERVE_MEM.Value(): SO_RESERVE_MEM, - SO_TIMESTAMP.Value(): SO_TIMESTAMP, - SO_TIMESTAMPNS.Value(): SO_TIMESTAMPNS, - SO_TIMESTAMPING.Value(): SO_TIMESTAMPING, - SO_RCVTIMEO.Value(): SO_RCVTIMEO, - SO_SNDTIMEO.Value(): SO_SNDTIMEO, - SO_TXREHASH.Value(): SO_TXREHASH, -} - -var getSocketOptionMap = func(m map[uint64]SocketOptionArgument) map[uint64]SocketOptionArgument { - newMap := make(map[uint64]SocketOptionArgument, len(m)) - for k, v := range m { - newMap[k] = v - } - // Will override the value of SO_ATTACH_FILTER - newMap[SO_GET_FILTER.Value()] = SO_GET_FILTER - return newMap -}(setSocketOptionMap) - -// ParseSetSocketOption parses the `optname` argument of the `setsockopt` syscall. -// https://man7.org/linux/man-pages/man2/setsockopt.2.html -// https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/socket.h -func ParseSetSocketOption(rawValue uint64) (SocketOptionArgument, error) { - v, ok := setSocketOptionMap[rawValue] - if !ok { - return SocketOptionArgument{}, fmt.Errorf("not a valid argument: %d", rawValue) - } - return v, nil -} - -// ParseGetSocketOption parses the `optname` argument of the `getsockopt` syscall. -// https://man7.org/linux/man-pages/man2/getsockopt.2.html -// https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/socket.h -func ParseGetSocketOption(rawValue uint64) (SocketOptionArgument, error) { - v, ok := getSocketOptionMap[rawValue] - if !ok { - return SocketOptionArgument{}, fmt.Errorf("not a valid argument: %d", rawValue) - } - return v, nil -} - -// BPFProgType is an enum as defined in https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/bpf.h -type BPFProgType uint32 - -const ( - BPFProgTypeUnspec BPFProgType = iota - BPFProgTypeSocketFilter - BPFProgTypeKprobe - BPFProgTypeSchedCls - BPFProgTypeSchedAct - BPFProgTypeTracepoint - BPFProgTypeXdp - BPFProgTypePerfEvent - BPFProgTypeCgroupSkb - BPFProgTypeCgroupSock - BPFProgTypeLwtIn - BPFProgTypeLwtOut - BPFProgTypeLwtXmit - BPFProgTypeSockOps - BPFProgTypeSkSkb - BPFProgTypeCgroupDevice - BPFProgTypeSkMsg - BPFProgTypeRawTracepoint - BPFProgTypeCgroupSockAddr - BPFProgTypeLwtSeg6Local - BPFProgTypeLircMode2 - BPFProgTypeSkReuseport - BPFProgTypeFlowDissector - BPFProgTypeCgroupSysctl - BPFProgTypeRawTracepointWritable - BPFProgTypeCgroupSockopt - BPFProgTypeTracing - BPFProgTypeStructOps - BPFProgTypeExt - BPFProgTypeLsm - BPFProgTypeSkLookup - BPFProgTypeSyscall -) - -func (b BPFProgType) Value() uint64 { - return uint64(b) -} - -func (b BPFProgType) String() string { - x := map[BPFProgType]string{ - BPFProgTypeUnspec: "BPF_PROG_TYPE_UNSPEC", - BPFProgTypeSocketFilter: "BPF_PROG_TYPE_SOCKET_FILTER", - BPFProgTypeKprobe: "BPF_PROG_TYPE_KPROBE", - BPFProgTypeSchedCls: "BPF_PROG_TYPE_SCHED_CLS", - BPFProgTypeSchedAct: "BPF_PROG_TYPE_SCHED_ACT", - BPFProgTypeTracepoint: "BPF_PROG_TYPE_TRACEPOINT", - BPFProgTypeXdp: "BPF_PROG_TYPE_XDP", - BPFProgTypePerfEvent: "BPF_PROG_TYPE_PERF_EVENT", - BPFProgTypeCgroupSkb: "BPF_PROG_TYPE_CGROUP_SKB", - BPFProgTypeCgroupSock: "BPF_PROG_TYPE_CGROUP_SOCK", - BPFProgTypeLwtIn: "BPF_PROG_TYPE_LWT_IN", - BPFProgTypeLwtOut: "BPF_PROG_TYPE_LWT_OUT", - BPFProgTypeLwtXmit: "BPF_PROG_TYPE_LWT_XMIT", - BPFProgTypeSockOps: "BPF_PROG_TYPE_SOCK_OPS", - BPFProgTypeSkSkb: "BPF_PROG_TYPE_SK_SKB", - BPFProgTypeCgroupDevice: "BPF_PROG_TYPE_CGROUP_DEVICE", - BPFProgTypeSkMsg: "BPF_PROG_TYPE_SK_MSG", - BPFProgTypeRawTracepoint: "BPF_PROG_TYPE_RAW_TRACEPOINT", - BPFProgTypeCgroupSockAddr: "BPF_PROG_TYPE_CGROUP_SOCK_ADDR", - BPFProgTypeLwtSeg6Local: "BPF_PROG_TYPE_LWT_SEG6LOCAL", - BPFProgTypeLircMode2: "BPF_PROG_TYPE_LIRC_MODE2", - BPFProgTypeSkReuseport: "BPF_PROG_TYPE_SK_REUSEPORT", - BPFProgTypeFlowDissector: "BPF_PROG_TYPE_FLOW_DISSECTOR", - BPFProgTypeCgroupSysctl: "BPF_PROG_TYPE_CGROUP_SYSCTL", - BPFProgTypeRawTracepointWritable: "BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE", - BPFProgTypeCgroupSockopt: "BPF_PROG_TYPE_CGROUP_SOCKOPT", - BPFProgTypeTracing: "BPF_PROG_TYPE_TRACING", - BPFProgTypeStructOps: "BPF_PROG_TYPE_STRUCT_OPS", - BPFProgTypeExt: "BPF_PROG_TYPE_EXT", - BPFProgTypeLsm: "BPF_PROG_TYPE_LSM", - BPFProgTypeSkLookup: "BPF_PROG_TYPE_SK_LOOKUP", - BPFProgTypeSyscall: "BPF_PROG_TYPE_SYSCALL", - } - str, found := x[b] - if !found { - str = BPFProgTypeUnspec.String() - } - return str -} - -var bpfProgTypeMap = map[uint64]BPFProgType{ - BPFProgTypeUnspec.Value(): BPFProgTypeUnspec, - BPFProgTypeSocketFilter.Value(): BPFProgTypeSocketFilter, - BPFProgTypeKprobe.Value(): BPFProgTypeKprobe, - BPFProgTypeSchedCls.Value(): BPFProgTypeSchedCls, - BPFProgTypeSchedAct.Value(): BPFProgTypeSchedAct, - BPFProgTypeTracepoint.Value(): BPFProgTypeTracepoint, - BPFProgTypeXdp.Value(): BPFProgTypeXdp, - BPFProgTypePerfEvent.Value(): BPFProgTypePerfEvent, - BPFProgTypeCgroupSkb.Value(): BPFProgTypeCgroupSkb, - BPFProgTypeCgroupSock.Value(): BPFProgTypeCgroupSock, - BPFProgTypeLwtIn.Value(): BPFProgTypeLwtIn, - BPFProgTypeLwtOut.Value(): BPFProgTypeLwtOut, - BPFProgTypeLwtXmit.Value(): BPFProgTypeLwtXmit, - BPFProgTypeSockOps.Value(): BPFProgTypeSockOps, - BPFProgTypeSkSkb.Value(): BPFProgTypeSkSkb, - BPFProgTypeCgroupDevice.Value(): BPFProgTypeCgroupDevice, - BPFProgTypeSkMsg.Value(): BPFProgTypeSkMsg, - BPFProgTypeRawTracepoint.Value(): BPFProgTypeRawTracepoint, - BPFProgTypeCgroupSockAddr.Value(): BPFProgTypeCgroupSockAddr, - BPFProgTypeLwtSeg6Local.Value(): BPFProgTypeLwtSeg6Local, - BPFProgTypeLircMode2.Value(): BPFProgTypeLircMode2, - BPFProgTypeSkReuseport.Value(): BPFProgTypeSkReuseport, - BPFProgTypeFlowDissector.Value(): BPFProgTypeFlowDissector, - BPFProgTypeCgroupSysctl.Value(): BPFProgTypeCgroupSysctl, - BPFProgTypeRawTracepointWritable.Value(): BPFProgTypeRawTracepointWritable, - BPFProgTypeCgroupSockopt.Value(): BPFProgTypeCgroupSockopt, - BPFProgTypeTracing.Value(): BPFProgTypeTracing, - BPFProgTypeStructOps.Value(): BPFProgTypeStructOps, - BPFProgTypeExt.Value(): BPFProgTypeExt, - BPFProgTypeLsm.Value(): BPFProgTypeLsm, - BPFProgTypeSkLookup.Value(): BPFProgTypeSkLookup, - BPFProgTypeSyscall.Value(): BPFProgTypeSyscall, -} - -func ParseBPFProgType(rawValue uint64) (BPFProgType, error) { - v, ok := bpfProgTypeMap[rawValue] - if !ok { - return BPFProgType(0), fmt.Errorf("not a valid argument: %d", rawValue) - } - return v, nil -} - -type MmapFlagArgument struct { - rawValue uint32 - stringValue string -} - -const ( - HugetlbFlagEncodeShift = 26 - MapHugeSizeMask = ((1 << 6) - 1) << HugetlbFlagEncodeShift -) - -var ( - MapShared MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_SHARED, stringValue: "MAP_SHARED"} - MapPrivate MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_PRIVATE, stringValue: "MAP_PRIVATE"} - MapSharedValidate MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_SHARED_VALIDATE, stringValue: "MAP_SHARED_VALIDATE"} - MapType MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_TYPE, stringValue: "MAP_TYPE"} - MapFixed MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_FIXED, stringValue: "MAP_FIXED"} - MapAnonymous MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_ANONYMOUS, stringValue: "MAP_ANONYMOUS"} - MapPopulate MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_POPULATE, stringValue: "MAP_POPULATE"} - MapNonblock MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_NONBLOCK, stringValue: "MAP_NONBLOCK"} - MapStack MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_STACK, stringValue: "MAP_STACK"} - MapHugetlb MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_HUGETLB, stringValue: "MAP_HUGETLB"} - MapSync MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_SYNC, stringValue: "MAP_SYNC"} - MapFixedNoreplace MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_FIXED_NOREPLACE, stringValue: "MAP_FIXED_NOREPLACE"} - MapGrowsdown MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_GROWSDOWN, stringValue: "MAP_GROWSDOWN"} - MapDenywrite MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_DENYWRITE, stringValue: "MAP_DENYWRITE"} - MapExecutable MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_EXECUTABLE, stringValue: "MAP_EXECUTABLE"} - MapLocked MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_LOCKED, stringValue: "MAP_LOCKED"} - MapNoreserve MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_NORESERVE, stringValue: "MAP_NORESERVE"} - MapFile MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_FILE, stringValue: "MAP_FILE"} - MapHuge2MB MmapFlagArgument = MmapFlagArgument{rawValue: 21 << HugetlbFlagEncodeShift, stringValue: "MAP_HUGE_2MB"} - MapHuge1GB MmapFlagArgument = MmapFlagArgument{rawValue: 30 << HugetlbFlagEncodeShift, stringValue: "MAP_HUGE_1GB"} - MapSYNC MmapFlagArgument = MmapFlagArgument{rawValue: unix.MAP_SYNC, stringValue: "MAP_SYNC"} - // TODO: Add support for MAP_UNINITIALIZED which collide with Huge TLB size bits -) - -var mmapFlagMap = map[uint64]MmapFlagArgument{ - MapShared.Value(): MapShared, - MapPrivate.Value(): MapPrivate, - MapSharedValidate.Value(): MapSharedValidate, - MapType.Value(): MapType, - MapFixed.Value(): MapFixed, - MapAnonymous.Value(): MapAnonymous, - MapPopulate.Value(): MapPopulate, - MapNonblock.Value(): MapNonblock, - MapStack.Value(): MapStack, - MapHugetlb.Value(): MapHugetlb, - MapSync.Value(): MapSync, - MapFixedNoreplace.Value(): MapFixedNoreplace, - MapGrowsdown.Value(): MapGrowsdown, - MapDenywrite.Value(): MapDenywrite, - MapExecutable.Value(): MapExecutable, - MapLocked.Value(): MapLocked, - MapNoreserve.Value(): MapNoreserve, - MapFile.Value(): MapFile, - MapHuge2MB.Value(): MapHuge2MB, - MapHuge1GB.Value(): MapHuge1GB, - MapSYNC.Value(): MapSYNC, -} - -func (mf MmapFlagArgument) Value() uint64 { - return uint64(mf.rawValue) -} - -func (mf MmapFlagArgument) String() string { - return mf.stringValue -} - -// getHugeMapSizeFlagString extract the huge flag size flag from the mmap flags. -// This flag is special, because it is 6-bits representation of the log2 of the size. -// For more information - https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/hugetlb_encode.h -func getHugeMapSizeFlagString(flags uint32) MmapFlagArgument { - hugeSizeFlagVal := flags & MapHugeSizeMask - // The size given in the flags is log2 of the size of the pages - mapHugeSizePower := hugeSizeFlagVal >> HugetlbFlagEncodeShift - - // Create a name of a flag matching given huge page size - // The size is 6 bits, so maximum value is 16EB - unitsPrefix := []string{"", "K", "M", "G", "T", "P", "E"} - var unitPrefix string - var inUnitSize uint - for i, prefix := range unitsPrefix { - if mapHugeSizePower < ((uint32(i) + 1) * 10) { - unitPrefix = prefix - inUnitSize = 1 << (mapHugeSizePower % 10) - break - } - } - return MmapFlagArgument{rawValue: hugeSizeFlagVal, stringValue: fmt.Sprintf("MAP_HUGE_%d%sB", inUnitSize, unitPrefix)} -} - -// ParseMmapFlags parses the `flags` bitmask argument of the `mmap` syscall -// http://man7.org/linux/man-pages/man2/mmap.2.html -// https://elixir.bootlin.com/linux/v5.5.3/source/include/uapi/asm-generic/mman-common.h#L19 -func ParseMmapFlags(rawValue uint64) MmapFlagArgument { - var f []string - for i := 0; i < HugetlbFlagEncodeShift; i++ { - flagMask := 1 << i - - if (rawValue & uint64(flagMask)) != 0 { - flag, ok := mmapFlagMap[1< baseValue { - return KernelVersionNewer, nil - } else if givenValue < baseValue { - return KernelVersionOlder, nil - } else { - continue - } - } - return KernelVersionEqual, nil -} diff --git a/vendor/github.com/aquasecurity/libbpfgo/helpers/elf.go b/vendor/github.com/aquasecurity/libbpfgo/helpers/elf.go deleted file mode 100644 index bdb13a653a..0000000000 --- a/vendor/github.com/aquasecurity/libbpfgo/helpers/elf.go +++ /dev/null @@ -1,59 +0,0 @@ -package helpers - -import ( - "debug/elf" - "errors" - "fmt" -) - -// SymbolToOffset attempts to resolve a 'symbol' name in the binary found at -// 'path' to an offset. The offset can be used for attaching a u(ret)probe -func SymbolToOffset(path, symbol string) (uint32, error) { - f, err := elf.Open(path) - if err != nil { - return 0, fmt.Errorf("could not open elf file to resolve symbol offset: %w", err) - } - - regularSymbols, regularSymbolsErr := f.Symbols() - dynamicSymbols, dynamicSymbolsErr := f.DynamicSymbols() - - // Only if we failed getting both regular and dynamic symbols - then we abort. - if regularSymbolsErr != nil && dynamicSymbolsErr != nil { - return 0, fmt.Errorf("could not open regular or dynamic symbol sections to resolve symbol offset: %w %s", regularSymbolsErr, dynamicSymbolsErr) - } - - // Concatenating into a single list. - // The list can have duplications, but we will find the first occurrence which is sufficient. - syms := append(regularSymbols, dynamicSymbols...) - - sectionsToSearchForSymbol := []*elf.Section{} - - for i := range f.Sections { - if f.Sections[i].Flags == elf.SHF_ALLOC+elf.SHF_EXECINSTR { - sectionsToSearchForSymbol = append(sectionsToSearchForSymbol, f.Sections[i]) - } - } - - var executableSection *elf.Section - - for j := range syms { - if syms[j].Name == symbol { - // Find what section the symbol is in by checking the executable section's - // addr space. - for m := range sectionsToSearchForSymbol { - if syms[j].Value > sectionsToSearchForSymbol[m].Addr && - syms[j].Value < sectionsToSearchForSymbol[m].Addr+sectionsToSearchForSymbol[m].Size { - executableSection = sectionsToSearchForSymbol[m] - } - } - - if executableSection == nil { - return 0, errors.New("could not find symbol in executable sections of binary") - } - - return uint32(syms[j].Value - executableSection.Addr + executableSection.Offset), nil - } - } - - return 0, fmt.Errorf("symbol %s not found in %s", symbol, path) -} diff --git a/vendor/github.com/aquasecurity/libbpfgo/helpers/kernel_config.go b/vendor/github.com/aquasecurity/libbpfgo/helpers/kernel_config.go deleted file mode 100644 index c93eda51e5..0000000000 --- a/vendor/github.com/aquasecurity/libbpfgo/helpers/kernel_config.go +++ /dev/null @@ -1,399 +0,0 @@ -package helpers - -import ( - "bufio" - "compress/gzip" - "fmt" - "io" - "os" - "path/filepath" - "strings" -) - -// KernelConfigOption is an abstraction of the key in key=value syntax of the kernel config file -type KernelConfigOption uint32 - -// KernelConfigOptionValue is an abstraction of the value in key=value syntax of kernel config file -type KernelConfigOptionValue uint8 - -const ( - UNDEFINED KernelConfigOptionValue = iota - BUILTIN - MODULE - STRING - ANY -) - -func (k KernelConfigOption) String() string { - return kernelConfigKeyIDToString[k] -} - -func (k KernelConfigOptionValue) String() string { - switch k { - case UNDEFINED: - return "UNDEFINED" - case BUILTIN: - return "BUILTIN" - case MODULE: - return "MODULE" - case STRING: - return "STRING" - case ANY: - return "ANY" - } - - return "" -} - -// These constants are a limited number of the total kernel config options, -// but are provided because they are most relevant for BPF development. - -const ( - CONFIG_BPF KernelConfigOption = iota + 1 - CONFIG_BPF_SYSCALL - CONFIG_HAVE_EBPF_JIT - CONFIG_BPF_JIT - CONFIG_BPF_JIT_ALWAYS_ON - CONFIG_CGROUPS - CONFIG_CGROUP_BPF - CONFIG_CGROUP_NET_CLASSID - CONFIG_SOCK_CGROUP_DATA - CONFIG_BPF_EVENTS - CONFIG_KPROBE_EVENTS - CONFIG_UPROBE_EVENTS - CONFIG_TRACING - CONFIG_FTRACE_SYSCALLS - CONFIG_FUNCTION_ERROR_INJECTION - CONFIG_BPF_KPROBE_OVERRIDE - CONFIG_NET - CONFIG_XDP_SOCKETS - CONFIG_LWTUNNEL_BPF - CONFIG_NET_ACT_BPF - CONFIG_NET_CLS_BPF - CONFIG_NET_CLS_ACT - CONFIG_NET_SCH_INGRESS - CONFIG_XFRM - CONFIG_IP_ROUTE_CLASSID - CONFIG_IPV6_SEG6_BPF - CONFIG_BPF_LIRC_MODE2 - CONFIG_BPF_STREAM_PARSER - CONFIG_NETFILTER_XT_MATCH_BPF - CONFIG_BPFILTER - CONFIG_BPFILTER_UMH - CONFIG_TEST_BPF - CONFIG_HZ - CONFIG_DEBUG_INFO_BTF - CONFIG_DEBUG_INFO_BTF_MODULES - CONFIG_BPF_LSM - CONFIG_BPF_PRELOAD - CONFIG_BPF_PRELOAD_UMD - CUSTOM_OPTION_START KernelConfigOption = 1000 -) - -var kernelConfigKeyStringToID = map[string]KernelConfigOption{ - "CONFIG_BPF": CONFIG_BPF, - "CONFIG_BPF_SYSCALL": CONFIG_BPF_SYSCALL, - "CONFIG_HAVE_EBPF_JIT": CONFIG_HAVE_EBPF_JIT, - "CONFIG_BPF_JIT": CONFIG_BPF_JIT, - "CONFIG_BPF_JIT_ALWAYS_ON": CONFIG_BPF_JIT_ALWAYS_ON, - "CONFIG_CGROUPS": CONFIG_CGROUPS, - "CONFIG_CGROUP_BPF": CONFIG_CGROUP_BPF, - "CONFIG_CGROUP_NET_CLASSID": CONFIG_CGROUP_NET_CLASSID, - "CONFIG_SOCK_CGROUP_DATA": CONFIG_SOCK_CGROUP_DATA, - "CONFIG_BPF_EVENTS": CONFIG_BPF_EVENTS, - "CONFIG_KPROBE_EVENTS": CONFIG_KPROBE_EVENTS, - "CONFIG_UPROBE_EVENTS": CONFIG_UPROBE_EVENTS, - "CONFIG_TRACING": CONFIG_TRACING, - "CONFIG_FTRACE_SYSCALLS": CONFIG_FTRACE_SYSCALLS, - "CONFIG_FUNCTION_ERROR_INJECTION": CONFIG_FUNCTION_ERROR_INJECTION, - "CONFIG_BPF_KPROBE_OVERRIDE": CONFIG_BPF_KPROBE_OVERRIDE, - "CONFIG_NET": CONFIG_NET, - "CONFIG_XDP_SOCKETS": CONFIG_XDP_SOCKETS, - "CONFIG_LWTUNNEL_BPF": CONFIG_LWTUNNEL_BPF, - "CONFIG_NET_ACT_BPF": CONFIG_NET_ACT_BPF, - "CONFIG_NET_CLS_BPF": CONFIG_NET_CLS_BPF, - "CONFIG_NET_CLS_ACT": CONFIG_NET_CLS_ACT, - "CONFIG_NET_SCH_INGRESS": CONFIG_NET_SCH_INGRESS, - "CONFIG_XFRM": CONFIG_XFRM, - "CONFIG_IP_ROUTE_CLASSID": CONFIG_IP_ROUTE_CLASSID, - "CONFIG_IPV6_SEG6_BPF": CONFIG_IPV6_SEG6_BPF, - "CONFIG_BPF_LIRC_MODE2": CONFIG_BPF_LIRC_MODE2, - "CONFIG_BPF_STREAM_PARSER": CONFIG_BPF_STREAM_PARSER, - "CONFIG_NETFILTER_XT_MATCH_BPF": CONFIG_NETFILTER_XT_MATCH_BPF, - "CONFIG_BPFILTER": CONFIG_BPFILTER, - "CONFIG_BPFILTER_UMH": CONFIG_BPFILTER_UMH, - "CONFIG_TEST_BPF": CONFIG_TEST_BPF, - "CONFIG_HZ": CONFIG_HZ, - "CONFIG_DEBUG_INFO_BTF": CONFIG_DEBUG_INFO_BTF, - "CONFIG_DEBUG_INFO_BTF_MODULES": CONFIG_DEBUG_INFO_BTF_MODULES, - "CONFIG_BPF_LSM": CONFIG_BPF_LSM, - "CONFIG_BPF_PRELOAD": CONFIG_BPF_PRELOAD, - "CONFIG_BPF_PRELOAD_UMD": CONFIG_BPF_PRELOAD_UMD, -} - -var kernelConfigKeyIDToString = map[KernelConfigOption]string{ - CONFIG_BPF: "CONFIG_BPF", - CONFIG_BPF_SYSCALL: "CONFIG_BPF_SYSCALL", - CONFIG_HAVE_EBPF_JIT: "CONFIG_HAVE_EBPF_JIT", - CONFIG_BPF_JIT: "CONFIG_BPF_JIT", - CONFIG_BPF_JIT_ALWAYS_ON: "CONFIG_BPF_JIT_ALWAYS_ON", - CONFIG_CGROUPS: "CONFIG_CGROUPS", - CONFIG_CGROUP_BPF: "CONFIG_CGROUP_BPF", - CONFIG_CGROUP_NET_CLASSID: "CONFIG_CGROUP_NET_CLASSID", - CONFIG_SOCK_CGROUP_DATA: "CONFIG_SOCK_CGROUP_DATA", - CONFIG_BPF_EVENTS: "CONFIG_BPF_EVENTS", - CONFIG_KPROBE_EVENTS: "CONFIG_KPROBE_EVENTS", - CONFIG_UPROBE_EVENTS: "CONFIG_UPROBE_EVENTS", - CONFIG_TRACING: "CONFIG_TRACING", - CONFIG_FTRACE_SYSCALLS: "CONFIG_FTRACE_SYSCALLS", - CONFIG_FUNCTION_ERROR_INJECTION: "CONFIG_FUNCTION_ERROR_INJECTION", - CONFIG_BPF_KPROBE_OVERRIDE: "CONFIG_BPF_KPROBE_OVERRIDE", - CONFIG_NET: "CONFIG_NET", - CONFIG_XDP_SOCKETS: "CONFIG_XDP_SOCKETS", - CONFIG_LWTUNNEL_BPF: "CONFIG_LWTUNNEL_BPF", - CONFIG_NET_ACT_BPF: "CONFIG_NET_ACT_BPF", - CONFIG_NET_CLS_BPF: "CONFIG_NET_CLS_BPF", - CONFIG_NET_CLS_ACT: "CONFIG_NET_CLS_ACT", - CONFIG_NET_SCH_INGRESS: "CONFIG_NET_SCH_INGRESS", - CONFIG_XFRM: "CONFIG_XFRM", - CONFIG_IP_ROUTE_CLASSID: "CONFIG_IP_ROUTE_CLASSID", - CONFIG_IPV6_SEG6_BPF: "CONFIG_IPV6_SEG6_BPF", - CONFIG_BPF_LIRC_MODE2: "CONFIG_BPF_LIRC_MODE2", - CONFIG_BPF_STREAM_PARSER: "CONFIG_BPF_STREAM_PARSER", - CONFIG_NETFILTER_XT_MATCH_BPF: "CONFIG_NETFILTER_XT_MATCH_BPF", - CONFIG_BPFILTER: "CONFIG_BPFILTER", - CONFIG_BPFILTER_UMH: "CONFIG_BPFILTER_UMH", - CONFIG_TEST_BPF: "CONFIG_TEST_BPF", - CONFIG_HZ: "CONFIG_HZ", - CONFIG_DEBUG_INFO_BTF: "CONFIG_DEBUG_INFO_BTF", - CONFIG_DEBUG_INFO_BTF_MODULES: "CONFIG_DEBUG_INFO_BTF_MODULES", - CONFIG_BPF_LSM: "CONFIG_BPF_LSM", - CONFIG_BPF_PRELOAD: "CONFIG_BPF_PRELOAD", - CONFIG_BPF_PRELOAD_UMD: "CONFIG_BPF_PRELOAD_UMD", -} - -// KernelConfig is a set of kernel configuration options (currently for running OS only) -type KernelConfig struct { - configs map[KernelConfigOption]interface{} // predominantly KernelConfigOptionValue, sometimes string - needed map[KernelConfigOption]interface{} - kConfigFilePath string -} - -// InitKernelConfig inits external KernelConfig object -func InitKernelConfig() (*KernelConfig, error) { - config := KernelConfig{} - - // special case: user provided kconfig file (it MUST exist) - - osKConfigFilePath, err := checkEnvPath("LIBBPFGO_KCONFIG_FILE") // override /proc/config.gz or /boot/config-$(uname -r) if needed (containers) - if err != nil { - return &config, err - } - if len(osKConfigFilePath) > 2 { - if _, err := os.Stat(osKConfigFilePath); err != nil { - return &config, err - } - config.kConfigFilePath = osKConfigFilePath - if err := config.initKernelConfig(osKConfigFilePath); err != nil { - return &config, err - } - - return &config, nil - } - - // fastpath: check config.gz in procfs first - - configGZ := "/proc/config.gz" - if _, err1 := os.Stat(configGZ); err1 == nil { - config.kConfigFilePath = configGZ - if err2 := config.initKernelConfig(configGZ); err2 != nil { - return &config, err2 - } - - return &config, nil - } // ignore if /proc/config.gz does not exist - - // slowerpath: /boot/$(uname -r) - - releaseVersion, err := UnameRelease() - if err != nil { - return &config, err - } - - releaseFilePath := fmt.Sprintf("/boot/config-%s", releaseVersion) - config.kConfigFilePath = releaseFilePath - err = config.initKernelConfig(releaseFilePath) - - return &config, err -} - -// GetKernelConfigFilePath gives the kconfig file chosen by InitKernelConfig during initialization -func (k *KernelConfig) GetKernelConfigFilePath() string { - return k.kConfigFilePath -} - -// AddCustomKernelConfig allows user to extend list of possible existing kconfigs to be parsed from kConfigFilePath -func (k *KernelConfig) AddCustomKernelConfig(key KernelConfigOption, value string) error { - if key < CUSTOM_OPTION_START { - return fmt.Errorf("KConfig key index must be bigger than %d (CUSTOM_OPTION_START)\n", CUSTOM_OPTION_START) - } - - // extend initial list of kconfig options: add other possible existing ones - kernelConfigKeyIDToString[key] = value - kernelConfigKeyStringToID[value] = key - - return nil -} - -// LoadKernelConfig will (re)read kconfig file (likely after AddCustomKernelConfig was called) -func (k *KernelConfig) LoadKernelConfig() error { - return k.initKernelConfig(k.kConfigFilePath) -} - -// initKernelConfig inits internal KernelConfig data by calling appropriate readConfigFromXXX function -func (k *KernelConfig) initKernelConfig(configFilePath string) error { - if _, err := os.Stat(configFilePath); err != nil { - return fmt.Errorf("could not read %v: %w", configFilePath, err) - } - - if strings.Compare(filepath.Ext(configFilePath), ".gz") == 0 { - return k.readConfigFromProcConfigGZ(configFilePath) - } - - return k.readConfigFromBootConfigRelease(configFilePath) // assume it is a txt file by default -} - -// readConfigFromBootConfigRelease prepares io.Reader (/boot/config-$(uname -r)) for readConfigFromScanner -func (k *KernelConfig) readConfigFromBootConfigRelease(filePath string) error { - file, _ := os.Open(filePath) // already checked - k.readConfigFromScanner(file) - file.Close() - - return nil -} - -// readConfigFromProcConfigGZ prepares gziped io.Reader (/proc/config.gz) for readConfigFromScanner -func (k *KernelConfig) readConfigFromProcConfigGZ(filePath string) error { - file, _ := os.Open(filePath) // already checked - zreader, _ := gzip.NewReader(file) - k.readConfigFromScanner(zreader) - zreader.Close() - file.Close() - - return nil -} - -// readConfigFromScanner reads all existing KernelConfigOption's and KernelConfigOptionValue's from given io.Reader -func (k *KernelConfig) readConfigFromScanner(reader io.Reader) { - - if k.configs == nil { - k.configs = make(map[KernelConfigOption]interface{}) - } - if k.needed == nil { - k.needed = make(map[KernelConfigOption]interface{}) - } - - scanner := bufio.NewScanner(reader) - for scanner.Scan() { - kv := strings.Split(scanner.Text(), "=") - if len(kv) != 2 { - continue - } - - configKeyID := kernelConfigKeyStringToID[kv[0]] - if configKeyID == 0 { - continue - } - if strings.Compare(kv[1], "m") == 0 { - k.configs[configKeyID] = MODULE - } else if strings.Compare(kv[1], "y") == 0 { - k.configs[configKeyID] = BUILTIN - } else { - k.configs[configKeyID] = kv[1] - } - } -} - -// GetValue will return a KernelConfigOptionValue for a given KernelConfigOption when this is a BUILTIN or a MODULE -func (k *KernelConfig) GetValue(option KernelConfigOption) KernelConfigOptionValue { - value, ok := k.configs[KernelConfigOption(option)].(KernelConfigOptionValue) - if ok { - return value - } - - return UNDEFINED // not an error as the config option might not exist in kconfig file -} - -// GetValueString will return a KernelConfigOptionValue for a given KernelConfigOption when this is actually a string -func (k *KernelConfig) GetValueString(option KernelConfigOption) (string, error) { - value, ok := k.configs[option].(string) - if ok { - return value, nil - } - - return "", fmt.Errorf("given option's value (%s) is not a string", option) -} - -// Exists will return true if a given KernelConfigOption was found in provided KernelConfig -// and it will return false if the KernelConfigOption is not set (# XXXXX is not set) -// -// Examples: -// kernelConfig.Exists(helpers.CONFIG_BPF) -// kernelConfig.Exists(helpers.CONFIG_BPF_PRELOAD) -// kernelConfig.Exists(helpers.CONFIG_HZ) -// -func (k *KernelConfig) Exists(option KernelConfigOption) bool { - if _, ok := k.configs[option]; ok { - return true - } - - return false -} - -// ExistsValue will return true if a given KernelConfigOption was found in provided KernelConfig -// AND its value is the same as the one provided by KernelConfigOptionValue -func (k *KernelConfig) ExistsValue(option KernelConfigOption, value interface{}) bool { - if cfg, ok := k.configs[option]; ok { - switch cfg.(type) { - case KernelConfigOptionValue: - if value == ANY { - return true - } else if k.configs[option].(KernelConfigOptionValue) == value { - return true - } - case string: - if strings.Compare(k.configs[option].(string), value.(string)) == 0 { - return true - } - } - } - - return false -} - -// CheckMissing returns an array of KernelConfigOption's that were added to KernelConfig as needed but couldn't be -// found. It returns an empty array if nothing is missing. -func (k *KernelConfig) CheckMissing() []KernelConfigOption { - missing := make([]KernelConfigOption, 0) - - for key, value := range k.needed { - if !k.ExistsValue(key, value) { - missing = append(missing, key) - } - } - - return missing -} - -// AddNeeded adds a KernelConfigOption and its value, if needed, as required for further checks with CheckMissing -// -// Examples: -// kernelConfig.AddNeeded(helpers.CONFIG_BPF, helpers.ANY) -// kernelConfig.AddNeeded(helpers.CONFIG_BPF_PRELOAD, helpers.ANY) -// kernelConfig.AddNeeded(helpers.CONFIG_HZ, "250") -// -func (k *KernelConfig) AddNeeded(option KernelConfigOption, value interface{}) { - if _, ok := kernelConfigKeyIDToString[option]; ok { - k.needed[option] = value - } -} diff --git a/vendor/github.com/aquasecurity/libbpfgo/helpers/kernel_symbols.go b/vendor/github.com/aquasecurity/libbpfgo/helpers/kernel_symbols.go deleted file mode 100644 index 767581ac10..0000000000 --- a/vendor/github.com/aquasecurity/libbpfgo/helpers/kernel_symbols.go +++ /dev/null @@ -1,121 +0,0 @@ -package helpers - -import ( - "bufio" - "errors" - "fmt" - "os" - "strconv" - "strings" -) - -/* - * The helpers in this file gives the ability to hold all the known kernel symbols. - * the package parse the /proc/kallsyms file that hold the known kernel symbol - * - * The KernelSymbolTable type holds map of all the kernel symbols with a key which is the kernel object owner and the name with under-case between them - * which means that symbolMap looks like [objectOwner_objectname{SymbolData}, objectOwner_objectname{SymbolData}, etc...] - * the key naming is because sometimes kernel symbols can have the same name or the same address which prevents to key the map with only one of them - * - */ - -type KernelSymbolTable struct { - symbolMap map[string]KernelSymbol - symbolAddrMap map[uint64]KernelSymbol - initialized bool -} - -type KernelSymbol struct { - Name string - Type string - Address uint64 - Owner string -} - -/* NewKernelSymbolsMap initiates the kernel symbol map by parsing the /proc/kallsyms file. - * each line contains the symbol's address, segment type, name, module owner (which can be empty in case the symbol is owned by the system) - * Note: the key of the map is the symbol owner and the symbol name (with undercase between them) - */ -func NewKernelSymbolsMap() (*KernelSymbolTable, error) { - var KernelSymbols = KernelSymbolTable{} - KernelSymbols.symbolMap = make(map[string]KernelSymbol) - KernelSymbols.symbolAddrMap = make(map[uint64]KernelSymbol) - file, err := os.Open("/proc/kallsyms") - if err != nil { - return nil, fmt.Errorf("could not open /proc/kallsyms: %w", err) - } - defer file.Close() - scanner := bufio.NewScanner(file) - scanner.Split(bufio.ScanLines) - for scanner.Scan() { - line := strings.Fields(scanner.Text()) - //if the line is less than 3 words, we can't parse it (one or more fields missing) - if len(line) < 3 { - continue - } - symbolAddr, err := strconv.ParseUint(line[0], 16, 64) - if err != nil { - continue - } - symbolType := line[1] - symbolName := line[2] - - symbolOwner := "system" - if len(line) > 3 { - // When a symbol is contained in a kernel module, it will be specified - // within square brackets, otherwise it's part of the system - symbolOwner = line[3] - symbolOwner = strings.TrimPrefix(symbolOwner, "[") - symbolOwner = strings.TrimSuffix(symbolOwner, "]") - } - - symbolKey := fmt.Sprintf("%s_%s", symbolOwner, symbolName) - symbol := KernelSymbol{symbolName, symbolType, symbolAddr, symbolOwner} - KernelSymbols.symbolMap[symbolKey] = symbol - KernelSymbols.symbolAddrMap[symbolAddr] = symbol - } - KernelSymbols.initialized = true - return &KernelSymbols, nil -} - -// TextSegmentContains checks if a given address is in the kernel text segment -// by comparing it to the kernel text segment address boundaries -func (k *KernelSymbolTable) TextSegmentContains(addr uint64) (bool, error) { - if !k.initialized { - return false, errors.New("kernel symbols map isnt initialized") - } - stext, err := k.GetSymbolByName("system", "_stext") - if err != nil { - return false, err - } - etext, err := k.GetSymbolByName("system", "_etext") - if err != nil { - return false, err - } - return ((addr >= stext.Address) && (addr < etext.Address)), nil -} - -// GetSymbolByName returns a symbol by a given name and owner -func (k *KernelSymbolTable) GetSymbolByName(owner string, name string) (*KernelSymbol, error) { - if !k.initialized { - return nil, errors.New("kernel symbols map isnt initialized") - } - key := fmt.Sprintf("%s_%s", owner, name) - symbol, exist := k.symbolMap[key] - if exist { - return &symbol, nil - } - return nil, fmt.Errorf("symbol not found: %s_%s", owner, name) -} - -// GetSymbolByAddr returns a symbol by a given address -func (k *KernelSymbolTable) GetSymbolByAddr(addr uint64) (*KernelSymbol, error) { - if !k.initialized { - return nil, errors.New("kernel symbols map isnt initialized") - } - symbol, exist := k.symbolAddrMap[addr] - if exist { - return &symbol, nil - } - return nil, fmt.Errorf("symbol not found at address: 0x%x", addr) -} diff --git a/vendor/github.com/aquasecurity/libbpfgo/helpers/osinfo.go b/vendor/github.com/aquasecurity/libbpfgo/helpers/osinfo.go deleted file mode 100644 index 4e530406e6..0000000000 --- a/vendor/github.com/aquasecurity/libbpfgo/helpers/osinfo.go +++ /dev/null @@ -1,290 +0,0 @@ -package helpers - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "os" - "strings" -) - -type OSReleaseID uint32 - -func (o OSReleaseID) String() string { - return osReleaseIDToString[o] -} - -const ( - UBUNTU OSReleaseID = iota + 1 - FEDORA - ARCH - DEBIAN - CENTOS - STREAM - ALMA -) - -// stringToOSReleaseID is a map of supported distributions -var stringToOSReleaseID = map[string]OSReleaseID{ - "ubuntu": UBUNTU, - "fedora": FEDORA, - "arch": ARCH, - "debian": DEBIAN, - "centos": CENTOS, - "stream": STREAM, - "alma": ALMA, -} - -// osReleaseIDToString is a map of supported distributions -var osReleaseIDToString = map[OSReleaseID]string{ - UBUNTU: "ubuntu", - FEDORA: "fedora", - ARCH: "arch", - DEBIAN: "debian", - CENTOS: "centos", - STREAM: "stream", - ALMA: "alma", -} - -const ( - OS_NAME OSReleaseField = iota + 0 - OS_ID - OS_ID_LIKE - OS_PRETTY_NAME - OS_VARIANT - OS_VARIANT_ID - OS_VERSION - OS_VERSION_ID - OS_VERSION_CODENAME - OS_BUILD_ID - OS_IMAGE_ID - OS_IMAGE_VERSION - // not part of default os-release: - OS_KERNEL_RELEASE - OS_ARCH -) - -type OSReleaseField uint32 - -func (o OSReleaseField) String() string { - return osReleaseFieldToString[o] -} - -// stringToOSReleaseField is a map of os-release file fields -var stringToOSReleaseField = map[string]OSReleaseField{ - "NAME": OS_NAME, - "ID": OS_ID, - "ID_LIKE": OS_ID_LIKE, - "PRETTY_NAME": OS_PRETTY_NAME, - "VARIANT": OS_VARIANT, - "VARIANT_ID": OS_VARIANT_ID, - "VERSION": OS_VERSION, - "VERSION_ID": OS_VERSION_ID, - "VERSION_CODENAME": OS_VERSION_CODENAME, - "BUILD_ID": OS_BUILD_ID, - "IMAGE_ID": OS_IMAGE_ID, - "IMAGE_VERSION": OS_IMAGE_VERSION, - "KERNEL_RELEASE": OS_KERNEL_RELEASE, - "ARCH": OS_ARCH, -} - -// osReleaseFieldToString is a map of os-release file fields -var osReleaseFieldToString = map[OSReleaseField]string{ - OS_NAME: "NAME", - OS_ID: "ID", - OS_ID_LIKE: "ID_LIKE", - OS_PRETTY_NAME: "PRETTY_NAME", - OS_VARIANT: "VARIANT", - OS_VARIANT_ID: "VARIANT_ID", - OS_VERSION: "VERSION", - OS_VERSION_ID: "VERSION_ID", - OS_VERSION_CODENAME: "VERSION_CODENAME", - OS_BUILD_ID: "BUILD_ID", - OS_IMAGE_ID: "IMAGE_ID", - OS_IMAGE_VERSION: "IMAGE_VERSION", - OS_KERNEL_RELEASE: "KERNEL_RELEASE", - OS_ARCH: "ARCH", -} - -// OSBTFEnabled checks if kernel has embedded BTF vmlinux file -func OSBTFEnabled() bool { - _, err := os.Stat("/sys/kernel/btf/vmlinux") // TODO: accept a KernelConfig param and check for CONFIG_DEBUG_INFO_BTF=y, or similar - - return err == nil -} - -// GetOSInfo creates a OSInfo object and runs discoverOSDistro() on its creation -func GetOSInfo() (*OSInfo, error) { - info := OSInfo{} - var err error - - if info.osReleaseFieldValues == nil { - info.osReleaseFieldValues = make(map[OSReleaseField]string) - } - - info.osReleaseFieldValues[OS_KERNEL_RELEASE], err = UnameRelease() - if err != nil { - return &info, fmt.Errorf("could not determine uname release: %w", err) - } - - info.osReleaseFieldValues[OS_ARCH], err = UnameMachine() - if err != nil { - return &info, fmt.Errorf("could not determine uname machine: %w", err) - } - - info.osReleaseFilePath, err = checkEnvPath("LIBBPFGO_OSRELEASE_FILE") // useful if users wants to mount host os-release in a container - if err != nil { - return &info, err - } else if info.osReleaseFilePath == "" { - info.osReleaseFilePath = "/etc/os-release" - } - - if err = info.discoverOSDistro(); err != nil { - return &info, err - } - - return &info, nil -} - -// OSInfo object contains all OS relevant information -// -// OSRelease is relevant to examples such as: -// 1) OSInfo.OSReleaseInfo[helpers.OS_KERNEL_RELEASE] => will provide $(uname -r) string -// 2) if OSInfo.GetReleaseID() == helpers.UBUNTU => {} will allow running code in specific distribution -type OSInfo struct { - osReleaseFieldValues map[OSReleaseField]string - osReleaseID OSReleaseID - osReleaseFilePath string -} - -// GetOSReleaseFieldValue provides access to internal OSInfo OSReleaseField's -func (btfi *OSInfo) GetOSReleaseFieldValue(value OSReleaseField) string { - return btfi.osReleaseFieldValues[value] -} - -// GetOSReleaseFilePath provides the path for the used os-release file as it might -// not necessarily be /etc/os-release, depending on the environment variable -func (btfi *OSInfo) GetOSReleaseFilePath() string { - return btfi.osReleaseFilePath -} - -// GetOSReleaseID provides the ID of current Linux distribution -func (btfi *OSInfo) GetOSReleaseID() OSReleaseID { - return btfi.osReleaseID -} - -// GetOSReleaseAllFieldValues allows user to dump, as strings, the existing OSReleaseField's and its values -func (btfi *OSInfo) GetOSReleaseAllFieldValues() map[OSReleaseField]string { - summary := make(map[OSReleaseField]string) - - for k, v := range btfi.osReleaseFieldValues { - summary[k] = v // create a copy so consumer can read internal data (e.g. debugging) - } - - return summary -} - -// CompareOSBaseKernelRelease will compare a given kernel version/release string -// to the current running version and returns a KernelVersionComparison constant -// that shows the relationship of the given kernel version to the running kernel. -// -// For example, if the running kernel is 5.18.0 and pass "4.3.2", the result -// would be KernelVersionOlder because 4.3.2 is older than the running kernel -// -// Consumers should use the constants defined in this package for checking -// the results: KernelVersionOlder, KernelVersionEqual, KernelVersionNewer -func (btfi *OSInfo) CompareOSBaseKernelRelease(version string) (KernelVersionComparison, error) { - return CompareKernelRelease(btfi.osReleaseFieldValues[OS_KERNEL_RELEASE], version) -} - -// discoverOSDistro discover running Linux distribution information by reading UTS and -// the /etc/os-releases file (https://man7.org/linux/man-pages/man5/os-release.5.html) -func (btfi *OSInfo) discoverOSDistro() error { - var err error - - if btfi.osReleaseFilePath == "" { - return fmt.Errorf("should specify os-release filepath") - } - - file, err := os.Open(btfi.osReleaseFilePath) - if err != nil { - return err - } - - defer file.Close() - scanner := bufio.NewScanner(file) - - for scanner.Scan() { - val := strings.Split(scanner.Text(), "=") - if len(val) != 2 { - continue - } - keyID := stringToOSReleaseField[val[0]] - if keyID == 0 { // could not find KEY= from os-release in consts - continue - } - btfi.osReleaseFieldValues[keyID] = val[1] - if keyID == OS_ID { - btfi.osReleaseID = stringToOSReleaseID[strings.ToLower(val[1])] - } - } - - return nil -} - -func FtraceEnabled() (bool, error) { - b, err := os.ReadFile("/proc/sys/kernel/ftrace_enabled") - if err != nil { - return false, fmt.Errorf("could not read from ftrace_enabled file: %s", err.Error()) - } - b = bytes.TrimSpace(b) - if len(b) != 1 { - return false, errors.New("malformed ftrace_enabled file") - } - return b[0] == '1', nil -} - -type LockdownMode int32 - -func (l LockdownMode) String() string { - return lockdownModeToString[l] -} - -const ( - NOVALUE LockdownMode = iota - NONE - INTEGRITY - CONFIDENTIALITY -) - -var stringToLockdownMode = map[string]LockdownMode{ - "none": NONE, - "integrity": INTEGRITY, - "confidentiality": CONFIDENTIALITY, -} - -var lockdownModeToString = map[LockdownMode]string{ - NONE: "none", - INTEGRITY: "integrity", - CONFIDENTIALITY: "confidentiality", -} - -func Lockdown() (LockdownMode, error) { - LockdownFile := "/sys/kernel/security/lockdown" - data, err := os.ReadFile(LockdownFile) - if err != nil { - return NOVALUE, err - } - - dataString := string(data[:]) - - for lockString, lockMode := range stringToLockdownMode { - tempString := fmt.Sprintf("[%s]", lockString) - if strings.Contains(dataString, tempString) { - return lockMode, nil - } - } - - return NOVALUE, fmt.Errorf("could not get lockdown mode") -} diff --git a/vendor/github.com/aquasecurity/libbpfgo/helpers/tracelisten.go b/vendor/github.com/aquasecurity/libbpfgo/helpers/tracelisten.go deleted file mode 100644 index a74874a5d6..0000000000 --- a/vendor/github.com/aquasecurity/libbpfgo/helpers/tracelisten.go +++ /dev/null @@ -1,34 +0,0 @@ -package helpers - -import ( - "bufio" - "fmt" - "os" -) - -// TracePipeListen reads data from the trace pipe that bpf_trace_printk() writes to, -// (/sys/kernel/debug/tracing/trace_pipe). -// It writes the data to stdout. The pipe is global, so this function is not -// associated with any BPF program. It is recommended to use bpf_trace_printk() -// and this function for debug purposes only. -// This is a blocking function intended to be called from a goroutine. -func TracePipeListen() error { - f, err := os.Open("/sys/kernel/debug/tracing/trace_pipe") - if err != nil { - return fmt.Errorf("failed to open trace pipe: %w", err) - } - defer f.Close() - - r := bufio.NewReader(f) - b := make([]byte, 1024) - - for { - l, err := r.Read(b) - if err != nil { - return fmt.Errorf("failed to read from trace pipe: %w", err) - } - - s := string(b[:l]) - fmt.Println(s) - } -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 6c523d1876..c269ff9022 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -262,9 +262,6 @@ github.com/Microsoft/hcsshim/pkg/ociwclayer # github.com/aquasecurity/libbpfgo v0.5.1-libbpf-1.2 ## explicit; go 1.18 github.com/aquasecurity/libbpfgo -# github.com/aquasecurity/libbpfgo/helpers v0.4.5 -## explicit; go 1.18 -github.com/aquasecurity/libbpfgo/helpers # github.com/avast/retry-go v3.0.0+incompatible ## explicit github.com/avast/retry-go