I've been exploring the libbpf library for different versions of the Linux
kernel, and trying to rewrite some of the BCC tools. I would like to do more
work with CO-RE eventually, but I'm trying to understand the entire model of
how BPF programs work and how data flows between the kernel, the VM, and
userspace. I just started using perf buffers instead of bpf_trace_printk and
came across an issue that has me scratching my head. In the below code, I'm not
able to access the const char * arg in the tracepoint sys_enter_openat (kernel
4.15). For some reason the verifier rejects this code. I think it's valid C
(although I'm a little bit rusty still) and I think I followed the correct flow
where data must be copied from the kernel to the VM before being able to use.
If anyone has insight to share, I'd much appreciate it. Conversely, if anyone
can point me in the direction of how to debug BPF programs that would be
extremely helpful too. Should I just dig into learning the basics of BPF asm?
Highlights of the code:
struct bpf_map_def SEC("maps") events = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(u32),
.max_entries = MAX_CPUS,
};
struct sys_enter_openat_args {
u16 common_type;
u8 common_flags;
u8 common_preempt_count;
int common_pid;
int __syscall_nr;
int dfd;
char *filename;
int flags;
__mode_t mode;
};
SEC("tracepoint/syscalls/sys_enter_openat")
int bpf_prog(struct sys_enter_openat_args *ctx) {
struct data_t data;
struct sys_enter_openat_args *args;
int res = bpf_probe_read(args, sizeof(ctx), ctx);
if(!res) {
data.file = "couldn't get file";
} else {
data.file = args->filename;
}
Error Message:
bpf_load_program() err=13
0: (bf) r6 = r1
1: (b7) r2 = 8
2: (bf) r3 = r6
3: (85) call bpf_probe_read#4
R1 type=ctx expected=fp
The kernel didn't load the BPF program
data.pid = bpf_get_current_pid_tgid(); // use fn from libbpf.h to get pid_tgid
bpf_get_current_comm(data.program_name, sizeof(data.program_name)); // puts
current comm into char array
bpf_perf_event_output(ctx, &events, 0, &data, sizeof(data));
return 0;
}
If more code would be helpful, I'm happy to share.
I recognize that libbpf and CO-RE in later kernels provides an easier API for
dealing with char * (bpf_probe_read_str() I believe) but I'm trying to
understand what needs to be done to target different kernels and not just the
most cutting edge.
As a second question, how much should I learn about perf(1) and its overlap
with BPF?
Finally, for long-term monitoring solutions and passing readable data, do most
programs rely on pinning maps to the vfs instead of using perf buffers or
passing directly to a userspace process?
Thanks for the patience and goodwill with a new systems dev. I've enjoyed my
interactions with the BPF community.
Tristan
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#1827): https://lists.iovisor.org/g/iovisor-dev/message/1827
Mute This Topic: https://lists.iovisor.org/mt/72496365/21656
Group Owner: [email protected]
Unsubscribe: https://lists.iovisor.org/g/iovisor-dev/unsub
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-