One minute
When LLVM’s Optimizer Breaks Your eBPF Program
This is a weird bug I ran into while working on the ebpf. A call to the built-in function ‘memset’ is not supported, and the confusing part was that I was using __builtin_memset. Here is the code.
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#define PATH_MAX 1024
struct path_key {
char container_path[PATH_MAX]; // 1024 bytes
char directory_path[PATH_MAX]; // 1024 bytes
};
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 1);
__type(key, u32);
__type(value, struct path_key);
} temp_map SEC(".maps");
SEC("kprobe/vfs_open_broken")
int broken_no_barrier(struct pt_regs *ctx)
{
u32 idx = 0;
struct path_key *out = bpf_map_lookup_elem(&temp_map, &idx);
if (!out)
return 0;
__builtin_memset(out->container_path, 0, sizeof(out->container_path));
__builtin_memset(out->directory_path, 0, sizeof(out->directory_path));
const char *path = "/some/path";
bpf_probe_read_kernel_str(out->directory_path,
sizeof(out->directory_path), path);
return 0;
}
char LICENSE[] SEC("license") = "GPL";
And when I commented out one of __builtin_memset it worked, and so it had to be how LLVM was compiling the code, which is most likely the reason for this.
call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(2048) %3, i8 0, i64 2048, i1 false), !dbg !131
LLVM merged my two 1K memsets into a single 2K operation.
Fix
I had to insert an asm volatile memory barrier after each memset asm volatile("" ::: "memory"); https://docs.ebpf.io/ebpf-library/libbpf/ebpf/barrier/ and this prevents the LLVM optimizer from merging the two memsets into one.
Read other posts