Skip to content

Framework for running BPF programs with rules on Linux as a daemon. Container aware.

License

Notifications You must be signed in to change notification settings

genuinetools/bpfd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

89 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bpfd

Travis CI GoDoc Github All Releases

Framework for running BPF programs with rules on Linux as a daemon. Container aware.

NOTE: WIP If you want to contribute see "How it Works" below and consider adding more example rules or programs. Thanks!!

Table of Contents

How it Works

Programs retrieve the data... Rules filter the data... Actions perform actions on the data.

The programs are in the program/ folder. The idea is that you can add any tracers you would like and then create rules for the data retrieved from the programs. Any events with data that passes the filters will be passed on to the specified action.

Programs

The programs that exist today are based off a few bcc-tools programs.

You could always add your own programs in a fork if you worry people will reverse engineer the data you are collecting and alerting on.

These must implement the Program interface:

// Program defines the basic capabilities of a program.
type Program interface {
    // Load creates the bpf module and starts collecting the data for the program.
    Load() error
    // Unload closes the bpf module and all the probes that all attached to it.
    Unload()
    // WatchEvent defines the function to watch the events for the program.
    WatchEvent() (*grpc.Event, error)
    // Start starts the map for the program.
    Start()
    // String returns a string representation of this program.
    String() string
}

As you can see from above you could technically implement this interface with something other than BPF ;)

The Event type defines the data returned from the program. As you can see below, the Data is of type map[string]string meaning any key value pair can be returned for the data. The rules then filter using those key value pairs.

// Event defines the data struct for holding event data.
type Event struct {
    PID              uint32            // Process ID.
    TGID             uint32            // Task group ID.
    Data             map[string]string
    ContainerRuntime string            // Filled in after the program is run so you don't need to.
    ContainerID      string            // Filled in after the program is run so you don't need to.
    Program          string            // Filled in after the program is run so you don't need to.
}

Rules

These are toml files that hold some logic for what you would like to trace. You can search for anything returned by a Program in it's map[string]string data struct.

You can also filter based off the container runtime you would like to alert on. The container runtime must be one of the strings defined here.

If you provide no rules for a program, then all the events will be passed to actions.

The example below describes a rule file to filter the data returned from the exec program. Events from exec will only be returned if the command matches one of those values AND the container runtime is docker or kube.

program = "exec"

[filterEvents]
  [filterEvents.command]
  values = ["sshd", "dbus-daemon-lau", "ping", "ping6", "critical-stack-", "pmmcli", "filemng", "PassengerAgent", "bwrap", "osdetect", "nginxmng", "sw-engine-fpm", "start-stop-daem"]

containerRuntimes = ["docker","kube"]

If you are wondering where the command key comes from it's defined in the exec program here.

Actions

Actions do "something" on an event. This way you can send filtered events to Slack, email, or even run arbitrary code. You could kill a container, pause a container, or checkpoint a container to restore it elsewhere without even having to login to a computer.

Actions implement the Actions interface:

// Action performs an action on an event.
type Action interface {
    // Do runs the action on an event.
    Do(event *grpc.Event) error
    // String returns a string representation of this program.
    String() string
}

Installation

To build, you need to have libbcc installed SEE INSTRUCTIONS HERE

Binaries

For installation instructions from binaries please visit the Releases Page.

Via Go

$ go get github.com/jessfraz/bpfd

Via Docker

$ docker run --rm -it \
    --name bpfd \
    -v /lib/modules:/lib/modules:ro \
    -v /usr/src:/usr/src:ro \
    --privileged \
    r.j3ss.co/bpfd daemon

Usage

$ bpfd -h
bpfd -  Framework for running BPF programs with rules on Linux as a daemon.

Usage: bpfd <command>

Flags:

  -d, --debug  enable debug logging (default: false)
  --grpc-addr  Address for gRPC api communication (default: /run/bpfd/bpfd.sock)

Commands:

  create   Create one or more rules.
  daemon   Start the daemon.
  ls       List rules.
  rm       Remove one or more rules.
  trace    Live trace the events returned after filtering.
  version  Show the version information.

Run the daemon

You can preload rules by passing --rules-dir to the command or placing rules in the default directory: /etc/bpfd/rules.

$ bpfd daemon -h
Usage: bpfd daemon [OPTIONS]

Start the daemon.

Flags:

  -d, --debug  enable debug logging (default: false)
  --grpc-addr  Address for gRPC api communication (default: /run/bpfd/bpfd.sock)
  --rules-dir  Directory that stores the rules files (default: /etc/bpfd/rules)

Create rules dynamically

You can create rules on the fly with the create command. You can pass more than one file at a time.

Usage: bpfd create [OPTIONS] RULE_FILE [RULE_FILE...]

Create one or more rules.

Flags:

  -d, --debug  enable debug logging (default: false)
  --grpc-addr  Address for gRPC api communication (default: /run/bpfd/bpfd.sock)

Remove rules dynamically

You can delete rules with the rm command. You can pass more than one rule name at a time.

$ bpfd rm -h
Usage: bpfd rm [OPTIONS] RULE_NAME [RULE_NAME...]

Remove one or more rules.

Flags:

  -d, --debug  enable debug logging (default: false)
  --grpc-addr  Address for gRPC api communication (default: /run/bpfd/bpfd.sock)

List active rules

You can list the rules that the daemon is filtering with by using the ls command.

$ bpfd ls
NAME                PROGRAM
bashreadline        bashreadline
password_files      open
setuid_binaries     exec

Live tracing events

You can live trace the events returned after filtering with the trace command.

This does not include past events. Consider it like a tail.

$ bpfd trace
INFO[0000] map[string]string{"filename":"/etc/shadow", "command":"sudo", "returnval":"4"}  container_id= container_runtime=not-found pid=12893 program=open tgid=0
INFO[0000] map[string]string{"command":"sudo", "returnval":"4", "filename":"/etc/sudoers.d/README"}  container_id= container_runtime=not-found pid=12893 program=open tgid=0
INFO[0000] map[string]string{"command":"sudo", "returnval":"4", "filename":"/etc/sudoers.d"}  container_id= container_runtime=not-found pid=12893 program=open tgid=0
INFO[0000] map[string]string{"filename":"/etc/sudoers", "command":"sudo", "returnval":"3"}  container_id= container_runtime=not-found pid=12893 program=open tgid=0
INFO[0000] map[string]string{"command":"sudo bpfd trace"}  container_id= container_runtime=not-found pid=23751 program=bashreadline tgid=0
INFO[0000] map[string]string{"command":"vim README.md"}  container_id= container_runtime=not-found pid=23751 program=bashreadline tgid=0
INFO[0000] map[string]string{"filename":"/etc/shadow", "command":"sudo", "returnval":"4"}  container_id= container_runtime=not-found pid=12786 program=open tgid=0
INFO[0000] map[string]string{"command":"sudo", "returnval":"4", "filename":"/etc/sudoers.d/README"}  container_id= container_runtime=not-found pid=12786 program=open tgid=0
INFO[0000] map[string]string{"filename":"/etc/sudoers.d", "command":"sudo", "returnval":"4"}  container_id= container_runtime=not-found pid=12786 program=open tgid=0
INFO[0000] map[string]string{"filename":"/etc/sudoers", "command":"sudo", "returnval":"3"}  container_id= container_runtime=not-found pid=12786 program=open tgid=0