How to access user space function argument (struct pointer) in bpf?

139 views Asked by At

I am using libbpf-bootstrap. For me the application "test.c" exists and its code is:

#include <stdio.h>
#include <unistd.h>

struct state_foo {
   int a;
   int b;
}


void foo(struct state_foo *s)
{
    sleep(1);
}

int main() {
    struct state_foo s_org = {0,0};
    struct state_foo *s = &s_org;
    s->a = 10; s->b = 10;
    foo(s);
    return 0;
}

I want to print or retrieve the value of "a", a member variable of struct state_foo, when the bpf program attached to function "foo" is triggered. (via bpf_prink).

below is my bpf program (uprobe.bpf.c).

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

#include <bpf/bpf_core_read.h>

char LICENSE[] SEC("license") = "Dual BSD/GPL";
    
struct state_foo {
    int a;
    int b;
};

SEC("uprobe")
void BPF_KPROBE(uprobe_test, struct state_foo *s) 
{
    int a_user = BPF_PROBE_READ_USER(s, a); //compile ok. but err -22 when run.
}

below is program (uprobe.c) which is used to attach my bpf program (uprobe.bpf.c) to user function "foo".

// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
/* Copyright (c) 2020 Facebook */
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
#include "uprobe_test.skel.h"

static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
{
    return vfprintf(stderr, format, args);
}


    int main(int argc, char **argv)
    {
        struct uprobe_test_bpf *skel;
        int err, i;
        LIBBPF_OPTS(bpf_uprobe_opts, uprobe_test_opts);
    
        /* Set up libbpf errors and debug info callback */
        libbpf_set_print(libbpf_print_fn);
    
        /* Load and verify BPF application */
        skel = uprobe_test_bpf__open_and_load();
        if (!skel) {
            fprintf(stderr, "Failed to open and load BPF skeleton\n");
            return 1;
        }
    
    
        uprobe_test_opts.func_name = "foo";
        uprobe_test_opts.retprobe = false;
        skel->links.uprobe_test = bpf_program__attach_uprobe_opts(
            skel->progs.uprobe_test, -1 , "/home/cih/test.o",
            0, &uprobe_test_opts );
        if (!skel->links.uprobe_test) {
            err = -errno;
            fprintf(stderr, "Failed to attach uprobe (uprobe_test): %d\n", err);
            goto cleanup;
        }
    
        printf("Successfully started! Please run `sudo cat /sys/kernel/debug/tracing/trace_pipe` "
               "to see output of the BPF programs.\n");
    
        while (1) {
            printf("running app\n");
            sleep(1);
        }
        return 0;
    
    cleanup:
        uprobe_test_bpf__destroy(skel);
        return -err;
    }

But, when I try to run, libbpf show errors as follows.

libbpf: prog 'uprobe_test': BPF program load failed: Invalid argument
libbpf: prog 'uprobe_test': -- BEGIN PROG LOAD LOG --
Unrecognized arg#0 type PTR
; void BPF_KPROBE(uprobe_test, struct state_foo *s) 
0: (79) r3 = *(u64 *)(r1 +112)
1: <invalid CO-RE relocation>
failed to resolve CO-RE relocation <byte_off> [11] struct state_foo.b (0:1 @ offset 4)
processed 2 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
-- END PROG LOAD LOG --
libbpf: prog 'uprobe_test': failed to load: -22
libbpf: failed to load object 'uprobe_test_bpf'
libbpf: failed to load BPF skeleton 'uprobe_test_bpf': -22
Failed to open and load BPF skeleton

Could you please give me some hints as to why this error occurs?

If the form of the function "foo" is not "foo(struct state_foo *s)" but is equal to "foo(int a)", it has been confirmed that the bpf program is executed normally and the value of "a" is printed correctly. However, a problem occurred when the argument was "struct". Any help would be greatly appreciated.

1

There are 1 answers

6
chux - Reinstate Monica On

struct state_foo *s; s->a = 10; is invalid as pointer s does not yet have a valid value to do s->a.