8000 Extend build and install by rdna · Pull Request #1 · libbpf/libbpf · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Extend build and install #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 11, 2018
Merged

Conversation

rdna
Copy link
Contributor
@rdna rdna commented Oct 11, 2018

This pull request extends Makefile and add two new UAPI headers to sync.
See individual commits for more details.

rdna added 2 commits October 11, 2018 15:26
Add more UAPI headers from kernel tree since libbpf relies on their
latest versions that may not be present on target system to use in
build.

if_link.h and netlink.h are synced to include/uapi/linux/ from [1]

[1]
https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/tree/tools/include/uapi/linux

Signed-off-by: Andrey Ignatov <rdna@fb.com>
Introduce multiple improvements to Makefile to make the build more
flexible and support install:

* Support overriding CFLAGS by user but keep required flags in place.
  ALL_FLAGS is used in Makefile as recommended in [1].

* Add additional BUILD_SHARED flag to build dynamically linked flavor of
  the library. If the flag is set, -fPIC is also passed to make it
  possible to build .so.

* Support building in a separate directory provided by OBJDIR variable.

* Add multiple install targets. By default the library itself and libbpf
  headers are installed (install target). UAPI headers can be optionally
  installed by user.

* All installation paths, including PREFIX, library and include
  directories can be overridden. UAPI can be made different from include
  directory for libbpf headers. That makes it possible to keep latest
  <linux/bpf.h> in a place that doesn't conflict with the one installed
  e.g. by kernel-headers package and use it in user's build system.

* Support DESTDIR (see [2]).

* Support overriding LDFLAGS.

* Use utilities such as rm directly as recommended in [3].

* Use compiler and related programs (such as ar) via make variables as
  recommended in [3].

* In clean rule remove all possible build artifacts not to rely on passed
  options (e.g. if build was done w/ BUILD_SHARED, but clean w/o it).

* Document new build options in README.

[1] https://www.gnu.org/software/make/manual/html_node/Command-Variables.html#Command-Variables
[2] https://www.gnu.org/prep/standards/html_node/DESTDIR.html
[3] https://www.gnu.org/software/make/manual/html_node/Utilities-in-Makefiles.html#Utilities-in-Makefiles

Signed-off-by: Andrey Ignatov <rdna@fb.com>
@rdna rdna changed the title Extend build install Extend build and install Oct 11, 2018
@yonghong-song yonghong-song merged commit a907cba into libbpf:master Oct 11, 2018
anakryiko pushed a commit to anakryiko/libbpf that referenced this pull request Jul 29, 2019
'channels.max_combined' initialized only on ioctl success and
errno is only valid on ioctl failure.

The code doesn't produce any runtime issues, but makes memory
sanitizers angry:

 Conditional jump or move depends on uninitialised value(s)
    at 0x55C056F: xsk_get_max_queues (xsk.c:336)
    by 0x55C05B2: xsk_create_bpf_maps (xsk.c:354)
    by 0x55C089F: xsk_setup_xdp_prog (xsk.c:447)
    by 0x55C0E57: xsk_socket__create (xsk.c:601)
  Uninitialised value was created by a stack allocation
    at 0x55C04CD: xsk_get_max_queues (xsk.c:318)

Additionally fixed warning on uninitialized bytes in ioctl arguments:

 Syscall param ioctl(SIOCETHTOOL) points to uninitialised byte(s)
    at 0x648D45B: ioctl (in /usr/lib64/libc-2.28.so)
    by 0x55C0546: xsk_get_max_queues (xsk.c:330)
    by 0x55C05B2: xsk_create_bpf_maps (xsk.c:354)
    by 0x55C089F: xsk_setup_xdp_prog (xsk.c:447)
    by 0x55C0E57: xsk_socket__create (xsk.c:601)
  Address 0x1ffefff378 is on thread 1's stack
  in frame libbpf#1, created by xsk_get_max_queues (xsk.c:318)
  Uninitialised value was created by a stack allocation
    at 0x55C04CD: xsk_get_max_queues (xsk.c:318)

CC: Magnus Karlsson <magnus.karlsson@intel.com>
Fixes: 1cad07884239 ("libbpf: add support for using AF_XDP sockets")
Signed-off-by: Ilya Maximets <i.maximets@samsung.com>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
anakryiko pushed a commit that referenced this pull request Jul 29, 2019
'channels.max_combined' initialized only on ioctl success and
errno is only valid on ioctl failure.

The code doesn't produce any runtime issues, but makes memory
sanitizers angry:

 Conditional jump or move depends on uninitialised value(s)
    at 0x55C056F: xsk_get_max_queues (xsk.c:336)
    by 0x55C05B2: xsk_create_bpf_maps (xsk.c:354)
    by 0x55C089F: xsk_setup_xdp_prog (xsk.c:447)
    by 0x55C0E57: xsk_socket__create (xsk.c:601)
  Uninitialised value was created by a stack allocation
    at 0x55C04CD: xsk_get_max_queues (xsk.c:318)

Additionally fixed warning on uninitialized bytes in ioctl arguments:

 Syscall param ioctl(SIOCETHTOOL) points to uninitialised byte(s)
    at 0x648D45B: ioctl (in /usr/lib64/libc-2.28.so)
    by 0x55C0546: xsk_get_max_queues (xsk.c:330)
    by 0x55C05B2: xsk_create_bpf_maps (xsk.c:354)
    by 0x55C089F: xsk_setup_xdp_prog (xsk.c:447)
    by 0x55C0E57: xsk_socket__create (xsk.c:601)
  Address 0x1ffefff378 is on thread 1's stack
  in frame #1, created by xsk_get_max_queues (xsk.c:318)
  Uninitialised value was created by a stack allocation
    at 0x55C04CD: xsk_get_max_queues (xsk.c:318)

CC: Magnus Karlsson <magnus.karlsson@intel.com>
Fixes: 1cad07884239 ("libbpf: add support for using AF_XDP sockets")
Signed-off-by: Ilya Maximets <i.maximets@samsung.com>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
anakryiko added a commit to anakryiko/libbpf that referenced this pull request Apr 30, 2020
As discussed at LPC 2019 ([0]), this patch brings (a quite belated) support
for declarative BTF-defined map-in-map support in libbpf. It allows to define
ARRAY_OF_MAPS and HASH_OF_MAPS BPF maps without any user-space initialization
code involved.

Additionally, it allows to initialize outer map's slots with references to
respective inner maps at load time, also completely declaratively.

Despite a weak type system of C, the way BTF-defined map-in-map definition
works, it's actually quite hard to accidentally initialize outer map with
incompatible inner maps. This being C, of course, it's still possible, but
even that would be caught at load time and error returned with helpful debug
log pointing exactly to the slot that failed to be initialized.

As an example, here's a rather advanced HASH_OF_MAPS declaration and
initialization example, filling slots #0 and libbpf#4 with two inner maps:

  #include <bpf/bpf_helpers.h>

  struct inner_map {
          __uint(type, BPF_MAP_TYPE_ARRAY);
          __uint(max_entries, 1);
          __type(key, int);
          __type(value, int);
  } inner_map1 SEC(".maps"),
    inner_map2 SEC(".maps");

  struct outer_hash {
          __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
          __uint(max_entries, 5);
          __uint(key_size, sizeof(int));
          __array(values, struct inner_map);
  } outer_hash SEC(".maps") = {
          .values = {
                  [0] = &inner_map2,
                  [4] = &inner_map1,
          },
  };

Here's the relevant part of libbpf debug log showing pretty clearly of what's
going on with map-in-map initialization:

  libbpf: .maps relo #0: for 6 value 0 rel.r_offset 96 name 260 ('inner_map1')
  libbpf: .maps relo #0: map 'outer_arr' slot [0] points to map 'inner_map1'
  libbpf: .maps relo libbpf#1: for 7 value 32 rel.r_offset 112 name 249 ('inner_map2')
  libbpf: .maps relo libbpf#1: map 'outer_arr' slot [2] points
8000
 to map 'inner_map2'
  libbpf: .maps relo libbpf#2: for 7 value 32 rel.r_offset 144 name 249 ('inner_map2')
  libbpf: .maps relo libbpf#2: map 'outer_hash' slot [0] points to map 'inner_map2'
  libbpf: .maps relo libbpf#3: for 6 value 0 rel.r_offset 176 name 260 ('inner_map1')
  libbpf: .maps relo libbpf#3: map 'outer_hash' slot [4] points to map 'inner_map1'
  libbpf: map 'inner_map1': created successfully, fd=4
  libbpf: map 'inner_map2': created successfully, fd=5
  libbpf: map 'outer_hash': created successfully, fd=7
  libbpf: map 'outer_hash': slot [0] set to map 'inner_map2' fd=5
  libbpf: map 'outer_hash': slot [4] set to map 'inner_map1' fd=4

Notice from the log above that fd=6 (not logged explicitly) is used for inner
"prototype" map, necessary for creation of outer map. It is destroyed
immediately after outer map is created.

See also included selftest with some extra comments explaining extra details
of usage. Additionally, similar initialization syntax and libbpf functionality
can be used to do initialization of BPF_PROG_ARRAY with references to BPF
sub-programs. This can be done in follow up patches, if there will be a demand
for this.

  [0] https://linuxplumbersconf.org/event/4/contributions/448/

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/bpf/20200429002739.48006-4-andriin@fb.com
anakryiko added a commit to anakryiko/libbpf that referenced this pull request May 1, 2020
As discussed at LPC 2019 ([0]), this patch brings (a quite belated) support
for declarative BTF-defined map-in-map support in libbpf. It allows to define
ARRAY_OF_MAPS and HASH_OF_MAPS BPF maps without any user-space initialization
code involved.

Additionally, it allows to initialize outer map's slots with references to
respective inner maps at load time, also completely declaratively.

Despite a weak type system of C, the way BTF-defined map-in-map definition
works, it's actually quite hard to accidentally initialize outer map with
incompatible inner maps. This being C, of course, it's still possible, but
even that would be caught at load time and error returned with helpful debug
log pointing exactly to the slot that failed to be initialized.

As an example, here's a rather advanced HASH_OF_MAPS declaration and
initialization example, filling slots #0 and libbpf#4 with two inner maps:

  #include <bpf/bpf_helpers.h>

  struct inner_map {
          __uint(type, BPF_MAP_TYPE_ARRAY);
          __uint(max_entries, 1);
          __type(key, int);
          __type(value, int);
  } inner_map1 SEC(".maps"),
    inner_map2 SEC(".maps");

  struct outer_hash {
          __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
          __uint(max_entries, 5);
          __uint(key_size, sizeof(int));
          __array(values, struct inner_map);
  } outer_hash SEC(".maps") = {
          .values = {
                  [0] = &inner_map2,
                  [4] = &inner_map1,
          },
  };

Here's the relevant part of libbpf debug log showing pretty clearly of what's
going on with map-in-map initialization:

  libbpf: .maps relo #0: for 6 value 0 rel.r_offset 96 name 260 ('inner_map1')
  libbpf: .maps relo #0: map 'outer_arr' slot [0] points to map 'inner_map1'
  libbpf: .maps relo libbpf#1: for 7 value 32 rel.r_offset 112 name 249 ('inner_map2')
  libbpf: .maps relo libbpf#1: map 'outer_arr' slot [2] points to map 'inner_map2'
  libbpf: .maps relo libbpf#2: for 7 value 32 rel.r_offset 144 name 249 ('inner_map2')
  libbpf: .maps relo libbpf#2: map 'outer_hash' slot [0] points to map 'inner_map2'
  libbpf: .maps relo libbpf#3: for 6 value 0 rel.r_offset 176 name 260 ('inner_map1')
  libbpf: .maps relo libbpf#3: map 'outer_hash' slot [4] points to map 'inner_map1'
  libbpf: map 'inner_map1': created successfully, fd=4
  libbpf: map 'inner_map2': created successfully, fd=5
  libbpf: map 'outer_hash': created successfully, fd=7
  libbpf: map 'outer_hash': slot [0] set to map 'inner_map2' fd=5
  libbpf: map 'outer_hash': slot [4] set to map 'inner_map1' fd=4

Notice from the log above that fd=6 (not logged explicitly) is used for inner
"prototype" map, necessary for creation of outer map. It is destroyed
immediately after outer map is created.

See also included selftest with some extra comments explaining extra details
of usage. Additionally, similar initialization syntax and libbpf functionality
can be used to do initialization of BPF_PROG_ARRAY with references to BPF
sub-programs. This can be done in follow up patches, if there will be a demand
for this.

  [0] https://linuxplumbersconf.org/event/4/contributions/448/

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/bpf/20200429002739.48006-4-andriin@fb.com
anakryiko added a commit that referenced this pull request May 2, 2020
As discussed at LPC 2019 ([0]), this patch brings (a quite belated) support
for declarative BTF-defined map-in-map support in libbpf. It allows to define
ARRAY_OF_MAPS and HASH_OF_MAPS BPF maps without any user-space initialization
code involved.

Additionally, it allows to initialize outer map's slots with references to
respective inner maps at load time, also completely declaratively.

Despite a weak type system of C, the way BTF-defined map-in-map definition
works, it's actually quite hard to accidentally initialize outer map with
incompatible inner maps. This being C, of course, it's still possible, but
even that would be caught at load time and error returned with helpful debug
log pointing exactly to the slot that failed to be initialized.

As an example, here's a rather advanced HASH_OF_MAPS declaration and
initialization example, filling slots #0 and #4 with two inner maps:

  #include <bpf/bpf_helpers.h>

  struct inner_map {
          __uint(type, BPF_MAP_TYPE_ARRAY);
          __uint(max_entries, 1);
          __type(key, int);
          __type(value, int);
  } inner_map1 SEC(".maps"),
    inner_map2 SEC(".maps");

  struct outer_hash {
          __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
          __uint(max_entries, 5);
          __uint(key_size, sizeof(int));
          __array(values, struct inner_map);
  } outer_hash SEC(".maps") = {
          .values = {
                  [0] = &inner_map2,
                  [4] = &inner_map1,
          },
  };

Here's the relevant part of libbpf debug log showing pretty clearly of what's
going on with map-in-map initialization:

  libbpf: .maps relo #0: for 6 value 0 rel.r_offset 96 name 260 ('inner_map1')
  libbpf: .maps relo #0: map 'outer_arr' slot [0] points to map 'inner_map1'
  libbpf: .maps relo #1: for 7 value 32 rel.r_offset 112 name 249 ('inner_map2')
  libbpf: .maps relo #1: map 'outer_arr' slot [2] points to map 'inner_map2'
  libbpf: .maps relo #2: for 7 value 32 rel.r_offset 144 name 249 ('inner_map2')
  libbpf: .maps relo #2: map 'outer_hash' slot [0] points to map 'inner_map2'
  libbpf: .maps relo #3: for 6 value 0 rel.r_offset 176 name 260 ('inner_map1')
  libbpf: .maps relo #3: map 'outer_hash' slot [4] points to map 'inner_map1'
  libbpf: map 'inner_map1': created successfully, fd=4
  libbpf: map 'inner_map2': created successfully, fd=5
  libbpf: map 'outer_hash': created successfully, fd=7
  libbpf: map 'outer_hash': slot [0] set to map 'inner_map2' fd=5
  libbpf: map 'outer_hash': slot [4] set to map 'inner_map1' fd=4

Notice from the log above that fd=6 (not logged explicitly) is used for inner
"prototype" map, necessary for creation of outer map. It is destroyed
immediately after outer map is created.

See also included selftest with some extra comments explaining extra details
of usage. Additionally, similar initialization syntax and libbpf functionality
can be used to do initialization of BPF_PROG_ARRAY with references to BPF
sub-programs. This can be done in follow up patches, if there will be a demand
for this.

  [0] https://linuxplumbersconf.org/event/4/contributions/448/

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/bpf/20200429002739.48006-4-andriin@fb.com
@SPYFF SPYFF mentioned this pull request Jul 17, 2021
anakryiko pushed a commit that referenced this pull request Jul 19, 2021
Manjaro is a popular and friendly Arch based distro. Recently they also enabled the BTF support: https://forum.manjaro.org/t/co-re-support-in-kernel/46134/19

I can confirm that:
[user@pc ~]$ uname -a
Linux pc 5.12.16-1-MANJARO #1 SMP PREEMPT Sun Jul 11 13:23:34 UTC 2021 x86_64 GNU/Linux
[user@pc ~]$ ls -la /sys/kernel/btf/vmlinux
-r--r--r-- 1 root root 4226769 jul   17 15.27 /sys/kernel/btf/vmlinux
anakryiko pushed a commit that referenced this pull request Apr 11, 2022
Fixes
```
./out/bpf-object-fuzzer: Running 1 inputs 1 time(s) each.
Running: CORPUS/036ff286c13e4590646c7ef59435ec642432da8e
elf_begin.c:232:20: runtime error: member access within misaligned address 0x000001655e71 for type 'Elf64_Shdr', which requires 8 byte alignment
0x000001655e71: note: pointer points here
 00 00 00  7f 45 4c 46 02 02 01 00  00 00 07 fb 00 1d 00 00  6c 69 63 65 42 fb 00 41  00 57 03 00 20
              ^
    #0 0x574d51 in get_shnum /home/libbpf/elfutils/libelf/elf_begin.c:232:20
    #1 0x574d51 in file_read_elf /home/libbpf/elfutils/libelf/elf_begin.c:296:19
    #2 0x569c2c in __libelf_read_mmaped_file /home/libbpf/elfutils/libelf/elf_begin.c:559:14
    #3 0x58e812 in elf_memory /home/libbpf/elfutils/libelf/elf_memory.c:49:10
    #4 0x4905b4 in bpf_object__elf_init /home/libbpf/src/libbpf.c:1255:9
    #5 0x4905b4 in bpf_object_open /home/libbpf/src/libbpf.c:7104:8
    #6 0x49144e in bpf_object__open_mem /home/libbpf/src/libbpf.c:7171:20
    #7 0x483018 in LLVMFuzzerTestOneInput /home/libbpf/fuzz/bpf-object-fuzzer.c:16:8
    #8 0x439389 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/libbpf/out/bpf-object-fuzzer+0x439389)
    #9 0x419e2f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/home/libbpf/out/bpf-object-fuzzer+0x419e2f)
    #10 0x421aee in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/libbpf/out/bpf-object-fuzzer+0x421aee)
    #11 0x410f96 in main (/home/libbpf/out/bpf-object-fuzzer+0x410f96)
    #12 0x7f153e21255f in __libc_start_call_main (/lib64/libc.so.6+0x2d55f)
    #13 0x7f153e21260b in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x2d60b)
    #14 0x410fe4 in _start (/home/libbpf/out/bpf-object-fuzzer+0x410fe4)

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior elf_begin.c:232:20 in
```
and
```
./out/bpf-object-fuzzer: Running 1 inputs 1 time(s) each.
Running: CORPUS/446b578d82c47fe177de6fd675f4cb6bae8d1ea9
elf_begin.c:485:40: runtime error: addition of unsigned offset to 0x000002277e70 overflowed to 0x0000021d7e6f
    #0 0x5748f1 in file_read_elf /home/libbpf/elfutils/libelf/elf_begin.c:485:40
    #1 0x569c2c in __libelf_read_mmaped_file /home/libbpf/elfutils/libelf/elf_begin.c:559:14
    #2 0x58e812 in elf_memory /home/libbpf/elfutils/libelf/elf_memory.c:49:10
    #3 0x4905b4 in bpf_object__elf_init /home/libbpf/src/libbpf.c:1255:9
    #4 0x4905b4 in bpf_object_open /home/libbpf/src/libbpf.c:7104:8
    #5 0x49144e in bpf_object__open_mem /home/libbpf/src/libbpf.c:7171:20
    #6 0x483018 in LLVMFuzzerTestOneInput /home/libbpf/fuzz/bpf-object-fuzzer.c:16:8
    #7 0x439389 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/libbpf/out/bpf-object-fuzzer+0x439389)
    #8 0x419e2f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/home/libbpf/out/bpf-object-fuzzer+0x419e2f)
    #9 0x421aee in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/libbpf/out/bpf-object-fuzzer+0x421aee)
    #10 0x410f96 in main (/home/libbpf/out/bpf-object-fuzzer+0x410f96)
    #11 0x7f753e38255f in __libc_start_call_main (/lib64/libc.so.6+0x2d55f)
    #12 0x7f753e38260b in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x2d60b)
    #13 0x410fe4 in _start (/home/libbpf/out/bpf-object-fuzzer+0x410fe4)

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior elf_begin.c:485:40 in
```
anakryiko pushed a commit to anakryiko/libbpf that referenced this pull request Oct 17, 2022
ASAN reports an use-after-free in btf_dump_name_dups:

ERROR: AddressSanitizer: heap-use-after-free on address 0xffff927006db at pc 0xaaaab5dfb618 bp 0xffffdd89b890 sp 0xffffdd89b928
READ of size 2 at 0xffff927006db thread T0
    #0 0xaaaab5dfb614 in __interceptor_strcmp.part.0 (test_progs+0x21b614)
    libbpf#1 0xaaaab635f144 in str_equal_fn tools/lib/bpf/btf_dump.c:127
    libbpf#2 0xaaaab635e3e0 in hashmap_find_entry tools/lib/bpf/hashmap.c:143
    libbpf#3 0xaaaab635e72c in hashmap__find tools/lib/bpf/hashmap.c:212
    libbpf#4 0xaaaab6362258 in btf_dump_name_dups tools/lib/bpf/btf_dump.c:1525
    libbpf#5 0xaaaab636240c in btf_dump_resolve_name tools/lib/bpf/btf_dump.c:1552
    libbpf#6 0xaaaab6362598 in btf_dump_type_name tools/lib/bpf/btf_dump.c:1567
    libbpf#7 0xaaaab6360b48 in btf_dump_emit_struct_def tools/lib/bpf/btf_dump.c:912
    libbpf#8 0xaaaab6360630 in btf_dump_emit_type tools/lib/bpf/btf_dump.c:798
    libbpf#9 0xaaaab635f720 in btf_dump__dump_type tools/lib/bpf/btf_dump.c:282
    libbpf#10 0xaaaab608523c in test_btf_dump_incremental tools/testing/selftests/bpf/prog_tests/btf_dump.c:236
    libbpf#11 0xaaaab6097530 in test_btf_dump tools/testing/selftests/bpf/prog_tests/btf_dump.c:875
    libbpf#12 0xaaaab6314ed0 in run_one_test tools/testing/selftests/bpf/test_progs.c:1062
    libbpf#13 0xaaaab631a0a8 in main tools/testing/selftests/bpf/test_progs.c:1697
    libbpf#14 0xffff9676d214 in __libc_start_main ../csu/libc-start.c:308
    libbpf#15 0xaaaab5d65990  (test_progs+0x185990)

0xffff927006db is located 11 bytes inside of 16-byte region [0xffff927006d0,0xffff927006e0)
freed by thread T0 here:
    #0 0xaaaab5e2c7c4 in realloc (test_progs+0x24c7c4)
    libbpf#1 0xaaaab634f4a0 in libbpf_reallocarray tools/lib/bpf/libbpf_internal.h:191
    libbpf#2 0xaaaab634f840 in libbpf_add_mem tools/lib/bpf/btf.c:163
    libbpf#3 0xaaaab636643c in strset_add_str_mem tools/lib/bpf/strset.c:106
    libbpf#4 0xaaaab6366560 in strset__add_str tools/lib/bpf/strset.c:157
    libbpf#5 0xaaaab6352d70 in btf__add_str tools/lib/bpf/btf.c:1519
    libbpf#6 0xaaaab6353e10 in btf__add_field tools/lib/bpf/btf.c:2032
    libbpf#7 0xaaaab6084fcc in test_btf_dump_incremental tools/testing/selftests/bpf/prog_tests/btf_dump.c:232
    libbpf#8 0xaaaab6097530 in test_btf_dump tools/testing/selftests/bpf/prog_tests/btf_dump.c:875
    libbpf#9 0xaaaab6314ed0 in run_one_test tools/testing/selftests/bpf/test_progs.c:1062
    libbpf#10 0xaaaab631a0a8 in main tools/testing/selftests/bpf/test_progs.c:1697
    libbpf#11 0xffff9676d214 in __libc_start_main ../csu/libc-start.c:308
    libbpf#12 0xaaaab5d65990  (test_progs+0x185990)

previously allocated by thread T0 here:
    #0 0xaaaab5e2c7c4 in realloc (test_progs+0x24c7c4)
    libbpf#1 0xaaaab634f4a0 in libbpf_reallocarray tools/lib/bpf/libbpf_internal.h:191
    libbpf#2 0xaaaab634f840 in libbpf_add_mem tools/lib/bpf/btf.c:163
    libbpf#3 0xaaaab636643c in strset_add_str_mem tools/lib/bpf/strset.c:106
    libbpf#4 0xaaaab6366560 in strset__add_str tools/lib/bpf/strset.c:157
    libbpf#5 0xaaaab6352d70 in btf__add_str tools/lib/bpf/btf.c:1519
    libbpf#6 0xaaaab6353ff0 in btf_add_enum_common tools/lib/bpf/btf.c:2070
    libbpf#7 0xaaaab6354080 in btf__add_enum tools/lib/bpf/btf.c:2102
    libbpf#8 0xaaaab6082f50 in test_btf_dump_incremental tools/testing/selftests/bpf/prog_tests/btf_dump.c:162
    libbpf#9 0xaaaab6097530 in test_btf_dump tools/testing/selftests/bpf/prog_tests/btf_dump.c:875
    libbpf#10 0xaaaab6314ed0 in run_one_test tools/testing/selftests/bpf/test_progs.c:1062
    libbpf#11 0xaaaab631a0a8 in main tools/testing/selftests/bpf/test_progs.c:1697
    libbpf#12 0xffff9676d214 in __libc_start_main ../csu/libc-start.c:308
    libbpf#13 0xaaaab5d65990  (test_progs+0x185990)

The reason is that the key stored in hash table name_map is a string
address, and the string memory is allocated by realloc() function, when
the memory is resized by realloc() later, the old memory may be freed,
so the address stored in name_map references to a freed memory, causing
use-after-free.

Fix it by storing duplicated string address in name_map.

Fixes: 919d2b1dbb07 ("libbpf: Allow modification of BTF and add btf__add_str API")
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://lore.kernel.org/bpf/20221011120108.782373-2-xukuohai@huaweicloud.com
anakryiko pushed a commit to anakryiko/libbpf that referenced this pull request Oct 17, 2022
This commit replace e_shnum with the elf_getshdrnum() helper to fix two
oss-fuzz-reported heap-buffer overflow in __bpf_object__open. Both
reports are incorrectly marked as fixed and while still being
reproducible in the latest libbpf.

  # clusterfuzz-testcase-minimized-bpf-object-fuzzer-5747922482888704
  libbpf: loading object 'fuzz-object' from buffer
  libbpf: sec_cnt is 0
  libbpf: elf: section(1) .data, size 0, link 538976288, flags 2020202020202020, type=2
  libbpf: elf: section(2) .data, size 32, link 538976288, flags 202020202020ff20, type=1
  =================================================================
  ==13==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000000c0 at pc 0x0000005a7b46 bp 0x7ffd12214af0 sp 0x7ffd12214ae8
  WRITE of size 4 at 0x6020000000c0 thread T0
  SCARINESS: 46 (4-byte-write-heap-buffer-overflow-far-from-bounds)
      #0 0x5a7b45 in bpf_object__elf_collect /src/libbpf/src/libbpf.c:3414:24
      libbpf#1 0x5733c0 in bpf_object_open /src/libbpf/src/libbpf.c:7223:16
      libbpf#2 0x5739fd in bpf_object__open_mem /src/libbpf/src/libbpf.c:7263:20
      ...

The issue lie in libbpf's direct use of e_shnum field in ELF header as
the section header count. Where as libelf implemented an extra logic
that, when e_shnum == 0 && e_shoff != 0, will use sh_size member of the
initial section header as the real section header count (part of ELF
spec to accommodate situation where section header counter is larger
than SHN_LORESERVE).

The above inconsistency lead to libbpf writing into a zero-entry calloc
area. So intead of using e_shnum directly, use the elf_getshdrnum()
helper provided by libelf to retrieve the section header counter into
sec_cnt.

Fixes: 0d6988e16a12 ("libbpf: Fix section counting logic")
Fixes: 25bbbd7a444b ("libbpf: Remove assumptions about uniqueness of .rodata/.data/.bss maps")
Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=40868
Link: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=40957
Link: https://lore.kernel.org/bpf/20221012022353.7350-2-shung-hsi.yu@suse.com
anakryiko pushed a commit that referenced this pull request Oct 17, 2022
ASAN reports an use-after-free in btf_dump_name_dups:

ERROR: AddressSanitizer: heap-use-after-free on address 0xffff927006db at pc 0xaaaab5dfb618 bp 0xffffdd89b890 sp 0xffffdd89b928
READ of size 2 at 0xffff927006db thread T0
    #0 0xaaaab5dfb614 in __interceptor_strcmp.part.0 (test_progs+0x21b614)
    #1 0xaaaab635f144 in str_equal_fn tools/lib/bpf/btf_dump.c:127
    #2 0xaaaab635e3e0 in hashmap_find_entry tools/lib/bpf/hashmap.c:143
    #3 0xaaaab635e72c in hashmap__find tools/lib/bpf/hashmap.c:212
    #4 0xaaaab6362258 in btf_dump_name_dups tools/lib/bpf/btf_dump.c:1525
    #5 0xaaaab636240c in btf_dump_resolve_name tools/lib/bpf/btf_dump.c:1552
    #6 0xaaaab6362598 in btf_dump_type_name tools/lib/bpf/btf_dump.c:1567
    #7 0xaaaab6360b48 in btf_dump_emit_struct_def tools/lib/bpf/btf_dump.c:912
    #8 0xaaaab6360630 in btf_dump_emit_type tools/lib/bpf/btf_dump.c:798
    #9 0xaaaab635f720 in btf_dump__dump_type tools/lib/bpf/btf_dump.c:282
    #10 0xaaaab608523c in test_btf_dump_incremental tools/testing/selftests/bpf/prog_tests/btf_dump.c:236
    #11 0xaaaab6097530 in test_btf_dump tools/testing/selftests/bpf/prog_tests/btf_dump.c:875
    #12 0xaaaab6314ed0 in run_one_test tools/testing/selftests/bpf/test_progs.c:1062
    #13 0xaaaab631a0a8 in main tools/testing/selftests/bpf/test_progs.c:1697
    #14 0xffff9676d214 in __libc_start_main ../csu/libc-start.c:308
    #15 0xaaaab5d65990  (test_progs+0x185990)

0xffff927006db is located 11 bytes inside of 16-byte region [0xffff927006d0,0xffff927006e0)
freed by thread T0 here:
    #0 0xaaaab5e2c7c4 in realloc (test_progs+0x24c7c4)
    #1 0xaaaab634f4a0 in libbpf_reallocarray tools/lib/bpf/libbpf_internal.h:191
    #2 0xaaaab634f840 in libbpf_add_mem tools/lib/bpf/btf.c:163
    #3 0xaaaab636643c in strset_add_str_mem tools/lib/bpf/strset.c:106
    #4 0xaaaab6366560 in strset__add_str tools/lib/bpf/strset.c:157
    #5 0xaaaab6352d70 in btf__add_str tools/lib/bpf/btf.c:1519
    #6 0xaaaab6353e10 in btf__add_field tools/lib/bpf/btf.c:2032
    #7 0xaaaab6084fcc in test_btf_dump_incremental tools/testing/selftests/bpf/prog_tests/btf_dump.c:232
    #8 0xaaaab6097530 in test_btf_dump tools/testing/selftests/bpf/prog_tests/btf_dump.c:875
    #9 0xaaaab6314ed0 in run_one_test tools/testing/selftests/bpf/test_progs.c:1062
    #10 0xaaaab631a0a8 in main tools/testing/selftests/bpf/test_progs.c:1697
    #11 0xffff9676d214 in __libc_start_main ../csu/libc-start.c:308
    #12 0xaaaab5d65990  (test_progs+0x185990)

previously allocated by thread T0 here:
    #0 0xaaaab5e2c7c4 in realloc (test_progs+0x24c7c4)
    #1 0xaaaab634f4a0 in libbpf_reallocarray tools/lib/bpf/libbpf_internal.h:191
    #2 0xaaaab634f840 in libbpf_add_mem tools/lib/bpf/btf.c:163
    #3 0xaaaab636643c in strset_add_str_mem tools/lib/bpf/strset.c:106
    #4 0xaaaab6366560 in strset__add_str tools/lib/bpf/strset.c:157
    #5 0xaaaab6352d70 in btf__add_str tools/lib/bpf/btf.c:1519
    #6 0xaaaab6353ff0 in btf_add_enum_common tools/lib/bpf/btf.c:2070
    #7 0xaaaab6354080 in btf__add_enum tools/lib/bpf/btf.c:2102
    #8 0xaaaab6082f50 in test_btf_dump_incremental tools/testing/selftests/bpf/prog_tests/btf_dump.c:162
    #9 0xaaaab6097530 in test_btf_dump tools/testing/selftests/bpf/prog_tests/btf_dump.c:875
    #10 0xaaaab6314ed0 in run_one_test tools/testing/selftests/bpf/test_progs.c:1062
    #11 0xaaaab631a0a8 in main tools/testing/selftests/bpf/test_progs.c:1697
    #12 0xffff9676d214 in __libc_start_main ../csu/libc-start.c:308
    #13 0xaaaab5d65990  (test_progs+0x185990)

The reason is that the key stored in hash table name_map is a string
address, and the string memory is allocated by realloc() function, when
the memory is resized by realloc() later, the old memory may be freed,
so the address stored in name_map references to a freed memory, causing
use-after-free.

Fix it by storing duplicated string address in name_map.

Fixes: 919d2b1dbb07 ("libbpf: Allow modification of BTF and add btf__add_str API")
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://lore.kernel.org/bpf/20221011120108.782373-2-xukuohai@huaweicloud.com
anakryiko pushed a commit that referenced this pull request Oct 17, 2022
This commit replace e_shnum with the elf_getshdrnum() helper to fix two
oss-fuzz-reported heap-buffer overflow in __bpf_object__open. Both
reports are incorrectly marked as fixed and while still being
reproducible in the latest libbpf.

  # clusterfuzz-testcase-minimized-bpf-object-fuzzer-5747922482888704
  libbpf: loading object 'fuzz-object' from buffer
  libbpf: sec_cnt is 0
  libbpf: elf: section(1) .data, size 0, link 538976288, flags 2020202020202020, type=2
  libbpf: elf: section(2) .data, size 32, link 538976288, flags 202020202020ff20, type=1
  =================================================================
  ==13==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000000c0 at pc 0x0000005a7b46 bp 0x7ffd12214af0 sp 0x7ffd12214ae8
  WRITE of size 4 at 0x6020000000c0 thread T0
  SCARINESS: 46 (4-byte-write-heap-buffer-overflow-far-from-bounds)
      #0 0x5a7b45 in bpf_object__elf_collect /src/libbpf/src/libbpf.c:3414:24
      #1 0x5733c0 in bpf_object_open /src/libbpf/src/libbpf.c:7223:16
      #2 0x5739fd in bpf_object__open_mem /src/libbpf/src/libbpf.c:7263:20
      ...

The issue lie in libbpf's direct use of e_shnum field in ELF header as
the section header count. Where as libelf implemented an extra logic
that, when e_shnum == 0 && e_shoff != 0, will use sh_size member of the
initial section header as the real section header count (part of ELF
spec to accommodate situation where section header counter is larger
than SHN_LORESERVE).

The above inconsistency lead to libbpf writing into a zero-entry calloc
area. So intead of using e_shnum directly, use the elf_getshdrnum()
helper provided by libelf to retrieve the section header counter into
sec_cnt.

Fixes: 0d6988e16a12 ("libbpf: Fix section counting logic")
Fixes: 25bbbd7a444b ("libbpf: Remove assumptions about uniqueness of .rodata/.data/.bss maps")
Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=40868
Link: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=40957
Link: https://lore.kernel.org/bpf/20221012022353.7350-2-shung-hsi.yu@suse.com
anakryiko pushed a commit to anakryiko/libbpf that referenced this pull request Nov 12, 2022
Changes de-duplication logic for enums in the following way:
- update btf_hash_enum to ignore size and kind fields to get
  ENUM and ENUM64 types in a same hash bucket;
- update btf_compat_enum to consider enum fwd to be compatible with
  full enum64 (and vice versa);

This allows BTF de-duplication in the following case:

    // CU libbpf#1
    enum foo;

    struct s {
      enum foo *a;
    } *x;

    // CU libbpf#2
    enum foo {
      x = 0xfffffffff // big enough to force enum64
    };

    struct s {
      enum foo *a;
    } *y;

De-duplicated BTF prior to this commit:

    [1] ENUM64 'foo' encoding=UNSIGNED size=8 vlen=1
    	'x' val=68719476735ULL
    [2] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64
        encoding=(none)
    [3] STRUCT 's' size=8 vlen=1
    	'a' type_id=4 bits_offset=0
    [4] PTR '(anon)' type_id=1
    [5] PTR '(anon)' type_id=3
    [6] STRUCT 's' size=8 vlen=1
    	'a' type_id=8 bits_offset=0
    [7] ENUM 'foo' encoding=UNSIGNED size=4 vlen=0
    [8] PTR '(anon)' type_id=7
    [9] PTR '(anon)' type_id=6

De-duplicated BTF after this commit:

    [1] ENUM64 'foo' encoding=UNSIGNED size=8 vlen=1
    	'x' val=68719476735ULL
    [2] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64
        encoding=(none)
    [3] STRUCT 's' size=8 vlen=1
    	'a' type_id=4 bits_offset=0
    [4] PTR '(anon)' type_id=1
    [5] PTR '(anon)' type_id=3

Enum forward declarations in C do not provide information about
enumeration values range. Thus the `btf_type->size` field is
meaningless for forward enum declarations. In fact, GCC does not
encode size in DWARF for forward enum declarations
(but dwarves sets enumeration size to a default value of `sizeof(int) * 8`
when size is not specified see dwarf_loader.c:die__create_new_enumeration).

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20221101235413.1824260-1-eddyz87@gmail.com
anakryiko pushed a commit to anakryiko/libbpf that referenced this pull request Nov 12, 2022
Resolve forward declarations that don't take part in type graphs
comparisons if declaration name is unambiguous. Example:

CU libbpf#1:

struct foo;              // standalone forward declaration
struct foo *some_global;

CU libbpf#2:

struct foo { int x; };
struct foo *another_global;

The `struct foo` from CU libbpf#1 is not a part of any definition that is
compared against another definition while `btf_dedup_struct_types`
processes structural types. The the BTF after `btf_dedup_struct_types`
the BTF looks as follows:

[1] STRUCT 'foo' size=4 vlen=1 ...
[2] INT 'int' size=4 ...
[3] PTR '(anon)' type_id=1
[4] FWD 'foo' fwd_kind=struct
[5] PTR '(anon)' type_id=4

This commit adds a new pass `btf_dedup_resolve_fwds`, that maps such
forward declarations to structs or unions with identical name in case
if the name is not ambiguous.

The pass is positioned before `btf_dedup_ref_types` so that types
[3] and [5] could be merged as a same type after [1] and [4] are merged.
The final result for the example above looks as follows:

[1] STRUCT 'foo' size=4 vlen=1
	'x' type_id=2 bits_offset=0
[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
[3] PTR '(anon)' type_id=1

For defconfig kernel with BTF enabled this removes 63 forward
declarations. Examples of removed declarations: `pt_regs`, `in6_addr`.
The running time of `btf__dedup` function is increased by about 3%.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Alan Maguire <alan.maguire@oracle.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20221109142611.879983-3-eddyz87@gmail.com
anakryiko pushed a commit that referenced this pull request Nov 13, 2022
Changes de-duplication logic for enums in the following way:
- update btf_hash_enum to ignore size and kind fields to get
  ENUM and ENUM64 types in a same hash bucket;
- update btf_compat_enum to consider enum fwd to be compatible with
  full enum64 (and vice versa);

This allows BTF de-duplication in the following case:

    // CU #1
    enum foo;

    struct s {
      enum foo *a;
    } *x;

    // CU #2
    enum foo {
      x = 0xfffffffff // big enough to force enum64
    };

    struct s {
      enum foo *a;
    } *y;

De-duplicated BTF prior to this commit:

    [1] ENUM64 'foo' encoding=UNSIGNED size=8 vlen=1
    	'x' val=68719476735ULL
    [2] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64
        encoding=(none)
    [3] STRUCT 's' size=8 vlen=1
    	'a' type_id=4 bits_offset=0
    [4] PTR '(anon)' type_id=1
    [5] PTR '(anon)' type_id=3
    [6] STRUCT 's' size=8 vlen=1
    	'a' type_id=8 bits_offset=0
    [7] ENUM 'foo' encoding=UNSIGNED size=4 vlen=0
    [8] PTR '(anon)' type_id=7
    [9] PTR '(anon)' type_id=6

De-duplicated BTF after this commit:

    [1] ENUM64 'foo' encoding=UNSIGNED size=8 vlen=1
    	'x' val=68719476735ULL
    [2] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64
        encoding=(none)
    [3] STRUCT 's' size=8 vlen=1
    	'a' type_id=4 bits_offset=0
    [4] PTR '(anon)' type_id=1
    [5] PTR '(anon)' type_id=3

Enum forward declarations in C do not provide information about
enumeration values range. Thus the `btf_type->size` field is
meaningless for forward enum declarations. In fact, GCC does not
encode size in DWARF for forward enum declarations
(but dwarves sets enumeration size to a default value of `sizeof(int) * 8`
when size is not specified see dwarf_loader.c:die__create_new_enumeration).

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20221101235413.1824260-1-eddyz87@gmail.com
anakryiko pushed a commit that referenced this pull request Nov 13, 2022
Resolve forward declarations that don't take part in type graphs
comparisons if declaration name is unambiguous. Example:

CU #1:

struct foo;              // standalone forward declaration
struct foo *some_global;

CU #2:

struct foo { int x; };
struct foo *another_global;

The `struct foo` from CU #1 is not a part of any definition that is
compared against another definition while `btf_dedup_struct_types`
processes structural types. The the BTF after `btf_dedup_struct_types`
the BTF looks as follows:

[1] STRUCT 'foo' size=4 vlen=1 ...
[2] INT 'int' size=4 ...
[3] PTR '(anon)' type_id=1
[4] FWD 'foo' fwd_kind=struct
[5] PTR '(anon)' type_id=4

This commit adds a new pass `btf_dedup_resolve_fwds`, that maps such
forward declarations to structs or unions with identical name in case
if the name is not ambiguous.

The pass is positioned before `btf_dedup_ref_types` so that types
[3] and [5] could be merged as a same type after [1] and [4] are merged.
The final result for the example above looks as follows:

[1] STRUCT 'foo' size=4 vlen=1
	'x' type_id=2 bits_offset=0
[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
[3] PTR '(anon)' type_id=1

For defconfig kernel with BTF enabled this removes 63 forward
declarations. Examples of removed declarations: `pt_regs`, `in6_addr`.
The running time of `btf__dedup` function is increased by about 3%.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Alan Maguire <alan.maguire@oracle.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20221109142611.879983-3-eddyz87@gmail.com
danielocfb pushed a commit to danielocfb/libbpf that referenced this pull request Feb 15, 2023
Original change: undetermined

Change-Id: I3f62f7ef96da39fc475dc357ce8e024b1a247aa3
danielocfb pushed a commit to danielocfb/libbpf that referenced this pull request Feb 15, 2023
…am: 8c3c43a

Original change: undetermined

Change-Id: I938a4f969c3b1a2939515def5e55f9dfe65166fb
danielocfb pushed a commit to danielocfb/libbpf that referenced this pull request Feb 15, 2023
< 6D47 a title="Merge pull request #1 from rdna/extend-build-install am: a907cbaee9 am: 8c3c43a0de am: 539a60d840 Original change: undetermined Change-Id: I4c7180d5d4bbafd536d352a3efa958ab150a587b" data-pjax="true" class="Link--secondary markdown-title" href="/danielocfb/libbpf/commit/9f6ed5db46be4c5377a257e4aeee69e0d1e31814">Merge pull request libbpf#1 from rdna/extend-build-install am: a907cba
…am: 8c3c43a am: 539a60d

Original change: undetermined

Change-Id: I4c7180d5d4bbafd536d352a3efa958ab150a587b
danielocfb pushed a commit to danielocfb/libbpf that referenced this pull request Feb 15, 2023
Summary:
Main reason to port this version was to being able to run
ebpf libbpf-based programs without the need of CONFIG_DEBUG_FS.

Rather than just backporting that patch, I decided to backport
the whole version. Probably some stuff will not work because we
lack the kernel patches, but we can backport them as needed.

More info at https://github.com/libbpf/libbpf/releases/tag/v1.0.0

Test Plan:
    $ m libbpf bpftool bpftool_boostrap
    $ ls -lrho out/target/product/hollywood/system/bin/bpftool
    -rwxr-xr-x. 1 salvabenedetto 406K Dec 18 11:00
    $ adb push out/target/product/hollywood/system/bin/bpftool /data/
    out/target/product/hollywood/system/bin/bpftool: 1 file pushed, 0 skipped. 141.0 MB/s (414920 bytes in 0.003s)
    $ adb shell /data/bpftool --version
    /data/bpftool v7.0.0
    using libbpf v1.0
    features: libbpf_strict, skeletons
    (/ )

bpftool_bootstrap skeleton feature was tested with the first
ebpf program based on libbpf which will be published later, but before
the error was

    libbpf: failed to open '/sys/kernel/debug/tracing/events/binder/binder_ioctl/id': No such file or directory
    libbpf: failed to determine tracepoint 'binder/binder_ioctl' perf event ID: No such file or directory
    libbpf: prog 'handle_binder_ioctl': failed to create tracepoint 'binder/binder_ioctl' perf event: No such file or director

This is because we don't have CONFIG_DEBUG_FS

    $ adb shell zcat /proc/config.gz | rg DEBUG_FS
    # CONFIG_DEBUG_FS is not set

but we do have TRACE_FS

    $ adb shell cat /sys/kernel/tracing/events/binder/binder_ioctl/id
    1408

With this version of libbpf, we can now use trapoints with only TRACE_FS in the system

```
$ adb shell /data/binderioctl
libbpf: loading object 'binderioctl' from buffer
libbpf: elf: section(3) tp/binder/binder_ioctl, size 344, link 0, flags 6, type=1
libbpf: sec 'tp/binder/binder_ioctl': found program 'handle_binder_ioctl' at insn offset 0 (0 bytes), code size 43 insns (344 bytes)
libbpf: elf: section(4) .reltp/binder/binder_ioctl, size 48, link 26, flags 0, type=9
libbpf: elf: section(5) tp/binder/binder_ioctl_done, size 392, link 0, flags 6, type=1
libbpf: sec 'tp/binder/binder_ioctl_done': found program 'handle_binder_ioctl_done' at insn offset 0 (0 bytes), code size 49 insns (392 bytes)
libbpf: elf: section(6) .reltp/binder/binder_ioctl_done, size 64, link 26, flags 0, type=9
libbpf: elf: section(7) .maps, size 120, link 0, flags 3, type=1
libbpf: elf: section(8) license, size 13, link 0, flags 3, type=1
libbpf: license of binderioctl is Dual BSD/GPL
libbpf: elf: section(17) .BTF, size 2634, link 0, flags 0, type=1
libbpf: elf: section(19) .BTF.ext, size 808, link 0, flags 0, type=1
libbpf: elf: section(26) .symtab, size 456, link 1, flags 0, type=2
libbpf: looking for externs among 19 symbols...
libbpf: collected 0 externs total
libbpf: map 'bindcalls': at sec_idx 7, offset 0.
libbpf: map 'bindcalls': found type = 1.
libbpf: map 'bindcalls': found key [8], sz = 4.
libbpf: map 'bindcalls': found value [11], sz = 8.
libbpf: map 'bindcalls': found max_entries = 102400.
libbpf: map 'transactions_per_tid': at sec_idx 7, offset 32.
libbpf: map 'transactions_per_tid': found type = 1.
libbpf: map 'transactions_per_tid': found key [17], sz = 20.
libbpf: map 'transactions_per_tid': found value [11], sz = 8.
libbpf: map 'transactions_per_tid': found max_entries = 102400.
libbpf: map 'heap': at sec_idx 7, offset 64.
libbpf: map 'heap': found type = 6.
libbpf: map 'heap': found key [2], sz = 4.
libbpf: map 'heap': found value [26], sz = 32.
libbpf: map 'heap': found max_entries = 1.
libbpf: map 'pb': at sec_idx 7, offset 96.
libbpf: map 'pb': found type = 4.
libbpf: map 'pb': found key_size = 4.
libbpf: map 'pb': found value_size = 4.
libbpf: sec '.reltp/binder/binder_ioctl': collecting relocation for section(3) 'tp/binder/binder_ioctl'
libbpf: sec '.reltp/binder/binder_ioctl': relo #0: insn libbpf#9 against 'bindcalls'
libbpf: prog 'handle_binder_ioctl': found map 0 (bindcalls, sec 7, off 0) for insn libbpf#9
libbpf: sec '.reltp/binder/binder_ioctl': relo libbpf#1: insn libbpf#25 against 'transactions_per_tid'
libbpf: prog 'handle_binder_ioctl': found map 1 (transactions_per_tid, sec 7, off 32) for insn libbpf#25
libbpf: sec '.reltp/binder/binder_ioctl': relo libbpf#2: insn libbpf#37 against 'transactions_per_tid'
libbpf: prog 'handle_binder_ioctl': found map 1 (transactions_per_tid, sec 7, off 32) for insn libbpf#37
libbpf: sec '.reltp/binder/binder_ioctl_done': collecting relocation for section(5) 'tp/binder/binder_ioctl_done'
libbpf: sec '.reltp/binder/binder_ioctl_done': relo #0: insn libbpf#5 against 'bindcalls'
libbpf: prog 'handle_binder_ioctl_done': found map 0 (bindcalls, sec 7, off 0) for insn libbpf#5
libbpf: sec '.reltp/binder/binder_ioctl_done': relo libbpf#1: insn libbpf#15 against 'bindcalls'
libbpf: prog 'handle_binder_ioctl_done': found map 0 (bindcalls, sec 7, off 0) for insn libbpf#15
libbpf: sec '.reltp/binder/binder_ioctl_done': relo libbpf#2: insn libbpf#25 against 'heap'
libbpf: prog 'handle_binder_ioctl_done': found map 2 (heap, sec 7, off 64) for insn libbpf#25
libbpf: sec '.reltp/binder/binder_ioctl_done': relo libbpf#3: insn libbpf#40 against 'pb'
libbpf: prog 'handle_binder_ioctl_done': found map 3 (pb, sec 7, off 96) for insn libbpf#40
libbpf: map 'bindcalls': created successfully, fd=4
libbpf: map 'transactions_per_tid': created successfully, fd=5
libbpf: map 'heap': created successfully, fd=6
libbpf: map 'pb': setting size to 8
libbpf: map 'pb': created successfully, fd=7
[814][surfaceflinger] binderioctl code 0 took 1 ms
[2111][Binder:2088_1] binderioctl code 0 took 2 ms
```

Reviewers: simsun, andriin, #ebpf_rl

Reviewed By: simsun

Subscribers: lguan, jiacan

Differential Revision: https://phabricator.intern.facebook.com/D42129427

Tasks: T140464111

Tags: accept2ship, dwt_test_infra_missing
liu-song-6 pushed a commit to liu-song-6/libbpf that referenced this pull request Feb 16, 2023
In a previous commit, Ubuntu kernel code version is correctly set
by retrieving the information from /proc/version_signature.

commit<5b3d72987701d51bf31823b39db49d10970f5c2d>
(libbpf: Improve LINUX_VERSION_CODE detection)

The /proc/version_signature file doesn't present in at least the
older versions of Debian distributions (eg, Debian 9, 10). The Debian
kernel has a similar issue where the release information from uname()
syscall doesn't give the kernel code version that matches what the
kernel actually expects. Below is an example content from Debian 10.

release: 4.19.0-23-amd64
version: libbpf#1 SMP Debian 4.19.269-1 (2022-12-20) x86_64

Debian reports incorrect kernel version in utsname::release returned
by uname() syscall, which in older kernels (Debian 9, 10) leads to
kprobe BPF programs failing to load due to the version check mismatch.

Fortunately, the correct kernel code version presents in the
utsname::version returned by uname() syscall in Debian kernels. This
change adds another get kernel version function to handle Debian in
addition to the previously added get kernel version function to handle
Ubuntu. Some minor refactoring work is also done to make the code more
readable.

Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
Signed-off-by: Ho-Ren (Jack) Chuang <horenchuang@bytedance.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20230203234842.2933903-1-hao.xiang@bytedance.com
anakryiko pushed a commit that referenced this pull request Feb 18, 2023
In a previous commit, Ubuntu kernel code version is correctly set
by retrieving the information from /proc/version_signature.

commit<5b3d72987701d51bf31823b39db49d10970f5c2d>
(libbpf: Improve LINUX_VERSION_CODE detection)

The /proc/version_signature file doesn't present in at least the
older versions of Debian distributions (eg, Debian 9, 10). The Debian
kernel has a similar issue where the release information from uname()
syscall doesn't give the kernel code version that matches what the
kernel actually expects. Below is an example content from Debian 10.

release: 4.19.0-23-amd64
version: #1 SMP Debian 4.19.269-1 (2022-12-20) x86_64

Debian reports incorrect kernel version in utsname::release returned
by uname() syscall, which in older kernels (Debian 9, 10) leads to
kprobe BPF programs failing to load due to the version check mismatch.

Fortunately, the correct kernel code version presents in the
utsname::version returned by uname() syscall in Debian kernels. This
change adds another get kernel version function to handle Debian in
addition to the previously added get kernel version function to handle
Ubuntu. Some minor refactoring work is also done to make the code more
readable.

Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
Signed-off-by: Ho-Ren (Jack) Chuang <horenchuang@bytedance.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20230203234842.2933903-1-hao.xiang@bytedance.com
Byte-Lab pushed a commit to Byte-Lab/libbpf that referenced this pull request Mar 11, 2023
Parsing of USDT arguments is architecture-specific; on arm it is
relatively easy since registers used are r[0-10], fp, ip, sp, lr,
pc. Format is slightly different compared to aarch64; forms are

- "size @ [ reg, #offset ]" for dereferences, for example
  "-8 @ [ sp, libbpf#76 ]" ; " -4 @ [ sp ]"
- "size @ reg" for register values; for example
  "-4@r0"
- "size @ #value" for raw values; for example
  "-8@libbpf#1"

Add support for parsing USDT arguments for ARM architecture.

To test the above changes QEMU's virt[1] board with cortex-a15
CPU was used. libbpf-bootstrap's usdt example[2] was modified to attach
to a test program with DTRACE_PROBE1/2/3/4... probes to test different
combinations.

[1] https://www.qemu.org/docs/master/system/arm/virt.html
[2] https://github.com/libbpf/libbpf-bootstrap/blob/master/examples/c/usdt.bpf.c

Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20230307120440.25941-3-puranjay12@gmail.com
anakryiko pushed a commit that referenced this pull request Mar 15, 2023
Parsing of USDT arguments is architecture-specific; on arm it is
relatively easy since registers used are r[0-10], fp, ip, sp, lr,
pc. Format is slightly different compared to aarch64; forms are

- "size @ [ reg, #offset ]" for dereferences, for example
  "-8 @ [ sp, #76 ]" ; " -4 @ [ sp ]"
- "size @ reg" for register values; for example
  "-4@r0"
- "size @ #value" for raw values; for example
  "-8@#1"

Add support for parsing USDT arguments for ARM architecture.

To test the above changes QEMU's virt[1] board with cortex-a15
CPU was used. libbpf-bootstrap's usdt example[2] was modified to attach
to a test program with DTRACE_PROBE1/2/3/4... probes to test different
combinations.

[1] https://www.qemu.org/docs/master/system/arm/virt.html
[2] https://github.com/libbpf/libbpf-bootstrap/blob/master/examples/c/usdt.bpf.c

Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20230307120440.25941-3-puranjay12@gmail.com
@ffashion ffashion mentioned this pull request May 19, 2023
anakryiko pushed a commit to anakryiko/libbpf that referenced this pull request Jan 4, 2024
An issue occurred while reading an ELF file in libbpf.c during fuzzing:

	Program received signal SIGSEGV, Segmentation fault.
	0x0000000000958e97 in bpf_object.collect_prog_relos () at libbpf.c:4206
	4206 in libbpf.c
	(gdb) bt
	#0 0x0000000000958e97 in bpf_object.collect_prog_relos () at libbpf.c:4206
	libbpf#1 0x000000000094f9d6 in bpf_object.collect_relos () at libbpf.c:6706
	libbpf#2 0x000000000092bef3 in bpf_object_open () at libbpf.c:7437
	libbpf#3 0x000000000092c046 in bpf_object.open_mem () at libbpf.c:7497
	libbpf#4 0x0000000000924afa in LLVMFuzzerTestOneInput () at fuzz/bpf-object-fuzzer.c:16
	libbpf#5 0x000000000060be11 in testblitz_engine::fuzzer::Fuzzer::run_one ()
	libbpf#6 0x000000000087ad92 in tracing::span::Span::in_scope ()
	libbpf#7 0x00000000006078aa in testblitz_engine::fuzzer::util::walkdir ()
	libbpf#8 0x00000000005f3217 in testblitz_engine::entrypoint::main::{{closure}} ()
	libbpf#9 0x00000000005f2601 in main ()
	(gdb)

scn_data was null at this code(tools/lib/bpf/src/libbpf.c):

	if (rel->r_offset % BPF_INSN_SZ || rel->r_offset >= scn_data->d_size) {

The scn_data is derived from the code above:

	scn = elf_sec_by_idx(obj, sec_idx);
	scn_data = elf_sec_data(obj, scn);

	relo_sec_name = elf_sec_str(obj, shdr->sh_name);
	sec_name = elf_sec_name(obj, scn);
	if (!relo_sec_name || !sec_name)// don't check whether scn_data is NULL
		return -EINVAL;

In certain special scenarios, such as reading a malformed ELF file,
it is possible that scn_data may be a null pointer

Signed-off-by: Mingyi Zhang <zhangmingyi5@huawei.com>
Signed-off-by: Xin Liu <liuxin350@huawei.com>
Signed-off-by: Changye Wu <wuchangye@huawei.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20231221033947.154564-1-liuxin350@huawei.com
anakryiko pushed a commit that referenced this pull request Jan 5, 2024
An issue occurred while reading an ELF file in libbpf.c during fuzzing:

	Program received signal SIGSEGV, Segmentation fault.
	0x0000000000958e97 in bpf_object.collect_prog_relos () at libbpf.c:4206
	4206 in libbpf.c
	(gdb) bt
	#0 0x0000000000958e97 in bpf_object.collect_prog_relos () at libbpf.c:4206
	#1 0x000000000094f9d6 in bpf_object.collect_relos () at libbpf.c:6706
	#2 0x000000000092bef3 in bpf_object_open () at libbpf.c:7437
	#3 0x000000000092c046 in bpf_object.open_mem () at libbpf.c:7497
	#4 0x0000000000924afa in LLVMFuzzerTestOneInput () at fuzz/bpf-object-fuzzer.c:16
	#5 0x000000000060be11 in testblitz_engine::fuzzer::Fuzzer::run_one ()
	#6 0x000000000087ad92 in tracing::span::Span::in_scope ()
	#7 0x00000000006078aa in testblitz_engine::fuzzer::util::walkdir ()
	#8 0x00000000005f3217 in testblitz_engine::entrypoint::main::{{closure}} ()
	#9 0x00000000005f2601 in main ()
	(gdb)

scn_data was null at this code(tools/lib/bpf/src/libbpf.c):

	if (rel->r_offset % BPF_INSN_SZ || rel->r_offset >= scn_data->d_size) {

The scn_data is derived from the code above:

	scn = elf_sec_by_idx(obj, sec_idx);
	scn_data = elf_sec_data(obj, scn);

	relo_sec_name = elf_sec_str(obj, shdr->sh_name);
	sec_name = elf_sec_name(obj, scn);
	if (!relo_sec_name || !sec_name)// don't check whether scn_data is NULL
		return -EINVAL;

In certain special scenarios, such as reading a malformed ELF file,
it is possible that scn_data may be a null pointer

Signed-off-by: Mingyi Zhang <zhangmingyi5@huawei.com>
Signed-off-by: Xin Liu <liuxin350@huawei.com>
Signed-off-by: Changye Wu <wuchangye@huawei.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20231221033947.154564-1-liuxin350@huawei.com
the80srobot pushed a commit to wowsignal-io/libbpf that referenced this pull request Mar 5, 2025
An issue occurred while reading an ELF file in libbpf.c during fuzzing:

	Program received signal SIGSEGV, Segmentation fault.
	0x0000000000958e97 in bpf_object.collect_prog_relos () at libbpf.c:4206
	4206 in libbpf.c
	(gdb) bt
	#0 0x0000000000958e97 in bpf_object.collect_prog_relos () at libbpf.c:4206
	libbpf#1 0x000000000094f9d6 in bpf_object.collect_relos () at libbpf.c:6706
	libbpf#2 0x000000000092bef3 in bpf_object_open () at libbpf.c:7437
	libbpf#3 0x000000000092c046 in bpf_object.open_mem () at libbpf.c:7497
	libbpf#4 0x0000000000924afa in LLVMFuzzerTestOneInput () at fuzz/bpf-object-fuzzer.c:16
	libbpf#5 0x000000000060be11 in testblitz_engine::fuzzer::Fuzzer::run_one ()
	libbpf#6 0x000000000087ad92 in tracing::span::Span::in_scope ()
	libbpf#7 0x00000000006078aa in testblitz_engine::fuzzer::util::walkdir ()
	libbpf#8 0x00000000005f3217 in testblitz_engine::entrypoint::main::{{closure}} ()
	libbpf#9 0x00000000005f2601 in main ()
	(gdb)

scn_data was null at this code(tools/lib/bpf/src/libbpf.c):

	if (rel->r_offset % BPF_INSN_SZ || rel->r_offset >= scn_data->d_size) {

The scn_data is derived from the code above:

	scn = elf_sec_by_idx(obj, sec_idx);
	scn_data = elf_sec_data(obj, scn);

	relo_sec_name = elf_sec_str(obj, shdr->sh_name);
	sec_name = elf_sec_name(obj, scn);
	if (!relo_sec_name || !sec_name)// don't check whether scn_data is NULL
		return -EINVAL;

In certain special scenarios, such as reading a malformed ELF file,
it is possible that scn_data may be a null pointer

Signed-off-by: Mingyi Zhang <zhangmingyi5@huawei.com>
Signed-off-by: Xin Liu <liuxin350@huawei.com>
Signed-off-by: Changye Wu <wuchangye@huawei.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20231221033947.154564-1-liuxin350@huawei.com
shunghsiyu added a commit to shunghsiyu/libbpf that referenced this pull request Apr 24, 2025
…linux-6.6.y

The panic look as follow

  68/1    deny_namespace/unpriv_userns_create_no_bpf:OK
  68/2    deny_namespace/userns_create_bpf:OK
  68      deny_namespace:OK
  [   45.307959] BUG: kernel NULL pointer dereference, address: 0000000000000000
  [   45.308066] #PF: supervisor read access in kernel mode
  [   45.308066] #PF: error_code(0x0000) - not-present page
  [   45.308066] PGD 0 P4D 0
  [   45.308066] Oops: 0000 [libbpf#1] PREEMPT SMP NOPTI
  [   45.308066] CPU: 0 PID: 102 Comm: test_progs Tainted: G           OE      6.6.87 libbpf#1
  [   45.308066] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
  [   45.308066] RIP: 0010:bpf_prog_8ee9cbe7c9b5a50f_test_1+0x17/0x28
  [   45.308066] Code: cc cc cc cc cc cc cc cc cc cc cc 40 00 00 00 cc cc cc cc f3 0f 1e fa 0f 1f 44 00 00 66 90 55 48 89 e5 f3 0f 1e fa 48 8b 7f 00 <8b> 47 00 be 5a 00 00 00 89 77 00 c9 e9 1b 99 cb cb cc cc cc cc cc
  [   45.308066] RSP: 0018:ffff8c9380a9fd90 EFLAGS: 00010202
  [   45.308066] RAX: 0000000000000001 RBX: 0000000000000001 RCX: 00000000d1c085bc
  [   45.308066] RDX: 0000000000000000 RSI: 00000000ef98db2b RDI: 0000000000000000
  [   45.308066] RBP: ffff8c9380a9fd90 R08: 000000000000001a R09: 000000000000001a
  [   45.308066] R10: 0000000000000001 R11: 0000000000000000 R12: ffff8946c25f8a00
  [   45.308066] R13: ffff8946c59d2000 R14: ffff8946c25f8980 R15: 000000000000006f
  [   45.308066] FS:  00007fcd84703140(0000) GS:ffff8946fbc00000(0000) knlGS:0000000000000000
  [   45.308066] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  [   45.308066] CR2: 0000000000000000 CR3: 0000000100288006 CR4: 0000000000370ef0
  [   45.308066] Call Trace:
  [   45.308066]  <TASK>
  [   45.308066]  ? srso_alias_return_thunk+0x5/0xfbef5
  [   45.308066]  ? bpf_struct_ops_test_run+0x1cb/0x2e0
  [   45.308066]  ? __sys_bpf+0x7db/0x2a70
  [   45.308066]  ? srso_alias_return_thunk+0x5/0xfbef5
  [   45.308066]  ? __x64_sys_bpf+0x1e/0x30
  [   45.308066]  ? do_syscall_64+0x39/0x90
  [   45.308066]  ? entry_SYSCALL_64_after_hwframe+0x78/0xe2
  [   45.308066]  </TASK>
  [   45.308066] Modules linked in: bpf_testmod(OE) [last unloaded: bpf_testmod(OE)]
  [   45.308066] CR2: 0000000000000000
  [   45.308066] ---[ end trace 0000000000000000 ]---
  [   45.308066] RIP: 0010:bpf_prog_8ee9cbe7c9b5a50f_test_1+0x17/0x28
  [   45.308066] Code: cc cc cc cc cc cc cc cc cc cc cc 40 00 00 00 cc cc cc cc f3 0f 1e fa 0f 1f 44 00 00 66 90 55 48 89 e5 f3 0f 1e fa 48 8b 7f 00 <8b> 47 00 be 5a 00 00 00 89 77 00 c9 e9 1b 99 cb cb cc cc cc cc cc
  [   45.308066] RSP: 0018:ffff8c9380a9fd90 EFLAGS: 00010202
  [   45.308066] RAX: 0000000000000001 RBX: 0000000000000001 RCX: 00000000d1c085bc
  [   45.308066] RDX: 0000000000000000 RSI: 00000000ef98db2b RDI: 0000000000000000
  [   45.308066] RBP: ffff8c9380a9fd90 R08: 000000000000001a R09: 000000000000001a
  [   45.308066] R10: 0000000000000001 R11: 0000000000000000 R12: ffff8946c25f8a00
  [   45.308066] R13: ffff8946c59d2000 R14: ffff8946c25f8980 R15: 000000000000006f
  [   45.308066] FS:  00007fcd84703140(0000) GS:ffff8946fbc00000(0000) knlGS:0000000000000000
  [   45.308066] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  [   45.308066] CR2: 0000000000000000 CR3: 0000000100288006 CR4: 0000000000370ef0
  [   45.308066] Kernel panic - not syncing: Fatal exception
  [   45.308066] Kernel Offset: 0xa000000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)

Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
anakryiko pushed a commit to anakryiko/libbpf that referenced this pull request Apr 29, 2025
As shown in [1], it is possible to corrupt a BPF ELF file such that
arbitrary BPF instructions are loaded by libbpf. This can be done by
setting a symbol (BPF program) section offset to a large (unsigned)
number such that <section start + symbol offset> overflows and points
before the section data in the memory.

Consider the situation below where:
- prog_start = sec_start + symbol_offset    <-- size_t overflow here
- prog_end   = prog_start + prog_size

    prog_start        sec_start        prog_end        sec_end
        |                |                 |              |
        v                v                 v              v
    .....................|################################|............

The report in [1] also provides a corrupted BPF ELF which can be used as
a reproducer:

    $ readelf -S crash
    Section Headers:
      [Nr] Name              Type             Address           Offset
           Size              EntSize          Flags  Link  Info  Align
    ...
      [ 2] uretprobe.mu[...] PROGBITS         0000000000000000  00000040
           0000000000000068  0000000000000000  AX       0     0     8

    $ readelf -s crash
    Symbol table '.symtab' contains 8 entries:
       Num:    Value          Size Type    Bind   Vis      Ndx Name
    ...
         6: ffffffffffffffb8   104 FUNC    GLOBAL DEFAULT    2 handle_tp

Here, the handle_tp prog has section offset ffffffffffffffb8, i.e. will
point before the actual memory where section 2 is allocated.

This is also reported by AddressSanitizer:

    =================================================================
    ==1232==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7c7302fe0000 at pc 0x7fc3046e4b77 bp 0x7ffe64677cd0 sp 0x7ffe64677490
    READ of size 104 at 0x7c7302fe0000 thread T0
        #0 0x7fc3046e4b76 in memcpy (/lib64/libasan.so.8+0xe4b76)
        libbpf#1 0x00000040df3e in bpf_object__init_prog /src/libbpf/src/libbpf.c:856
        libbpf#2 0x00000040df3e in bpf_object__add_programs /src/libbpf/src/libbpf.c:928
        libbp
B30A
f#3 0x00000040df3e in bpf_object__elf_collect /src/libbpf/src/libbpf.c:3930
        libbpf#4 0x00000040df3e in bpf_object_open /src/libbpf/src/libbpf.c:8067
        libbpf#5 0x00000040f176 in bpf_object__open_file /src/libbpf/src/libbpf.c:8090
        libbpf#6 0x000000400c16 in main /poc/poc.c:8
        libbpf#7 0x7fc3043d25b4 in __libc_start_call_main (/lib64/libc.so.6+0x35b4)
        libbpf#8 0x7fc3043d2667 in __libc_start_main@@GLIBC_2.34 (/lib64/libc.so.6+0x3667)
        libbpf#9 0x000000400b34 in _start (/poc/poc+0x400b34)

    0x7c7302fe0000 is located 64 bytes before 104-byte region [0x7c7302fe0040,0x7c7302fe00a8)
    allocated by thread T0 here:
        #0 0x7fc3046e716b in malloc (/lib64/libasan.so.8+0xe716b)
        libbpf#1 0x7fc3045ee600 in __libelf_set_rawdata_wrlock (/lib64/libelf.so.1+0xb600)
        libbpf#2 0x7fc3045ef018 in __elf_getdata_rdlock (/lib64/libelf.so.1+0xc018)
        libbpf#3 0x00000040642f in elf_sec_data /src/libbpf/src/libbpf.c:3740

The problem here is that currently, libbpf only checks that the program
end is within the section bounds. There used to be a check
`while (sec_off < sec_sz)` in bpf_object__add_programs, however, it was
removed by commit 6245947c1b3c ("libbpf: Allow gaps in BPF program
sections to support overriden weak functions").

Add a check for detecting the overflow of `sec_off + prog_sz` to
bpf_object__init_prog to fix this issue.

[1] https://github.com/lmarch2/poc/blob/main/libbpf/libbpf.md

Fixes: 6245947c1b3c ("libbpf: Allow gaps in BPF program sections to support overriden weak functions")
Reported-by: lmarch2 <2524158037@qq.com>
Signed-off-by: Viktor Malik <vmalik@redhat.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
Link: https://github.com/lmarch2/poc/blob/main/libbpf/libbpf.md
Link: https://lore.kernel.org/bpf/20250415155014.397603-1-vmalik@redhat.com
anakryiko pushed a commit that referenced this pull request Apr 29, 2025
As shown in [1], it is possible to corrupt a BPF ELF file such that
arbitrary BPF instructions are loaded by libbpf. This can be done by
setting a symbol (BPF program) section offset to a large (unsigned)
number such that <section start + symbol offset> overflows and points
before the section data in the memory.

Consider the situation below where:
- prog_start = sec_start + symbol_offset    <-- size_t overflow here
- prog_end   = prog_start + prog_size

    prog_start        sec_start        prog_end        sec_end
        |                |                 |              |
        v                v                 v              v
    .....................|################################|............

The report in [1] also provides a corrupted BPF ELF which can be used as
a reproducer:

    $ readelf -S crash
    Section Headers:
      [Nr] Name              Type             Address           Offset
           Size              EntSize          Flags  Link  Info  Align
    ...
      [ 2] uretprobe.mu[...] PROGBITS         0000000000000000  00000040
           0000000000000068  0000000000000000  AX       0     0     8

    $ readelf -s crash
    Symbol table '.symtab' contains 8 entries:
       Num:    Value          Size Type    Bind   Vis      Ndx Name
    ...
         6: ffffffffffffffb8   104 FUNC    GLOBAL DEFAULT    2 handle_tp

Here, the handle_tp prog has section offset ffffffffffffffb8, i.e. will
point before the actual memory where section 2 is allocated.

This is also reported by AddressSanitizer:

    =================================================================
    ==1232==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7c7302fe0000 at pc 0x7fc3046e4b77 bp 0x7ffe64677cd0 sp 0x7ffe64677490
    READ of size 104 at 0x7c7302fe0000 thread T0
        #0 0x7fc3046e4b76 in memcpy (/lib64/libasan.so.8+0xe4b76)
        #1 0x00000040df3e in bpf_object__init_prog /src/libbpf/src/libbpf.c:856
        #2 0x00000040df3e in bpf_object__add_programs /src/libbpf/src/libbpf.c:928
        #3 0x00000040df3e in bpf_object__elf_collect /src/libbpf/src/libbpf.c:3930
        #4 0x00000040df3e in bpf_object_open /src/libbpf/src/libbpf.c:8067
        #5 0x00000040f176 in bpf_object__open_file /src/libbpf/src/libbpf.c:8090
        #6 0x000000400c16 in main /poc/poc.c:8
        #7 0x7fc3043d25b4 in __libc_start_call_main (/lib64/libc.so.6+0x35b4)
        #8 0x7fc3043d2667 in __libc_start_main@@GLIBC_2.34 (/lib64/libc.so.6+0x3667)
        #9 0x000000400b34 in _start (/poc/poc+0x400b34)

    0x7c7302fe0000 is located 64 bytes before 104-byte region [0x7c7302fe0040,0x7c7302fe00a8)
    allocated by thread T0 here:
        #0 0x7fc3046e716b in malloc (/lib64/libasan.so.8+0xe716b)
        #1 0x7fc3045ee600 in __libelf_set_rawdata_wrlock (/lib64/libelf.so.1+0xb600)
        #2 0x7fc3045ef018 in __elf_getdata_rdlock (/lib64/libelf.so.1+0xc018)
        #3 0x00000040642f in elf_sec_data /src/libbpf/src/libbpf.c:3740

The problem here is that currently, libbpf only checks that the program
end is within the section bounds. There used to be a check
`while (sec_off < sec_sz)` in bpf_object__add_programs, however, it was
removed by commit 6245947c1b3c ("libbpf: Allow gaps in BPF program
sections to support overriden weak functions").

Add a check for detecting the overflow of `sec_off + prog_sz` to
bpf_object__init_prog to fix this issue.

[1] https://github.com/lmarch2/poc/blob/main/libbpf/libbpf.md

Fixes: 6245947c1b3c ("libbpf: Allow gaps in BPF program sections to support overriden weak functions")
Reported-by: lmarch2 <2524158037@qq.com>
Signed-off-by: Viktor Malik <vmalik@redhat.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
Link: https://github.com/lmarch2/poc/blob/main/libbpf/libbpf.md
Link: https://lore.kernel.org/bpf/20250415155014.397603-1-vmalik@redhat.com
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0