Skip to content
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

CFLAGS #cgo pragma in libbpfgo.go cannot be ignored for static building #1

Open
grantseltzer opened this issue May 17, 2021 · 4 comments
Assignees
Labels
bug Something isn't working good first issue Good for newcomers

Comments

@grantseltzer
Copy link
Contributor

When building a project that uses libbpfgo, the go compiler must be given a linker flag pointing to libbpf. If libbpf is installed in a standard location -lbpf can be passed. They can also point to a specific location. Since go get attempts to build the package without any ldflags, this will cause the errors pasted below.

Users could do something like: CGO_LDFLAGS="-lbpf" go get github.com/aquasecurity/tracee. Alternatively we can add a line for CGO_LDFLAGS in the CGO code.

This shouldn't cause any related issues if not using go get.

For example:

[*] go get github.com/aquasecurity/libbpfgo

go: downloading github.com/aquasecurity/libbpfgo v0.0.0-20210517223445-485e1cdc10ae
go: downloading golang.org/x/sys v0.0.0-20210514084401-e8d321eab015
# github.com/aquasecurity/libbpfgo
/usr/bin/ld: $WORK/b001/_x003.o: in function `init_ring_buf':
../../../../../pkg/mod/github.com/aquasecurity/[email protected]/libbpfgo.go:40: undefined reference to `ring_buffer__new'
/usr/bin/ld: $WORK/b001/_x003.o: in function `init_perf_buf':
../../../../../pkg/mod/github.com/aquasecurity/[email protected]/libbpfgo.go:54: undefined reference to `perf_buffer__new'
/usr/bin/ld: $WORK/b001/_x003.o: in function `attach_kprobe_legacy':
../../../../../pkg/mod/github.com/aquasecurity/[email protected]/libbpfgo.go:158: undefined reference to `bpf_program__attach_perf_event'
/usr/bin/ld: ../../../../../pkg/mod/github.com/aquasecurity/[email protected]/libbpfgo.go:159: undefined reference to `libbpf_get_error'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_link__destroy':
/tmp/go-build/cgo-gcc-prolog:74: undefined reference to `bpf_link__destroy'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_map__fd':
/tmp/go-build/cgo-gcc-prolog:93: undefined reference to `bpf_map__fd'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_map__max_entries':
/tmp/go-build/cgo-gcc-prolog:112: undefined reference to `bpf_map__max_entries'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_map__pin':
/tmp/go-build/cgo-gcc-prolog:132: undefined reference to `bpf_map__pin'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_map__resize':
/tmp/go-build/cgo-gcc-prolog:153: undefined reference to `bpf_map__resize'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_map__set_pin_path':
/tmp/go-build/cgo-gcc-prolog:173: undefined reference to `bpf_map__set_pin_path'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_map__unpin':
/tmp/go-build/cgo-gcc-prolog:193: undefined reference to `bpf_map__unpin'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_map_delete_elem':
/tmp/go-build/cgo-gcc-prolog:214: undefined reference to `bpf_map_delete_elem'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_map_lookup_elem':
/tmp/go-build/cgo-gcc-prolog:236: undefined reference to `bpf_map_lookup_elem'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_map_update_elem':
/tmp/go-build/cgo-gcc-prolog:259: undefined reference to `bpf_map_update_elem'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_object__find_map_by_name':
/tmp/go-build/cgo-gcc-prolog:290: undefined reference to `bpf_object__find_map_by_name'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_object__find_program_by_name':
/tmp/go-build/cgo-gcc-prolog:309: undefined reference to `bpf_object__find_program_by_name'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_object__load':
/tmp/go-build/cgo-gcc-prolog:328: undefined reference to `bpf_object__load'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_object__open':
/tmp/go-build/cgo-gcc-prolog:346: undefined reference to `bpf_object__open'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_object__open_buffer':
/tmp/go-build/cgo-gcc-prolog:366: undefined reference to `bpf_object__open_buffer'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_program__attach_kprobe':
/tmp/go-build/cgo-gcc-prolog:387: undefined reference to `bpf_program__attach_kprobe'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_program__attach_lsm':
/tmp/go-build/cgo-gcc-prolog:405: undefined reference to `bpf_program__attach_lsm'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_program__attach_raw_tracepoint':
/tmp/go-build/cgo-gcc-prolog:424: undefined reference to `bpf_program__attach_raw_tracepoint'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_program__attach_tracepoint':
/tmp/go-build/cgo-gcc-prolog:444: undefined reference to `bpf_program__attach_tracepoint'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_program__fd':
/tmp/go-build/cgo-gcc-prolog:463: undefined reference to `bpf_program__fd'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_program__get_type':
/tmp/go-build/cgo-gcc-prolog:482: undefined reference to `bpf_program__get_type'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_program__set_autoload':
/tmp/go-build/cgo-gcc-prolog:503: undefined reference to `bpf_program__set_autoload'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_program__set_tracepoint':
/tmp/go-build/cgo-gcc-prolog:522: undefined reference to `bpf_program__set_tracepoint'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_perf_buffer__poll':
/tmp/go-build/cgo-gcc-prolog:607: undefined reference to `perf_buffer__poll'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_ring_buffer__poll':
/tmp/go-build/cgo-gcc-prolog:661: undefined reference to `ring_buffer__poll'
/usr/bin/ld: $WORK/b001/_x003.o: in function `set_print_fn':
../../../../../pkg/mod/github.com/aquasecurity/[email protected]/libbpfgo.go:35: undefined reference to `libbpf_set_print'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_bpf_object__close':
/tmp/go-build/cgo-gcc-prolog:274: undefined reference to `bpf_object__close'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_perf_buffer__free':
/tmp/go-build/cgo-gcc-prolog:589: undefined reference to `perf_buffer__free'
/usr/bin/ld: $WORK/b001/_x003.o: in function `_cgo_a66f50300837_Cfunc_ring_buffer__free':
/tmp/go-build/cgo-gcc-prolog:643: undefined reference to `ring_buffer__free'
collect2: error: ld returned 1 exit status
@grantseltzer grantseltzer added the bug Something isn't working label May 20, 2021
@rafaeldtinoco
Copy link
Contributor

This was somehow handled by:

#28

But now we have to address the following:

#28 (comment)

So I would say this issue has become the issue described above.

@rafaeldtinoco rafaeldtinoco changed the title Using go get causes linker errors CFLAGS #cgo pragma in libbpfgo.go cannot be ignored for static building Jul 30, 2021
@rafaeldtinoco rafaeldtinoco self-assigned this Jul 30, 2021
@rafaeldtinoco
Copy link
Contributor

The Makefile file in tracee uses pkgconfig for the libbpf static compilation:

image

libbpfgo could do the same and use:

// #cgo pkg-config: libelf zlib

to have this issue addressed.

@ShubhamPalriwala
Copy link

Just faced the exact same bug when trying to run a test here in Tracee with:

tracee/cmd/tracee-ebpf/internal/printer
go test -v

@MaciekLeks
Copy link

I've struggled the same or almost the same "thing".
So, this code does not work:

CGO_CFLAGS_STATIC = "-I$(abspath $(LIBBPF_DIR))"
CGO_LDFLAGS_STATIC = "-lelf -lz $(LIBBPF_STATIC_LIB)"
CGO_EXTLDFLAGS_STATIC = '-w -extldflags "-static"'
.PHONY: k8s-build-cmd
k8s-build-cmd:  $(CMD_K8S_GO_SOURCE) $(TARGET_BPF) 
	CGO_CFLAGS=$(CGO_CFLAGS_STATIC) \
	CGO_LDFLAGS=$(CGO_LDFLAGS_STATIC) \
	$(GO) build -x \
	-tags netgo -ldflags $(CGO_EXTLDFLAGS_STATIC) \
	-o $(TARGET_K8S) ./cmd/kubernetes/$(MAIN).go

but this works well:

CGO_CFLAGS_STATIC = "-I$(abspath $(LIBBPF_DIR))"
CGO_LDFLAGS_STATIC = "-lelf -lz $(LIBBPF_STATIC_LIB)"
GO_EXTLDFLAGS_STATIC = '-w -extldflags "-static $(LIBBPF_STATIC_LIB) -lelf -lz"'
#^ librabbry order is important for GO_EXTLDFLAGS_STATIC
k8s-build-cmd: $(CMD_K8S_GO_SOURCE) $(TARGET_BPF)
	CGO_CFLAGS=$(CGO_CFLAGS_STATIC) \
	$(GO) build -x \
	-tags netgo -ldflags $(GO_EXTLDFLAGS_STATIC) \
	-o $(TARGET_K8S) ./cmd/kubernetes/$(MAIN).go

So, the only difference is moving LDFLAGS on the go build level and changing order of the libs.

javierhonduco added a commit to javierhonduco/libbpfgo that referenced this issue May 9, 2023
In
aquasecurity@0238ec3
the freeing of C strings was changed to use defers. This can cause a
double-free, which in the best case it will produce a crash. The reason
why this happens is that the memory address at `defer` time is captured
for later execution. If `KConfigFilePath` is less than 3, it was being
freed and set to NULL. Once the defer executes on function return, the
same address we already freed will be passed again.

We observed this while upgrading libbpfgo in Parca Agent
(parca-dev/parca-agent#1599).

Test Plan
=========

Verified it's a double free with ASAN

```
=================================================================
==171270==ERROR: AddressSanitizer: attempting double-free on 0x602000000010 in thread T14:
    #0 0x4d6e68 in __interceptor_free.part.0 asan_malloc_linux.cpp.o
    aquasecurity#1 0x3004be2 in _cgo_38fdf0a0bedf_Cfunc_free (/home/javierhonduco/code/parca-agent/dist/parca-agent+0x3004be2) (BuildId: aebc1e250e9da366a49de9206c528fb67b730e0b)
    aquasecurity#2 0x58bac3 in runtime.asmcgocall.abi0 runtime/asm_amd64.s:848

0x602000000010 is located 0 bytes inside of 1-byte region [0x602000000010,0x602000000011)
freed by thread T14 here:
    #0 0x4d6e68 in __interceptor_free.part.0 asan_malloc_linux.cpp.o
    aquasecurity#1 0x3004be2 in _cgo_38fdf0a0bedf_Cfunc_free (/home/javierhonduco/code/parca-agent/dist/parca-agent+0x3004be2) (BuildId: aebc1e250e9da366a49de9206c528fb67b730e0b)
    aquasecurity#2 0x58bac3 in runtime.asmcgocall.abi0 runtime/asm_amd64.s:848

previously allocated by thread T14 here:
    #0 0x4d7e37 in __interceptor_malloc (/home/javierhonduco/code/parca-agent/dist/parca-agent+0x4d7e37) (BuildId: aebc1e250e9da366a49de9206c528fb67b730e0b)
    aquasecurity#1 0x2ff3ff2 in _cgo_38fdf0a0bedf_Cfunc__Cmalloc (/home/javierhonduco/code/parca-agent/dist/parca-agent+0x2ff3ff2) (BuildId: aebc1e250e9da366a49de9206c528fb67b730e0b)
    aquasecurity#2 0x58bac3 in runtime.asmcgocall.abi0 runtime/asm_amd64.s:848
```

And that there are no issues with this patch applied, both while running
the Agent with and without ASAN as well as while running the cpu
profiling integration tests which exercise this code path.

Signed-off-by: Francisco Javier Honduvilla Coto <[email protected]>
javierhonduco added a commit to javierhonduco/libbpfgo that referenced this issue May 9, 2023
In
aquasecurity@0238ec3
the freeing of C strings was changed to use defers. This can cause a
double-free, which in the best case it will produce a crash. The reason
why this happens is that the memory address at `defer` time is captured
for later execution. If `KConfigFilePath` is less than 3, it was being
freed and set to NULL. Once the defer executes on function return, the
same address we already freed will be passed again.

We observed this while upgrading libbpfgo in Parca Agent
(parca-dev/parca-agent#1599).

Test Plan
=========

Verified it's a double free with ASAN

```
=================================================================
==171270==ERROR: AddressSanitizer: attempting double-free on 0x602000000010 in thread T14:
    #0 0x4d6e68 in __interceptor_free.part.0 asan_malloc_linux.cpp.o
    aquasecurity#1 0x3004be2 in _cgo_38fdf0a0bedf_Cfunc_free (/home/javierhonduco/code/parca-agent/dist/parca-agent+0x3004be2) (BuildId: aebc1e250e9da366a49de9206c528fb67b730e0b)
    aquasecurity#2 0x58bac3 in runtime.asmcgocall.abi0 runtime/asm_amd64.s:848

0x602000000010 is located 0 bytes inside of 1-byte region [0x602000000010,0x602000000011)
freed by thread T14 here:
    #0 0x4d6e68 in __interceptor_free.part.0 asan_malloc_linux.cpp.o
    aquasecurity#1 0x3004be2 in _cgo_38fdf0a0bedf_Cfunc_free (/home/javierhonduco/code/parca-agent/dist/parca-agent+0x3004be2) (BuildId: aebc1e250e9da366a49de9206c528fb67b730e0b)
    aquasecurity#2 0x58bac3 in runtime.asmcgocall.abi0 runtime/asm_amd64.s:848

previously allocated by thread T14 here:
    #0 0x4d7e37 in __interceptor_malloc (/home/javierhonduco/code/parca-agent/dist/parca-agent+0x4d7e37) (BuildId: aebc1e250e9da366a49de9206c528fb67b730e0b)
    aquasecurity#1 0x2ff3ff2 in _cgo_38fdf0a0bedf_Cfunc__Cmalloc (/home/javierhonduco/code/parca-agent/dist/parca-agent+0x2ff3ff2) (BuildId: aebc1e250e9da366a49de9206c528fb67b730e0b)
    aquasecurity#2 0x58bac3 in runtime.asmcgocall.abi0 runtime/asm_amd64.s:848
```

And that there are no issues with this patch applied, both while running
the Agent with and without ASAN as well as while running the cpu
profiling integration tests which exercise this code path.

Signed-off-by: Francisco Javier Honduvilla Coto <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

4 participants