├── Dockerfile ├── Makefile ├── README.md └── app ├── Makefile ├── go.mod └── src ├── bpf └── execve.bpf.c └── main.go /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM almalinux:8.5 as builder 2 | RUN dnf install epel-release dnf-plugins-core -y 3 | #RUN dnf config-manager --enable epel -y 4 | #RUN dnf repolist 5 | RUN dnf --enablerepo=powertools install clang go make libbpf-devel -y 6 | WORKDIR / 7 | COPY app . 8 | RUN make 9 | 10 | FROM scratch 11 | COPY --from=builder /exec_scrape /exec_scrape 12 | CMD ["/exec_scrape"] 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | APP="exec_scrape" 2 | REG="192.168.2.51:5000" 3 | 4 | .PHONY: build 5 | build: vmlinux 6 | docker build -t $(APP) . 7 | -docker rm -f dummy 8 | docker create -it --name dummy $(APP) /bin/sh 9 | docker cp dummy:$(APP) $(APP) 10 | docker rm -f dummy 11 | docker save $(APP) | gzip -9 > $(APP).tar.gz 12 | 13 | .PHONY: push 14 | push: build 15 | docker tag $(APP) $(REG)/$(APP) 16 | docker push $(REG)/$(APP) 17 | docker image remove $(REG)/$(APP) 18 | 19 | .PHONY: rund 20 | rund: build 21 | docker run -it --privileged -v /sys/kernel/debug:/sys/kernel/debug $(APP) 22 | 23 | .PHONY: container 24 | container: build 25 | docker run -it --privileged -v /sys/kernel/debug:/sys/kernel/debug $(APP) /bin/sh 26 | 27 | .PHONY: vmlinux 28 | vmlinux: 29 | cd app && make clean && make vmlinux 30 | 31 | .PHONY: clean 32 | clean: 33 | -docker system prune -a 34 | -rm -f $(APP) 35 | cd app && make clean -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bpf_with_go 2 | -------------------------------------------------------------------------------- /app/Makefile: -------------------------------------------------------------------------------- 1 | APP=exec_scrape 2 | 3 | .PHONY: build 4 | build: gen $(APP) 5 | 6 | .PHONY: run 7 | run: build 8 | sudo ./$(APP) 9 | 10 | .PHONY: gen 11 | gen: sum vmlinux src/gen_execve_bpfel.go 12 | 13 | .PHONY: vmlinux 14 | vmlinux: src/bpf/vmlinux.h 15 | 16 | .PHONY: sum 17 | sum: go.sum 18 | 19 | .PHONY: fmt 20 | fmt: sum 21 | go fmt src/*.go 22 | 23 | .PHONY: clean 24 | clean: 25 | -rm $(APP) 26 | -rm src/gen* 27 | -rm src/bpf/vmlinux.h 28 | -rm go.sum 29 | sed 's/v.*/latest/g' -i go.mod 30 | 31 | $(APP): src/main.go src/gen_execve_bpfel.go 32 | CGO_ENABLED=0 go build -o $(APP) src/*.go 33 | 34 | src/bpf/vmlinux.h: 35 | bpftool btf dump file /sys/kernel/btf/vmlinux format c > src/bpf/vmlinux.h 36 | 37 | src/gen_execve_bpfel.go: src/bpf/execve.bpf.c 38 | go generate src/*.go 39 | 40 | go.sum: 41 | go mod download github.com/cilium/ebpf 42 | go get github.com/cilium/ebpf/internal/unix 43 | -------------------------------------------------------------------------------- /app/go.mod: -------------------------------------------------------------------------------- 1 | module gobpf-test 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/cilium/ebpf latest 7 | golang.org/x/sys latest 8 | ) 9 | -------------------------------------------------------------------------------- /app/src/bpf/execve.bpf.c: -------------------------------------------------------------------------------- 1 | #include "vmlinux.h" 2 | #include 3 | 4 | #define FNAME_LEN 32 5 | struct exec_data_t { 6 | u32 pid; 7 | u8 fname[FNAME_LEN]; 8 | u8 comm[FNAME_LEN]; 9 | }; 10 | 11 | // For Rust libbpf-rs only 12 | struct exec_data_t _edt = {0}; 13 | 14 | struct { 15 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); 16 | __uint(key_size, sizeof(u32)); 17 | __uint(value_size, sizeof(u32)); 18 | } events SEC(".maps"); 19 | 20 | struct execve_entry_args_t { 21 | u64 _unused; 22 | u64 _unused2; 23 | 24 | const char* filename; 25 | const char* const* argv; 26 | const char* const* envp; 27 | }; 28 | 29 | #define LAST_32_BITS(x) x & 0xFFFFFFFF 30 | #define FIRST_32_BITS(x) x >> 32 31 | 32 | SEC("tracepoint/syscalls/sys_enter_execve") 33 | int enter_execve(struct execve_entry_args_t *args) 34 | { 35 | struct exec_data_t exec_data = {}; 36 | u64 pid_tgid; 37 | 38 | pid_tgid = bpf_get_current_pid_tgid(); 39 | exec_data.pid = LAST_32_BITS(pid_tgid); 40 | 41 | bpf_probe_read_user_str(exec_data.fname, 42 | sizeof(exec_data.fname), args->filename); 43 | 44 | bpf_get_current_comm(exec_data.comm, sizeof(exec_data.comm)); 45 | 46 | bpf_perf_event_output(args, &events, 47 | BPF_F_CURRENT_CPU, &exec_data, sizeof(exec_data)); 48 | 49 | bpf_printk("hello, world\n"); 50 | 51 | return 0; 52 | } 53 | 54 | char LICENSE[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /app/src/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target bpfel -cc clang gen_execve ./bpf/execve.bpf.c -- -I/usr/include/bpf -I. 4 | 5 | import ( 6 | "bytes" 7 | "encoding/binary" 8 | "fmt" 9 | "github.com/cilium/ebpf/link" 10 | "github.com/cilium/ebpf/perf" 11 | "golang.org/x/sys/unix" 12 | "log" 13 | "os" 14 | ) 15 | 16 | type exec_data_t struct { 17 | Pid uint32 18 | F_name [32]byte 19 | Comm [32]byte 20 | } 21 | 22 | func setlimit() { 23 | if err := unix.Setrlimit(unix.RLIMIT_MEMLOCK, 24 | &unix.Rlimit{ 25 | Cur: unix.RLIM_INFINITY, 26 | Max: unix.RLIM_INFINITY, 27 | }); err != nil { 28 | log.Fatalf("failed to set temporary rlimit: %v", err) 29 | } 30 | } 31 | 32 | func main() { 33 | setlimit() 34 | 35 | objs := gen_execveObjects{} 36 | 37 | loadGen_execveObjects(&objs, nil) 38 | link.Tracepoint("syscalls", "sys_enter_execve", objs.EnterExecve) 39 | 40 | rd, err := perf.NewReader(objs.Events, os.Getpagesize()) 41 | if err != nil { 42 | log.Fatalf("reader err") 43 | } 44 | 45 | for { 46 | ev, err := rd.Read() 47 | if err != nil { 48 | log.Fatalf("Read fail") 49 | } 50 | 51 | if ev.LostSamples != 0 { 52 | log.Printf("perf event ring buffer full, dropped %d samples", ev.LostSamples) 53 | continue 54 | } 55 | 56 | b_arr := bytes.NewBuffer(ev.RawSample) 57 | 58 | var data exec_data_t 59 | if err := binary.Read(b_arr, binary.LittleEndian, &data); err != nil { 60 | log.Printf("parsing perf event: %s", err) 61 | continue 62 | } 63 | 64 | fmt.Printf("On cpu %02d %s ran : %d %s\n", 65 | ev.CPU, data.Comm, data.Pid, data.F_name) 66 | } 67 | } 68 | --------------------------------------------------------------------------------