From be076643a8aab1bc94d3249b2926aeab21906278 Mon Sep 17 00:00:00 2001 From: Brennan Vincent Date: Wed, 9 Oct 2024 08:32:42 -0400 Subject: [PATCH] Attempt to run without syscall tracepoints, if possible. This implements the proposal in https://github.com/open-telemetry/opentelemetry-ebpf-profiler/issues/173 . Please see there for full details. --- main.go | 4 -- tracer/maccess.go | 4 +- tracer/probe_linux.go | 91 ------------------------------------------- tracer/probe_other.go | 5 --- 4 files changed, 3 insertions(+), 101 deletions(-) diff --git a/main.go b/main.go index 92b6594a..5fc8904a 100644 --- a/main.go +++ b/main.go @@ -130,10 +130,6 @@ func mainWithExitCode() exitCode { return failure("Failed to probe eBPF syscall: %v", err) } - if err = tracer.ProbeTracepoint(); err != nil { - return failure("Failed to probe tracepoint: %v", err) - } - presentCores, err := numcpus.GetPresent() if err != nil { return failure("Failed to read CPU file: %v", err) diff --git a/tracer/maccess.go b/tracer/maccess.go index 68a00e47..5048c592 100644 --- a/tracer/maccess.go +++ b/tracer/maccess.go @@ -26,7 +26,9 @@ func checkForMaccessPatch(coll *cebpf.CollectionSpec, maps map[string]*cebpf.Map code, err := loadKernelCode(coll, maps, faultyFunc.Address) if err != nil { - log.Warnf("Failed to load code for %s: %v", faultyFunc.Name, err) + log.Warnf("Failed to load code for %s: %v.\n"+ + "Syscall tracepoints are not working on this system, so whether the kernel is patched could not be determined. "+ + "Either use a kernel configured with syscall tracepoints, or upgrade to kernel version 6.4 or higher.", faultyFunc.Name, err) return false } diff --git a/tracer/probe_linux.go b/tracer/probe_linux.go index 838a657b..d5706aee 100644 --- a/tracer/probe_linux.go +++ b/tracer/probe_linux.go @@ -32,16 +32,6 @@ func ProbeBPFSyscall() error { return nil } -// getTracepointID returns the system specific tracepoint ID for a given tracepoint. -func getTracepointID(tracepoint string) (uint64, error) { - id, err := os.ReadFile("/sys/kernel/debug/tracing/events/syscalls/" + tracepoint + "/id") - if err != nil { - return 0, fmt.Errorf("failed to read tracepoint ID for %s: %v", tracepoint, err) - } - tid := util.DecToUint64(strings.TrimSpace(string(id))) - return tid, nil -} - // GetCurrentKernelVersion returns the major, minor and patch version of the kernel of the host // from the utsname struct. func GetCurrentKernelVersion() (major, minor, patch uint32, err error) { @@ -52,84 +42,3 @@ func GetCurrentKernelVersion() (major, minor, patch uint32, err error) { _, _ = fmt.Fscanf(bytes.NewReader(uname.Release[:]), "%d.%d.%d", &major, &minor, &patch) return major, minor, patch, nil } - -// ProbeTracepoint checks if tracepoints are available on the system, so we can attach -// our eBPF code there. -func ProbeTracepoint() error { - ins := asm.Instructions{ - // set exit code to 0 - asm.Mov.Imm(asm.R0, 0), - asm.Return(), - } - - // The check of the kernel version was removed with - // commit 6c4fc209fcf9d27efbaa48368773e4d2bfbd59aa. So kernel < 4.20 - // need to set the kernel version to not be rejected by the verifier. - major, minor, patch, err := GetCurrentKernelVersion() - if err != nil { - return err - } - kernelVersion := util.VersionUint(major, minor, patch) - restoreRlimit, err := rlimit.MaximizeMemlock() - if err != nil { - return fmt.Errorf("failed to increase rlimit: %v", err) - } - defer restoreRlimit() - - prog, err := cebpf.NewProgram(&cebpf.ProgramSpec{ - Type: cebpf.TracePoint, - License: "GPL", - Instructions: ins, - KernelVersion: kernelVersion, - }) - if err != nil { - return fmt.Errorf("failed to create tracepoint_probe: %v", err) - } - defer prog.Close() - - var tid uint64 - // sys_enter_mmap is the first tracepoint we have used - tid, err = getTracepointID("sys_enter_mmap") - if err != nil { - return fmt.Errorf("failed to get id for tracepoint: %v", err) - } - - attr := unix.PerfEventAttr{ - Type: unix.PERF_TYPE_TRACEPOINT, - Config: tid, - Sample_type: unix.PERF_SAMPLE_RAW, - Sample: 1, - Wakeup: 1, - } - - pfd, err := unix.PerfEventOpen(&attr, -1, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) - if err != nil { - return fmt.Errorf("unable to open perf events: %v", err) - } - defer func() { - if err = unix.Close(pfd); err != nil { - log.Fatalf("Failed to close tracepoint sys_enter_mmap probe: %v", err) - } - }() - - if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(pfd), - unix.PERF_EVENT_IOC_ENABLE, 0); errno != 0 { - return fmt.Errorf("unable to set up perf events: %d", errno) - } - - if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(pfd), - unix.PERF_EVENT_IOC_SET_BPF, uintptr(prog.FD())); errno != 0 { - return fmt.Errorf("unable to attach bpf program to perf event %d: %d", tid, errno) - } - - // The test was successful, so disable the tracepoint and clean up. - // In kernel < 4.15 we can not attach multiple eBPF programs to the same tracepoint. - // This was changed in the kernel with commit e87c6bc3852b981e71c757be20771546ce9f76f3. - // So it is important not only to disable the tracepoint but also close its - // perf event file descriptor. - if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(pfd), - unix.PERF_EVENT_IOC_DISABLE, 0); errno != 0 { - return fmt.Errorf("unable to disable perf events: %v", err) - } - return nil -} diff --git a/tracer/probe_other.go b/tracer/probe_other.go index f90b280c..ceb81600 100644 --- a/tracer/probe_other.go +++ b/tracer/probe_other.go @@ -16,11 +16,6 @@ func ProbeBPFSyscall() error { return fmt.Errorf("eBPF is not available on your system %s", runtime.GOOS) } -// ProbeTracepoint checks if tracepoints are available on the system. -func ProbeTracepoint() error { - return fmt.Errorf("tracepoints are not available on your system %s", runtime.GOOS) -} - // GetCurrentKernelVersion returns an error for OS other than linux. func GetCurrentKernelVersion() (_, _, _ uint32, err error) { return 0, 0, 0, fmt.Errorf("kernel version detection is not supported on %s",