Skip to content

Commit

Permalink
Add iterator for bpf programs/maps in a bpf object (#166)
Browse files Browse the repository at this point in the history
* Helper for getting section name

Signed-off-by: grantseltzer <grantseltzer@gmail.com>

* Add ProgramIterator for iterating over programs in a BPF object, and a
selftest

Signed-off-by: grantseltzer <grantseltzer@gmail.com>

* Add map iteration

Signed-off-by: grantseltzer <grantseltzer@gmail.com>
  • Loading branch information
grantseltzer committed May 6, 2022
1 parent b5a21bd commit be71c35
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 0 deletions.
60 changes: 60 additions & 0 deletions libbpfgo.go
Expand Up @@ -897,6 +897,66 @@ func (b *BPFMap) Update(key, value unsafe.Pointer) error {
return nil
}

// BPFObjectProgramIterator iterates over maps in a BPF object
type BPFObjectIterator struct {
m *Module
prevProg *BPFProg
prevMap *BPFMap
}

func (m *Module) Iterator() *BPFObjectIterator {
return &BPFObjectIterator{
m: m,
prevProg: nil,
prevMap: nil,
}
}

func (it *BPFObjectIterator) NextMap() *BPFMap {
var startMap *C.struct_bpf_map
if it.prevMap != nil && it.prevMap.bpfMap != nil {
startMap = it.prevMap.bpfMap
}

m := C.bpf_object__next_map(it.m.obj, startMap)
if m == nil {
return nil
}
cName := C.bpf_map__name(m)

bpfMap := &BPFMap{
name: C.GoString(cName),
bpfMap: m,
module: it.m,
}

it.prevMap = bpfMap
return bpfMap
}

func (it *BPFObjectIterator) NextProgram() *BPFProg {

var startProg *C.struct_bpf_program
if it.prevProg != nil && it.prevProg.prog != nil {
startProg = it.prevProg.prog
}

p := C.bpf_object__next_program(it.m.obj, startProg)
if p == nil {
return nil
}
cName := C.bpf_program__name(p)

prog := &BPFProg{
name: C.GoString(cName),
prog: p,
module: it.m,
}
it.prevProg = prog
return prog
}

// BPFMapIterator iterates over keys in a BPF map
type BPFMapIterator struct {
b *BPFMap
err error
Expand Down
1 change: 1 addition & 0 deletions selftest/object-iterator/Makefile
7 changes: 7 additions & 0 deletions selftest/object-iterator/go.mod
@@ -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/object-iterator/go.sum
@@ -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/object-iterator/main.bpf.c
@@ -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_HASH);
__type(key, u32);
__type(value, u32);
__uint(max_entries, 1);
} one SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(key_size, sizeof(u32));
__uint(value_size, sizeof(u32));
__uint(max_entries, 1);
} two SEC(".maps");

SEC("fentry/__x64_sys_mmap")
int mmap_fentry(struct pt_regs *ctx)
{
return 0;
}

SEC("fentry/__x64_sys_execve")
int execve_fentry(struct pt_regs *ctx)
{
return 0;
}

SEC("fentry/__x64_sys_execveat")
int execveat_fentry(struct pt_regs *ctx)
{
return 0;
}

char LICENSE[] SEC("license") = "GPL";
76 changes: 76 additions & 0 deletions selftest/object-iterator/main.go
@@ -0,0 +1,76 @@
package main

import "C"

import (
"os"

"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)
}

iterator := bpfModule.Iterator()

// Iterate over programs
expectedProgramNames := map[string]bool{
"mmap_fentry": false,
"execve_fentry": false,
"execveat_fentry": false,
}

currentProg := iterator.NextProgram()
for currentProg != nil {
expectedProgramNames[currentProg.GetName()] = true
currentProg = iterator.NextProgram()
}

if len(expectedProgramNames) != 3 {
fmt.Fprintln(os.Stderr, "did not iterate over expected programs")
os.Exit(-1)
}
for k, v := range expectedProgramNames {
if v == false {
fmt.Fprintf(os.Stderr, "did not iterate over expected program: %s", k)
os.Exit(-1)
}
}

// Iterate over maps
expectedMapNames := map[string]bool{
"one": false,
"two": false,
}

currentMap := iterator.NextMap()
for currentMap != nil {
expectedMapNames[currentMap.GetName()] = true
currentMap = iterator.NextMap()
}

if len(expectedMapNames) != 2 {
fmt.Fprintln(os.Stderr, "did not iterate over expected maps")
os.Exit(-1)
}
for k, v := range expectedMapNames {
if v == false {
fmt.Fprintf(os.Stderr, "did not iterate over expected map: %s", k)
os.Exit(-1)
}
}
}
1 change: 1 addition & 0 deletions selftest/object-iterator/run.sh

0 comments on commit be71c35

Please sign in to comment.