Skip to content

Commit 92f7021

Browse files
authored
Merge pull request #231 from bobrik/ivan/capabilities
Implement capability dropping and document needed capabilities
2 parents 1f0e5c4 + 380912c commit 92f7021

File tree

5 files changed

+102
-4
lines changed

5 files changed

+102
-4
lines changed

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,45 @@ with your own config baked in.
112112

113113
See [benchmark](benchmark) directory to get an idea of how low ebpf overhead is.
114114

115+
## Required capabilities
116+
117+
While you can run `ebpf_exporter` as `root`, it is not strictly necessary.
118+
Only the following two capabilities are necessary for normal operation:
119+
120+
* `CAP_BPF`: required for privileged bpf operations and for reading memory
121+
* `CAP_PERFMON`: required to attach bpf programs to kprobes and tracepoints
122+
123+
If you are using `systemd`, you can use the following configuration to run
124+
as on otherwise unprivileged dynamic user with the needed capabilities:
125+
126+
```ini
127+
DynamicUser=true
128+
AmbientCapabilities=CAP_BPF CAP_PERFMON
129+
CapabilityBoundingSet=CAP_BPF CAP_PERFMON
130+
```
131+
132+
Prior to Linux v5.8 there was no dedicated `CAP_BPF` and `CAP_PERFMON`,
133+
but you can use `CAP_SYS_ADMIN` instead of your kernel is older.
134+
135+
If you pass `--capabilities.keep=none` flag to `ebpf_expoter`, then it drops
136+
all capabilities after attaching the probes, leaving it fully unprivileged.
137+
138+
The following additional capabilities might be needed:
139+
140+
* `CAP_SYSLOG`: if you use `ksym` decoder to have access to `/proc/kallsyms`.
141+
Note that you must keep this capability: `--capabilities.keep=cap_syslog`.
142+
See: https://elixir.bootlin.com/linux/v6.4/source/kernel/kallsyms.c#L982
143+
* `CAP_IPC_LOCK`: if you use `perf_event_array` for reading from the kernel.
144+
Note that you must keep it: `--capabilities.keep=cap_perfmon,cap_ipc_lock`.
145+
* `CAP_SYS_ADMIN`: if you want BTF information from modules.
146+
See: https://github.com/libbpf/libbpf/blob/v1.2.0/src/libbpf.c#L8654-L8666
147+
and https://elixir.bootlin.com/linux/v6.5-rc1/source/kernel/bpf/syscall.c#L3789
148+
* `CAP_NET_ADMIN`: if you use net admin related programs like xdp.
149+
See: https://elixir.bootlin.com/linux/v6.4/source/kernel/bpf/syscall.c#L3787
150+
* `CAP_SYS_RESOURCE`: if you run an older kernel without memcg accounting for
151+
bpf memory. Upstream Linux kernel added support for this in v5.11.
152+
See: https://github.com/libbpf/libbpf/blob/v1.2.0/src/bpf.c#L98-L106
153+
115154
## Supported scenarios
116155

117156
Currently the only supported way of getting data out of the kernel is via maps.

cmd/ebpf_exporter/main.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/prometheus/client_golang/prometheus/promhttp"
1717
"github.com/prometheus/common/version"
1818
"gopkg.in/alecthomas/kingpin.v2"
19+
"kernel.org/pub/linux/libs/security/libcap/cap"
1920
)
2021

2122
func main() {
@@ -25,6 +26,7 @@ func main() {
2526
noLogTime := kingpin.Flag("log.no-timestamps", "Disable timestamps in log.").Bool()
2627
listenAddress := kingpin.Flag("web.listen-address", "The address to listen on for HTTP requests (fd://0 for systemd activation).").Default(":9435").String()
2728
metricsPath := kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String()
29+
capabilities := kingpin.Flag("capabilities.keep", "Comma separated list of capabilities to keep (cap_syslog, cap_bpf, etc.), 'all' or 'none'").Default("all").String()
2830
kingpin.Version(version.Print("ebpf_exporter"))
2931
kingpin.HelpFlag.Short('h')
3032
kingpin.Parse()
@@ -59,6 +61,11 @@ func main() {
5961
log.Fatalf("Error attaching exporter: %s", err)
6062
}
6163

64+
err = ensureCapabilities(*capabilities)
65+
if err != nil {
66+
log.Fatalf("Error dropping capabilities: %s", err)
67+
}
68+
6269
log.Printf("Started with %d programs found in the config in %dms", len(configs), time.Since(started).Milliseconds())
6370

6471
err = prometheus.Register(version.NewCollector("ebpf_exporter"))
@@ -120,6 +127,49 @@ func listen(addr string) error {
120127

121128
}
122129

130+
func ensureCapabilities(keep string) error {
131+
existing := cap.GetProc()
132+
log.Printf("Started with capabilities: %q", existing)
133+
134+
if keep == "all" {
135+
log.Printf("Retaining all existing capabilities")
136+
return nil
137+
}
138+
139+
ensure := cap.NewSet()
140+
141+
values := []cap.Value{}
142+
if keep != "none" {
143+
for _, name := range strings.Split(keep, ",") {
144+
value, err := cap.FromName(name)
145+
if err != nil {
146+
return fmt.Errorf("error parsing capability %q: %v", name, err)
147+
}
148+
149+
values = append(values, value)
150+
}
151+
}
152+
153+
err := ensure.SetFlag(cap.Permitted, true, values...)
154+
if err != nil {
155+
return fmt.Errorf("error setting permitted capabilities: %v", err)
156+
}
157+
158+
err = ensure.SetFlag(cap.Effective, true, values...)
159+
if err != nil {
160+
return fmt.Errorf("error setting effective capabilities: %v", err)
161+
}
162+
163+
err = ensure.SetProc()
164+
if err != nil {
165+
return fmt.Errorf("failed to drop capabilities: %q -> %q: %v", existing, ensure, err)
166+
}
167+
168+
log.Printf("Dropped capabilities to %q", ensure)
169+
170+
return nil
171+
}
172+
123173
func libbpfLogCallback(level int, msg string) {
124174
levelName := "unknown"
125175
switch level {

exporter/exporter.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@ func (e *Exporter) Attach() error {
112112
return fmt.Errorf("multiple configs with name %q", cfg.Name)
113113
}
114114

115-
module, err := libbpfgo.NewModuleFromFile(cfg.BPFPath)
115+
module, err := libbpfgo.NewModuleFromFileArgs(libbpfgo.NewModuleArgs{
116+
BPFObjPath: cfg.BPFPath,
117+
SkipMemlockBump: true, // Let libbpf itself decide whether it is needed
118+
})
116119
if err != nil {
117120
return fmt.Errorf("error creating module from %q for config %q: %v", cfg.BPFPath, cfg.Name, err)
118121
}

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/cloudflare/ebpf_exporter/v2
33
go 1.18
44

55
require (
6-
github.com/aquasecurity/libbpfgo v0.4.9-libbpf-1.2.0
6+
github.com/aquasecurity/libbpfgo v0.4.9-libbpf-1.2.0.0.20230724123347-7e47ce85fbec
77
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
88
github.com/elastic/go-perf v0.0.0-20191212140718-9c656876f595
99
github.com/iovisor/gobpf v0.2.0
@@ -12,6 +12,7 @@ require (
1212
golang.org/x/sys v0.10.0
1313
gopkg.in/alecthomas/kingpin.v2 v2.2.6
1414
gopkg.in/yaml.v2 v2.4.0
15+
kernel.org/pub/linux/libs/security/libcap/cap v1.2.69
1516
)
1617

1718
require (
@@ -25,4 +26,5 @@ require (
2526
github.com/prometheus/client_model v0.4.0 // indirect
2627
github.com/prometheus/procfs v0.10.1 // indirect
2728
google.golang.org/protobuf v1.30.0 // indirect
29+
kernel.org/pub/linux/libs/security/libcap/psx v1.2.69 // indirect
2830
)

go.sum

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo
22
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
33
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
44
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
5-
github.com/aquasecurity/libbpfgo v0.4.9-libbpf-1.2.0 h1:pk9L7I6wF1nTfO42+jjXhA8ozRjvtj2ZvHV/i/YC0dE=
6-
github.com/aquasecurity/libbpfgo v0.4.9-libbpf-1.2.0/go.mod h1:UD3Mfr+JZ/ASK2VMucI/zAdEhb35LtvYXvAUdrdqE9s=
5+
github.com/aquasecurity/libbpfgo v0.4.9-libbpf-1.2.0.0.20230724123347-7e47ce85fbec h1:3UdURQ4/Ja18MilfB9UWmheuHtgyoQItXZrc+XRyGrM=
6+
github.com/aquasecurity/libbpfgo v0.4.9-libbpf-1.2.0.0.20230724123347-7e47ce85fbec/go.mod h1:UD3Mfr+JZ/ASK2VMucI/zAdEhb35LtvYXvAUdrdqE9s=
77
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
88
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
99
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
@@ -58,3 +58,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
5858
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
5959
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
6060
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
61+
kernel.org/pub/linux/libs/security/libcap/cap v1.2.69 h1:N0m3tKYbkRMmDobh/47ngz+AWeV7PcfXMDi8xu3Vrag=
62+
kernel.org/pub/linux/libs/security/libcap/cap v1.2.69/go.mod h1:Tk5Ip2TuxaWGpccL7//rAsLRH6RQ/jfqTGxuN/+i/FQ=
63+
kernel.org/pub/linux/libs/security/libcap/psx v1.2.69 h1:IdrOs1ZgwGw5CI+BH6GgVVlOt+LAXoPyh7enr8lfaXs=
64+
kernel.org/pub/linux/libs/security/libcap/psx v1.2.69/go.mod h1:+l6Ee2F59XiJ2I6WR5ObpC1utCQJZ/VLsEbQCD8RG24=

0 commit comments

Comments
 (0)