libbpf / libbpf-rs

Minimal and opinionated eBPF tooling for the Rust ecosystem
Other
788 stars 138 forks source link

segfault related to mismatching libbpf version #987

Closed mat-1 closed 2 weeks ago

mat-1 commented 3 weeks ago

I'm making this issue as reference for anyone else that ran into the same issue since it took me several hours to figure out what was going on, I'm not sure if there's a good solution that this library should take. :sweat_smile:

libbpf-rs currently depends on libbpf-sys 1.4.1, but the Rust dependency resolver just matches 2.0.0 > version >= 1.4.1 for that, so it uses 1.5.0 instead.

libbpf 1.4.x has a struct that looks like:

struct bpf_map_skeleton {
    const char *name;
    struct bpf_map **map;
    void **mmaped;
};

In libbpf 1.5.0 (which released a few days ago), the struct was updated with an additional field:

struct bpf_map_skeleton {
    const char *name;
    struct bpf_map **map;
    void **mmaped;
    struct bpf_link **link;
};

The bpf_map_skeletons are stored in an array. This means if your program has more than one map, and your system is using libbpf 1.4.x, and your libbpf-sys version is 1.5.x, it'll write the 4 fields for each map but then only read 3, resulting in a null dereference when reading the second map's name (since bpf_link is left as a null pointer).

My solution ended up being to force libbpf-sys to version 1.4.1 in the Cargo.toml:

[build-dependencies]
libbpf-sys = { version = "=1.4.1", default-features = false }
mat-1 commented 3 weeks ago

I may have made this issue a bit too early, I realized libbpf-sys does vendor libbpf so the system's libbpf version is irrelevant.

It seems like the actual reason it was linking with libbpf 1.4 instead of 1.5 is because my program also depends on xsk-rs which depends on libxdp-sys which links xdp-tools's version of libbpf which is still 1.4.

danielocfb commented 3 weeks ago

Yeah, vendoring is the default and then there should not be any issue (well, in the usual case). But given that we support usage of the system libbpf, we should see if we can fix the code. I think this is pretty much the libbpf-rs equivalent of https://github.com/libbpf/libbpf/commit/bf7ddbef99d0c1e597c12b8b64ccd0c4d0c70282 on the libbpf side (at least from a quick glance)... :-(

danielocfb commented 2 weeks ago

I no longer believe there is an issue in libbpf-rs. The segfault is happening in libbpf and as per my experimentation it's caused by a lack of https://github.com/libbpf/libbpf/commit/bf7ddbef99d0c1e597c12b8b64ccd0c4d0c70282. Please update your system library to a version that includes this patch. It has been backported to various lower minor versions. There is nothing else we can do.

This is easily reproduced as follows: In `/tmp/libbpf/src`: ``` $ rm -rf build/; mkdir -p build root; CFLAGS=-fPIC BUILD_STATIC_ONLY=y OBJDIR=build DESTDIR=root make install ``` In `libbpf-rs` ```patch --- Cargo.toml +++ Cargo.toml @@ -6,12 +6,12 @@ authors = ["Devasia Thomas "] license = "LGPL-2.1-only OR BSD-2-Clause" [build-dependencies] -libbpf-cargo = { path = "../../libbpf-cargo" } +libbpf-cargo = { path = "../../libbpf-cargo", default-features = false } vmlinux = { version = "0.0", git = "https://github.com/libbpf/vmlinux.h.git", rev = "83a228cf37fc65f2d14e4896a04922b5ee531a94" } [dependencies] anyhow = "1.0.4" -libbpf-rs = { path = "../../libbpf-rs" } +libbpf-rs = { path = "../../libbpf-rs", default-features = false } libc = "0.2" phf = { version = "0.11", features = ["macros"] } plain = "0.2" ``` ``` $ cd examples/capable $ LIBBPF_SYS_LIBRARY_PATH=/tmp/libbpf/src/build cargo run $ sudo ../../target/debug/capable ``` Everything is fine on, say, `libbpf` `1.3.4` branch as long as `libbpf: fix BPF skeleton forward/backward compat handling` is included. Once backed out we see segfault when running `capable`.