Skip to content

Commit

Permalink
Attempt to run without syscall tracepoints, if possible.
Browse files Browse the repository at this point in the history
This implements the proposal in
open-telemetry#173
. Please see there for full details.
  • Loading branch information
umanwizard committed Oct 9, 2024
1 parent cb08159 commit be07664
Show file tree
Hide file tree
Showing 4 changed files with 3 additions and 101 deletions.
4 changes: 0 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion tracer/maccess.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
91 changes: 0 additions & 91 deletions tracer/probe_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
}
5 changes: 0 additions & 5 deletions tracer/probe_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit be07664

Please sign in to comment.