On Mon, Mar 23, 2020 at 9:38 AM <[email protected]> wrote:
>
> 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,
> };

nit: this is a legacy syntax of specifying BPF maps, please see [0]
for some newer examples

  [0] https://github.com/iovisor/bcc/tree/master/libbpf-tools

>
> 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);

you don't need to bpf_probe_read() ctx here, you can just access its
members directly.

>   if(!res) {
>          data.file = "couldn't get file";
>   } else {
>          data.file = args->filename;

But here if you want to read filename contents itself, you'll need to
use bpf_probe_read_str().

Having data_t definition would be also helpful.

>   }
>
> 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

this error from verifier is quite misleading, but what verifier
complains about here is that you try to read uninitialized pointer
(arg) and pass it as a first parameter into bpf_probe_read(). But see
above, you don't need to bpf_probe_read() anything, and even if you
wanted to it would have to be done very differently:

struct sys_enter_openat_args args; /* notice no pointer here */
bpf_probe_read(&args, sizeof(args), ctx); /* taking address of args,
taking size of args, not its pointer */

> 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?

It's a mix. If your data should/can be pre-aggregated in kernel, using
map might benefit you in that you will be sending much less data to
user-space. But if you want to send every piece of information than
perf_buffer is faster and more convenient than having user-space query
BPF maps all the time.

>
> Thanks for the patience and goodwill with a new systems dev. I've enjoyed my 
> interactions with the BPF community.

You're welcome. Check libbpf-tools in BCC repo, it should give you
some examples to work off of.

>
> Tristan
> 

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.

View/Reply Online (#1829): https://lists.iovisor.org/g/iovisor-dev/message/1829
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]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to