Skip to content

Commit

Permalink
Add libbpfgo API functions for attaching generic bpf program types su…
Browse files Browse the repository at this point in the history
…ch as fentry/fexit, and add selftests for demonstration

Signed-off-by: grantseltzer <grantseltzer@gmail.com>
  • Loading branch information
grantseltzer committed Apr 5, 2022
1 parent 5ced2a6 commit 15a926a
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 0 deletions.
62 changes: 62 additions & 0 deletions libbpfgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ struct ring_buffer * init_ring_buf(int map_fd, uintptr_t ctx)
return rb;
}
void list_programs(struct bpf_object* obj) {
struct bpf_program *pos;
const char *cs;
const char *css;
bpf_object__for_each_program(pos, obj) {
cs = bpf_program__section_name(pos);
css = bpf_program__name(pos);
printf("section: %s\tname: %s\n", cs, css);
}
}
struct perf_buffer * init_perf_buf(int map_fd, int page_cnt, uintptr_t ctx)
{
struct perf_buffer_opts pb_opts = {};
Expand Down Expand Up @@ -215,6 +227,7 @@ const (
PerfEvent
Uprobe
Uretprobe
Tracing
)

type BPFLink struct {
Expand All @@ -236,6 +249,26 @@ func (l *BPFLink) GetFd() int {
return int(C.bpf_link__fd(l.link))
}

func (l *BPFLink) Pin(pinPath string) error {
path := C.CString(pinPath)
errC := C.bpf_link__pin(l.link, path)
C.free(unsafe.Pointer(path))
if errC != 0 {
return fmt.Errorf("failed to pin link %s to path %s: %w", l.eventName, pinPath, syscall.Errno(-errC))
}
return nil
}

func (l *BPFLink) Unpin(pinPath string) error {
path := C.CString(pinPath)
errC := C.bpf_link__unpin(l.link)
C.free(unsafe.Pointer(path))
if errC != 0 {
return fmt.Errorf("failed to unpin link %s from path %s: %w", l.eventName, pinPath, syscall.Errno(-errC))
}
return nil
}

type PerfBuffer struct {
pb *C.struct_perf_buffer
bpfMap *BPFMap
Expand Down Expand Up @@ -843,6 +876,10 @@ func (m *Module) GetProgram(progName string) (*BPFProg, error) {
}, nil
}

func (m *Module) ListProgramNames() {
C.list_programs(m.obj)
}

func (p *BPFProg) GetFd() int {
return int(C.bpf_program__fd(p.prog))
}
Expand Down Expand Up @@ -922,6 +959,7 @@ const (
BPFProgTypeExt
BPFProgTypeLsm
BPFProgTypeSkLookup
BPFProgTypeSyscall
)

func (p *BPFProg) GetType() uint32 {
Expand All @@ -945,6 +983,30 @@ func (p *BPFProg) SetTracepoint() error {
return nil
}

func (p *BPFProg) AttachGeneric() (*BPFLink, error) {
link, errno := C.bpf_program__attach(p.prog)
if C.IS_ERR_OR_NULL(unsafe.Pointer(link)) {
return nil, fmt.Errorf("failed to attach program: %w", errno)
}
bpfLink := &BPFLink{
link: link,
prog: p,
linkType: Tracing,
eventName: fmt.Sprintf("tracing-%s", p.name),
}
return bpfLink, nil
}

func (p *BPFProg) SetAttachType(attachProgFD int, attachFuncName string) error {
cs := C.CString(attachFuncName)
errC := C.bpf_program__set_attach_target(p.prog, C.int(attachProgFD), cs)
C.free(unsafe.Pointer(cs))
if errC != 0 {
return fmt.Errorf("failed to set attach target for program %s %s %w", p.name, attachFuncName, syscall.Errno(-errC))
}
return nil
}

func (p *BPFProg) AttachTracepoint(category, name string) (*BPFLink, error) {
tpCategory := C.CString(category)
tpName := C.CString(name)
Expand Down
1 change: 1 addition & 0 deletions selftest/tracing/Makefile
7 changes: 7 additions & 0 deletions selftest/tracing/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/aquasecurity/libbpfgo/selftest/perfbuffers

go 1.16

require github.com/aquasecurity/libbpfgo v0.2.1-libbpf-0.4.0

replace github.com/aquasecurity/libbpfgo => ../../
11 changes: 11 additions & 0 deletions selftest/tracing/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
43 changes: 43 additions & 0 deletions selftest/tracing/main.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//+build ignore
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

#ifdef asm_inline
#undef asm_inline
#define asm_inline asm
#endif

struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 1 << 24);
} events SEC(".maps");
long ringbuffer_flags = 0;

SEC("fentry/__x64_sys_mmap")
int mmap_fentry(struct pt_regs *ctx)
{
int *process;

// Reserve space on the ringbuffer for the sample
process = bpf_ringbuf_reserve(&events, sizeof(int), ringbuffer_flags);
if (!process) {
return 0;
}

*process = 2021;

bpf_ringbuf_submit(process, ringbuffer_flags);
return 0;
}

SEC("fentry/commit_creds")
int BPF_PROG(commit_creds, struct cred *foobar)
{
bpf_printk("%d\n", foobar->uid.val);
return 0;
}


char LICENSE[] SEC("license") = "GPL";

88 changes: 88 additions & 0 deletions selftest/tracing/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import "C"

import (
"encoding/binary"
"os"
"syscall"
"time"

"fmt"

bpf "github.com/aquasecurity/libbpfgo"
)

func main() {

bpfModule, err := bpf.NewModuleFromFile("main.bpf.o")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(-1)
}
defer bpfModule.Close()

err = bpfModule.BPFLoadObject()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(-1)
}

bpfModule.ListProgramNames()

prog, err := bpfModule.GetProgram("mmap_fentry")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(-1)
}
link, err := prog.AttachGeneric()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(-1)
}
if link.GetFd() == 0 {
os.Exit(-1)
}

prog1, err := bpfModule.GetProgram("commit_creds")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(-1)
}
link1, err := prog1.AttachGeneric()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(-1)
}
if link1.GetFd() == 0 {
os.Exit(-1)
}

eventsChannel := make(chan []byte)
rb, err := bpfModule.InitRingBuf("events", eventsChannel)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(-1)
}

rb.Start()
numberOfEventsReceived := 0
go func() {
for {
syscall.Mmap(999, 999, 999, 1, 1)
time.Sleep(time.Second / 2)
}
}()
recvLoop:
for {
b := <-eventsChannel
if binary.LittleEndian.Uint32(b) != 2021 {
fmt.Fprintf(os.Stderr, "invalid data retrieved\n")
os.Exit(-1)
}
numberOfEventsReceived++
if numberOfEventsReceived > 5 {
break recvLoop
}
}
}
1 change: 1 addition & 0 deletions selftest/tracing/run.sh

0 comments on commit 15a926a

Please sign in to comment.