8000 Add embed directive to embed the compiled CORE bpf object into go binary by grantseltzer · Pull Request #818 · aquasecurity/tracee · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add embed directive to embed the compiled CORE bpf object into go binary #818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 23, 2021
26 changes: 11 additions & 15 deletions tracee-ebpf/Makefile
8000
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,8 @@ OUT_DIR ?= dist
GO_SRC := $(shell find . -type f -name '*.go')
OUT_BIN := $(OUT_DIR)/tracee-ebpf
BPF_SRC := tracee/tracee.bpf.c

ifndef CORE
OUT_BPF := $(OUT_DIR)/tracee.bpf.$(subst .,_,$(KERN_RELEASE)).$(subst .,_,$(VERSION)).o
else
OUT_BPF := $(OUT_DIR)/tracee.bpf.core.$(subst .,_,$(VERSION)).o
endif
OUT_BPF_CORE := $(OUT_DIR)/tracee.bpf.core.o
BPF_HEADERS := 3rdparty/include
BPF_BUNDLE := $(OUT_DIR)/tracee.bpf.tar.gz
LIBBPF_SRC := 3rdparty/libbpf/src
Expand All @@ -47,9 +43,9 @@ build: $(OUT_BIN)

go_env := GOOS=linux GOARCH=$(ARCH:x86_64=amd64) CC=$(CMD_CLANG) CGO_CFLAGS="-I $(abspath $(LIBBPF_HEADERS))" CGO_LDFLAGS="$(abspath $(LIBBPF_OBJ))"
ifndef DOCKER
$(OUT_BIN): $(LIBBPF_HEADERS) $(LIBBPF_OBJ) $(filter-out *_test.go,$(GO_SRC)) $(BPF_BUNDLE) | $(OUT_DIR)
$(OUT_BIN): $(LIBBPF_HEADERS) $(LIBBPF_OBJ) $(OUT_BPF_CORE) $(filter-out *_test.go,$(GO_SRC)) $(BPF_BUNDLE) | $(OUT_DIR)
$(go_env) go build -v -o $(OUT_BIN) \
-ldflags "-X main.version=$(VERSION) -X main.bpf_core=$(CORE)"
-ldflags "-X main.version=$(VERSION)"
else
$(OUT_BIN): $(DOCKER_BUILDER) | $(OUT_DIR)
$(call docker_builder_make,$@ VERSION=$(VERSION))
Expand All @@ -74,11 +70,10 @@ $(BPF_BUNDLE): $(BPF_SRC) $(LIBBPF_HEADERS)/bpf $(BPF_HEADERS)
cp $$(find $^ -type f) $(bpf_bundle_dir)

.PHONY: bpf
bpf: $(OUT_BPF)
bpf: $(OUT_BPF) $(OUT_BPF_CORE)

linux_arch := $(ARCH:x86_64=x86)
ifndef DOCKER
ifndef CORE
$(OUT_DIR)/tracee.bpf.%.o: $(BPF_SRC) $(LIBBPF_HEADERS) | $(OUT_DIR) $(bpf_compile_tools)
@v=$$($(CMD_CLANG) --version); test $$(echo $${v#*version} | head -n1 | cut -d '.' -f1) -ge '9' || (echo 'required minimum clang version: 9' ; false)
$(CMD_CLANG) -S \
Expand Down Expand Up @@ -117,9 +112,8 @@ $(OUT_DIR)/tracee.bpf.%.o: $(BPF_SRC) $(LIBBPF_HEADERS) | $(OUT_DIR) $(bpf_compi
$(CMD_LLC) -march=bpf -filetype=obj -o $@ $(@:.o=.ll)
-$(CMD_LLVM_STRIP) -g $@
rm $(@:.o=.ll)
else
#docker no, CO:RE yes
$(OUT_DIR)/tracee.bpf.core.%.o: $(BPF_SRC) $(LIBBPF_HEADERS) $(CMD_CLANG)

$(OUT_BPF_CORE): $(BPF_SRC) $(LIBBPF_HEADERS) $(CMD_CLANG)
$(CMD_CLANG) \
-I $(LIBBPF_HEADERS)/bpf \
-I $(BPF_HEADERS) \
Expand All @@ -132,11 +126,13 @@ $(OUT_DIR)/tracee.bpf.core.%.o: $(BPF_SRC) $(LIBBPF_HEADERS) $(CMD_CLANG)
-DLINUX_VERSION_CODE=$(LINUX_VERSION_CODE) \
-target bpf \
-O2 -c -g -o $@ $<
endif
else
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DOCKER mode seem to be inconsistently supported for the obj files now. We need to be able to build both obj targets with docker and without. currently I think it's not possible? (haven't tried, just by reading the code)
If I'm right, would be easier to implement, and also more readable to just copy the same stanza from the other targets (e.g the OUT_BIN target) where the DOKCER variance is inside the target, not outside.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it resolved? I don't see any change in the code

Copy link
Contributor Author
@grantseltzer grantseltzer Jul 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, I forgot to git push... Sorry about that.

#docker yes
$(OUT_BPF): $(DOCKER_BUILDER) | $(OUT_DIR)
$(call docker_builder_make,$@)

$(OUT_BPF_CORE): $(DOCKER_BUILDER) | $(OUT_DIR)
$(call docker_builder_make,$@)
endif

.PHONY: test
Expand Down Expand Up @@ -164,12 +160,12 @@ define docker_builder_make
-v $(abspath $(DOCKER_BUILDER_KERN_SRC_MNT)):$(DOCKER_BUILDER_KERN_SRC_MNT) \
-v $(abspath .):/tracee/tracee-ebpf \
-w /tracee/tracee-ebpf \
--entrypoint make $(DOCKER_BUILDER) KERN_BLD_PATH=$(DOCKER_BUILDER_KERN_BLD) CORE="$(CORE)" KERN_SRC_PATH=$(DOCKER_BUILDER_KERN_SRC) $(1)
--entrypoint make $(DOCKER_BUILDER) KERN_BLD_PATH=$(DOCKER_BUILDER_KERN_BLD) KERN_SRC_PATH=$(DOCKER_BUILDER_KERN_SRC) $(1)
endef

.PHONY: mostlyclean
mostlyclean:
-rm -rf $(OUT_BIN) $(bpf_bundle_dir) $(OUT_BPF) $(BPF_BUNDLE)
-rm -rf $(OUT_BIN) $(bpf_bundle_dir) $(OUT_BPF) $(OUT_BPF_CORE) $(BPF_BUNDLE)

.PHONY: clean
clean:
Expand Down
83 changes: 74 additions & 9 deletions tracee-ebpf/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ var buildPolicy string

// These vars are supposed to be injected at build time
//go:embed "dist/tracee.bpf/*"
//go:embed "dist/tracee.bpf.core.o"
var bpfBundleInjected embed.FS
var version string
var bpf_core string

func main() {
app := &cli.App{
Expand Down Expand Up @@ -67,11 +67,48 @@ func main() {
if c.Bool("security-alerts") {
cfg.Filter.EventsToTrace = append(cfg.Filter.EventsToTrace, tracee.MemProtAlertEventID)
}
bpfFile, err := getBPFObject()

var bpfBytes []byte

// Check if user specified a bpf object path explicitly
bpfFilePath, err := checkTraceeBPFEnvPath()
if err != nil {
return err
}
cfg.BPFObjPath = bpfFile
if bpfFilePath != "" {
if debug {
fmt.Printf("BPF object file specified by TRACEE_BPF_FILE found: %s", bpfFilePath)
}
bpfBytes, err = ioutil.ReadFile(bpfFilePath)
if err != nil {
return err
}
} else if btfEnabled() {
if debug {
fmt.Println("BTF enabled, attempting to unpack CORE bpf object")
}
bpfFilePath = "embedded-core"
bpfBytes, err = unpackCOREBinary()
if err != nil {
return err
}
} else {
if debug {
fmt.Println("BTF is not enabled")
}
bpfFilePath, err = getBPFObjectPath()
if err != nil {
return err
}
bpfBytes, err = ioutil.ReadFile(bpfFilePath)
if err != nil {
return err
}
}

cfg.BPFObjPath = bpfFilePath
cfg.BPFObjBytes = bpfBytes

if !checkRequiredCapabilities() {
return fmt.Errorf("insufficient privileges to run")
}
Expand Down Expand Up @@ -826,6 +863,7 @@ func parseRetFilter(filterName string, operatorAndValues string, eventsNameToID

return nil
}

func prepareEventsToTrace(eventFilter *tracee.StringFilter, setFilter *tracee.StringFilter, eventsNameToID map[string]int32) ([]int32, error) {
eventFilter.Enabled = true
eventsToTrace := eventFilter.Equal
Expand Down Expand Up @@ -1020,6 +1058,14 @@ func printList() {
// It first tries in the paths given by the dirs, and then a system lookup
func locateFile(file string, dirs []string) string {
var res string

if filepath.IsAbs(file) {
_, err := os.Stat(file)
if err == nil {
return file
}
}

for _, dir := range dirs {
if dir != "" {
fi, err := os.Stat(filepath.Join(dir, file))
Expand All @@ -1037,20 +1083,19 @@ func locateFile(file string, dirs []string) string {
return ""
}

// getBPFObject finds or builds ebpf object file and returns it's path
func getBPFObject() (string, error) {
func checkTraceeBPFEnvPath() (string, error) {
bpfPath, present := os.LookupEnv("TRACEE_BPF_FILE")
if present {
if _, err := os.Stat(bpfPath); os.IsNotExist(err) {
return "", fmt.Errorf("path given in TRACEE_BPF_FILE doesn't exist!")
}
return bpfPath, nil
}
return "", nil
}

bpfObjFileName := fmt.Sprintf("tracee.bpf.%s.%s.o", strings.ReplaceAll(tracee.UnameRelease(), ".", "_"), strings.ReplaceAll(version, ".", "_"))
if bpf_core != "" {
bpfObjFileName = fmt.Sprintf("tracee.bpf.core.%s.o", strings.ReplaceAll(version, ".", "_"))
}
// getBPFObjectPath finds or builds ebpf object file and returns it's path
func getBPFObjectPath() (string, error) {

exePath, err := os.Executable()
if err != nil {
Expand All @@ -1061,6 +1106,8 @@ func getBPFObject() (string, error) {
filepath.Dir(exePath),
traceeInstallPath,
}

bpfObjFileName := fmt.Sprintf("tracee.bpf.%s.%s.o", strings.ReplaceAll(tracee.UnameRelease(), ".", "_"), strings.ReplaceAll(version, ".", "_"))
bpfObjFilePath := locateFile(bpfObjFileName, searchPaths)
if bpfObjFilePath != "" && debug {
fmt.Printf("found bpf object file at: %s\n", bpfObjFilePath)
Expand All @@ -1087,6 +1134,19 @@ func getBPFObject() (string, error) {
return bpfObjFilePath, nil
}

func unpackCOREBinary() ([]byte, error) {
b, err := bpfBundleInjected.ReadFile("dist/tracee.bpf.core.o")
if err != nil {
return nil, err
}

if debug {
fmt.Println("unpacked CO:RE bpf object file into memory")
}

return b, nil
}

// unpackBPFBundle unpacks the bundle into the provided directory
func unpackBPFBundle(dir string) error {
basePath := "dist/tracee.bpf"
Expand Down Expand Up @@ -1321,3 +1381,8 @@ func makeBPFObject(outFile string) error {

return nil
}

func btfEnabled() bool {
_, err := os.Stat("/sys/kernel/btf/vmlinux")
return err == nil
}
16 changes: 9 additions & 7 deletions tracee-ebpf/tracee/tracee.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -41,6 +42,7 @@ type Config struct {
Debug bool
maxPidsCache int // maximum number of pids to cache per mnt ns (in Tracee.pidsInMntns)
BPFObjPath string
BPFObjBytes []byte
ChanEvents chan external.Event
}

Expand Down Expand Up @@ -181,12 +183,12 @@ func (tc Config) Validate() error {
return fmt.Errorf("the length of a path filter is limited to 50 characters: %s", filter)
}
}
_, err := os.Stat(tc.BPFObjPath)
if err != nil {
return err

if tc.BPFObjBytes == nil {
return errors.New("nil bpf object in memory")
}

err = tc.Output.Validate()
err := tc.Output.Validate()
if err != nil {
return err
}
Expand Down Expand Up @@ -351,7 +353,7 @@ func New(cfg Config) (*Tracee, error) {
}
}

err = t.initBPF(cfg.BPFObjPath)
err = t.initBPF()
if err != nil {
t.Close()
return nil, err
Expand Down Expand Up @@ -932,10 +934,10 @@ func (t *Tracee) attachNetProbes() error {
return nil
}

func (t *Tracee) initBPF(bpfObjectPath string) error {
func (t *Tracee) initBPF() error {
var err error

t.bpfModule, err = bpf.NewModuleFromFile(bpfObjectPath)
t.bpfModule, err = bpf.NewModuleFromBuffer(t.config.BPFObjBytes, t.config.BPFObjPath)
if err != nil {
return err
}
Expand Down
0