-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbpf.go
116 lines (102 loc) · 2.79 KB
/
bpf.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//go:build linux
// +build linux
package exectrace
import (
"bytes"
"runtime"
"sync"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/rlimit"
"github.com/hashicorp/go-multierror"
"golang.org/x/xerrors"
)
var (
errObjectsClosed = xerrors.New("objects are closed")
removeMemlockOnce sync.Once
// collectionOpts used for loading the BPF objects.
collectionOpts = &ebpf.CollectionOptions{
Programs: ebpf.ProgramOptions{
// While debugging, it may be helpful to set this value to be much
// higher (i.e. * 1000).
LogSize: ebpf.DefaultVerifierLogSize,
},
}
)
// loadBPFObjects reads and parses the programs and maps out of the embedded
// BPF program.
func loadBPFObjects() (*bpfObjects, error) {
// Allow the current process to lock memory for eBPF resources. This does
// nothing on 5.11+ kernels which don't need this.
var err error
removeMemlockOnce.Do(func() {
err = rlimit.RemoveMemlock()
})
if err != nil {
return nil, xerrors.Errorf("remove kernel memlock: %w", err)
}
r := bytes.NewReader(bpfProgram)
spec, err := ebpf.LoadCollectionSpecFromReader(r)
if err != nil {
return nil, xerrors.Errorf("load collection from reader: %w", err)
}
objs := &bpfObjects{
closeLock: sync.Mutex{},
closed: make(chan struct{}),
}
err = spec.LoadAndAssign(objs, collectionOpts)
if err != nil {
var ve *ebpf.VerifierError
if xerrors.As(err, &ve) {
// It's better to use %+v for this as it forces the error to contain
// all lines from the verifier log.
return nil, xerrors.Errorf("load and assign specs: verifier error: %+v", ve)
}
return nil, xerrors.Errorf("load and assign specs: %w", err)
}
return objs, nil
}
type bpfObjects struct {
EnterExecveProg *ebpf.Program `ebpf:"enter_execve"`
EventsMap *ebpf.Map `ebpf:"events"`
LogsMap *ebpf.Map `ebpf:"logs"`
FiltersMap *ebpf.Map `ebpf:"filters"`
closeLock sync.Mutex
closed chan struct{}
}
func (o *bpfObjects) Close() error {
o.closeLock.Lock()
defer o.closeLock.Unlock()
select {
case <-o.closed:
return errObjectsClosed
default:
}
close(o.closed)
runtime.SetFinalizer(o, nil)
var merr error
if o.EnterExecveProg != nil {
err := o.EnterExecveProg.Close()
if err != nil {
merr = multierror.Append(merr, xerrors.Errorf(`close BPF program "enter_execve": %w`, err))
}
}
if o.EventsMap != nil {
err := o.EventsMap.Close()
if err != nil {
merr = multierror.Append(merr, xerrors.Errorf(`close BPF map "events": %w`, err))
}
}
if o.LogsMap != nil {
err := o.LogsMap.Close()
if err != nil {
merr = multierror.Append(merr, xerrors.Errorf(`close BPF map "logs": %w`, err))
}
}
if o.FiltersMap != nil {
err := o.FiltersMap.Close()
if err != nil {
merr = multierror.Append(merr, xerrors.Errorf(`close BPF map "filters": %w`, err))
}
}
return merr
}