exectrace

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 19, 2022 License: GPL-2.0, MIT, MIT Imports: 17 Imported by: 1

README

exectrace Go Reference

Simple eBPF-based exec snooping on Linux packaged as a Go library.

exectrace loads a pre-compiled eBPF program into the running kernel to receive details about the exec family of syscalls.

Requirements

exectrace only supports Go 1.16+ and Linux kernel 5.8+ (due to the use of BPF_MAP_TYPE_RINGBUF).

Installation

$ go get -u github.com/coder/exectrace

Quickstart

You will need root access, CAP_SYS_ADMIN or CAP_BPF, to run eBPF programs on your system.

Use go run -exec sudo ./cmd/program to compile a program and start it with sudo

$ go install -u github.com/coder/exectrace/cmd/exectrace
$ exectrace --help
...

$ sudo exectrace
2021/12/01 16:42:02 Waiting for events..
[1188921, comm="node", uid=1002, gid=1003] /bin/sh -c 'which ps'
[1188922, comm="sh", uid=1002, gid=1003] which ps

Usage

exectrace exposes a minimal API surface. Call exectrace.New(nil) and then you can start reading events from the returned Tracer.

It is important that you close the tracer to avoid leaking kernel resources, so we recommend implementing a simple signal handler like the one in this example:

package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/coder/exectrace"
)

func main() {
	tracer, err := exectrace.New(nil)
	if err != nil {
		panic(err)
	}
	defer tracer.Close()

	go func() {
		sigs := make(chan os.Signal, 1)
		signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
		<-sigs
		tracer.Close()
	}()

	for {
		event, err := tracer.Read()
		if err != nil {
			panic(err)
		}

		fmt.Printf("%+v\n", event)
	}
}

For a full usage example, refer to this comprehensive program that uses the library.

Development

You will need the following:

  • Docker (the Makefile runs clang within a Docker container for reproducibility)
  • golangci-lint
  • prettier
  • shellcheck

Since the eBPF program is packaged as a Go library, you need to compile the program and include it in the repo.

If you change the files in the bpf directory, run make and ensure that you include the .o files you changed in your commit (CI will verify that you've done this correctly).

Status: beta

This library is ready to use as-is, though it is under active development as we modify it to suit the needs of Coder's enterprise product.

We plan on adding more features and fields that can be read from the API, as well as easier-to-use methods for filtering events (currently, you must implement additional filtering yourself).

See also

  • canonical/etrace - Go binary that uses ptrace and tracks the processes that a command launches for debugging and analysis
  • shirou/gopsutil - Go library that has methods for listing process details and getting information about the system

Dual licensed under the MIT and GPL 2.0 licenses. See LICENSE.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var NativeEndian = binary.LittleEndian

The native endian of the processor this program was compiled for.

Functions

This section is empty.

Types

type Event

type Event struct {
	Filename string `json:"filename"`
	// Argv contains the raw argv supplied to the process, including argv[0]
	// (which is equal to `filepath.Base(e.Filename)` in most circumstances).
	Argv []string `json:"argv"`
	// Truncated is true if we were unable to read all process arguments into
	// Argv because there were more than ARGLEN arguments.
	Truncated bool `json:"truncated"`

	// These values are of the new process. Keep in mind that the exec call may
	// fail and the PID will be released in such a case.
	PID uint32 `json:"pid"`
	UID uint32 `json:"uid"`
	GID uint32 `json:"gid"`

	// Comm is the "name" of the parent process, usually the filename of the
	// executable (but not always).
	Comm string `json:"comm"`
}

Event contains data about each exec event with many fields for easy filtering and logging.

type Tracer

type Tracer interface {
	io.Closer

	Read() (*Event, error)
}

Tracer allows consumers to read exec events from the kernel via an eBPF program. `execve()` syscalls are traced in the kernel, and details about the event are sent back to this Go interface.

func New

func New(opts *TracerOpts) (Tracer, error)

New instantiates all of the BPF objects into the running kernel, starts tracing, and returns the created Tracer. After calling this successfully, the caller should immediately attach a for loop running `h.Read()`.

The returned Tracer MUST be closed when not needed anymore otherwise kernel resources may be leaked.

type TracerOpts

type TracerOpts struct {
	// PidNS filters all processes that are in the given PID namespace or in the
	// child namespace tree of this given namespace. This is very useful for
	// Docker containers, as you can read all processes in a container (or in
	// child containers).
	//
	// You can read the PID namespace ID for a given process by running
	// `readlink /proc/x/ns/pid`.
	//
	// This filter runs in the kernel for high performance.
	PidNS uint32
}

TracerOpts contains all of the configuration options for the tracer. All are optional.

Directories

Path Synopsis
cmd
exectrace command
enterprise module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL