diff --git a/backport-libbpf-Fix-is_pow_of_2.patch b/backport-libbpf-Fix-is_pow_of_2.patch new file mode 100644 index 0000000000000000000000000000000000000000..092fbcc9dcff02ba4225a828cc2bfcdee5305dd2 --- /dev/null +++ b/backport-libbpf-Fix-is_pow_of_2.patch @@ -0,0 +1,67 @@ +From ad0783c4309a37690810a152a8902c3d12b086b5 Mon Sep 17 00:00:00 2001 +From: Yuze Chi +Date: Thu, 2 Jun 2022 22:51:56 -0700 +Subject: [PATCH] libbpf: Fix is_pow_of_2 + +Move the correct definition from linker.c into libbpf_internal.h. + +Fixes: 0087a681fa8c ("libbpf: Automatically fix up BPF_MAP_TYPE_RINGBUF size, if necessary") +Reported-by: Yuze Chi +Signed-off-by: Yuze Chi +Signed-off-by: Ian Rogers +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20220603055156.2830463-1-irogers@google.com +--- + src/libbpf.c | 5 ----- + src/libbpf_internal.h | 5 +++++ + src/linker.c | 5 ----- + 3 files changed, 5 insertions(+), 10 deletions(-) + +diff --git a/src/libbpf.c b/src/libbpf.c +index 5afe4cbd6..b03165687 100644 +--- a/src/libbpf.c ++++ b/src/libbpf.c +@@ -5071,11 +5071,6 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) + + static void bpf_map__destroy(struct bpf_map *map); + +-static bool is_pow_of_2(size_t x) +-{ +- return x && (x & (x - 1)); +-} +- + static size_t adjust_ringbuf_sz(size_t sz) + { + __u32 page_sz = sysconf(_SC_PAGE_SIZE); +diff --git a/src/libbpf_internal.h b/src/libbpf_internal.h +index 4abdbe2fe..ef5d97507 100644 +--- a/src/libbpf_internal.h ++++ b/src/libbpf_internal.h +@@ -580,4 +580,9 @@ struct bpf_link * usdt_manager_attach_usdt(struct usdt_manager *man, + const char *usdt_provider, const char *usdt_name, + __u64 usdt_cookie); + ++static inline bool is_pow_of_2(size_t x) ++{ ++ return x && (x & (x - 1)) == 0; ++} ++ + #endif /* __LIBBPF_LIBBPF_INTERNAL_H */ +diff --git a/src/linker.c b/src/linker.c +index 9aa016fb5..85c0fddf5 100644 +--- a/src/linker.c ++++ b/src/linker.c +@@ -697,11 +697,6 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, + return err; + } + +-static bool is_pow_of_2(size_t x) +-{ +- return x && (x & (x - 1)) == 0; +-} +- + static int linker_sanity_check_elf(struct src_obj *obj) + { + struct src_sec *sec; +-- +2.33.0 diff --git a/backport-libbpf-Fix-realloc-API-handling-in-zero-sized-edge-cases.patch b/backport-libbpf-Fix-realloc-API-handling-in-zero-sized-edge-cases.patch new file mode 100644 index 0000000000000000000000000000000000000000..e2638f0f6243824520744a22623705f203b2d0c1 --- /dev/null +++ b/backport-libbpf-Fix-realloc-API-handling-in-zero-sized-edge-cases.patch @@ -0,0 +1,92 @@ +From f117080307163d7057034341aa8ff6b201041599 Mon Sep 17 00:00:00 2001 +From: Andrii Nakryiko +Date: Mon, 10 Jul 2023 19:41:50 -0700 +Subject: [PATCH] libbpf: Fix realloc API handling in zero-sized edge cases + +realloc() and reallocarray() can either return NULL or a special +non-NULL pointer, if their size argument is zero. This requires a bit +more care to handle NULL-as-valid-result situation differently from +NULL-as-error case. This has caused real issues before ([0]), and just +recently bit again in production when performing bpf_program__attach_usdt(). + +This patch fixes 4 places that do or potentially could suffer from this +mishandling of NULL, including the reported USDT-related one. + +There are many other places where realloc()/reallocarray() is used and +NULL is always treated as an error value, but all those have guarantees +that their size is always non-zero, so those spot don't need any extra +handling. + + [0] d08ab82f59d5 ("libbpf: Fix double-free when linker processes empty sections") + +Fixes: 999783c8bbda ("libbpf: Wire up spec management and other arch-independent USDT logic") +Fixes: b63b3c490eee ("libbpf: Add bpf_program__set_insns function") +Fixes: 697f104db8a6 ("libbpf: Support custom SEC() handlers") +Fixes: b12688267280 ("libbpf: Change the order of data and text relocations.") +Signed-off-by: Andrii Nakryiko +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/bpf/20230711024150.1566433-1-andrii@kernel.org +--- + src/libbpf.c | 15 ++++++++++++--- + src/usdt.c | 5 ++++- + 2 files changed, 16 insertions(+), 4 deletions(-) + +diff --git a/src/libbpf.c b/src/libbpf.c +index 78635feb1..63311a73c 100644 +--- a/src/libbpf.c ++++ b/src/libbpf.c +@@ -6161,7 +6161,11 @@ static int append_subprog_relos(struct bpf_program *main_prog, struct bpf_progra + if (main_prog == subprog) + return 0; + relos = libbpf_reallocarray(main_prog->reloc_desc, new_cnt, sizeof(*relos)); +- if (!relos) ++ /* if new count is zero, reallocarray can return a valid NULL result; ++ * in this case the previous pointer will be freed, so we *have to* ++ * reassign old pointer to the new value (even if it's NULL) ++ */ ++ if (!relos && new_cnt) + return -ENOMEM; + if (subprog->nr_reloc) + memcpy(relos + main_prog->nr_reloc, subprog->reloc_desc, +@@ -8532,7 +8536,8 @@ int bpf_program__set_insns(struct bpf_program *prog, + return -EBUSY; + + insns = libbpf_reallocarray(prog->insns, new_insn_cnt, sizeof(*insns)); +- if (!insns) { ++ /* NULL is a valid return from reallocarray if the new count is zero */ ++ if (!insns && new_insn_cnt) { + pr_warn("prog '%s': failed to realloc prog code\n", prog->name); + return -ENOMEM; + } +@@ -8841,7 +8846,11 @@ int libbpf_unregister_prog_handler(int handler_id) + + /* try to shrink the array, but it's ok if we couldn't */ + sec_defs = libbpf_reallocarray(custom_sec_defs, custom_sec_def_cnt, sizeof(*sec_defs)); +- if (sec_defs) ++ /* if new count is zero, reallocarray can return a valid NULL result; ++ * in this case the previous pointer will be freed, so we *have to* ++ * reassign old pointer to the new value (even if it's NULL) ++ */ ++ if (sec_defs || custom_sec_def_cnt == 0) + custom_sec_defs = sec_defs; + + return 0; +diff --git a/src/usdt.c b/src/usdt.c +index f1a141555..37455d00b 100644 +--- a/src/usdt.c ++++ b/src/usdt.c +@@ -852,8 +852,11 @@ static int bpf_link_usdt_detach(struct bpf_link *link) + * system is so exhausted on memory, it's the least of user's + * concerns, probably. + * So just do our best here to return those IDs to usdt_manager. ++ * Another edge case when we can legitimately get NULL is when ++ * new_cnt is zero, which can happen in some edge cases, so we ++ * need to be careful about that. + */ +- if (new_free_ids) { ++ if (new_free_ids || new_cnt == 0) { + memcpy(new_free_ids + man->free_spec_cnt, usdt_link->spec_ids, + usdt_link->spec_cnt * sizeof(*usdt_link->spec_ids)); + man->free_spec_ids = new_free_ids; +-- +2.33.0 diff --git a/backport-libbpf-Set-close-on-exec-flag-on-gzopen.patch b/backport-libbpf-Set-close-on-exec-flag-on-gzopen.patch new file mode 100644 index 0000000000000000000000000000000000000000..ec494ea74e9706a50b0c065ae22028394c102fc3 --- /dev/null +++ b/backport-libbpf-Set-close-on-exec-flag-on-gzopen.patch @@ -0,0 +1,37 @@ +From 20699ecf61f21b761fcc369ddc85da5f5cf5a1cf Mon Sep 17 00:00:00 2001 +From: Marco Vedovati +Date: Thu, 10 Aug 2023 14:43:53 -0700 +Subject: [PATCH] libbpf: Set close-on-exec flag on gzopen + +Enable the close-on-exec flag when using gzopen. This is especially important +for multithreaded programs making use of libbpf, where a fork + exec could +race with libbpf library calls, potentially resulting in a file descriptor +leaked to the new process. This got missed in 59842c5451fe ("libbpf: Ensure +libbpf always opens files with O_CLOEXEC"). + +Fixes: 59842c5451fe ("libbpf: Ensure libbpf always opens files with O_CLOEXEC") +Signed-off-by: Marco Vedovati +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/bpf/20230810214350.106301-1-martin.kelly@crowdstrike.com +--- + src/libbpf.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libbpf.c b/src/libbpf.c +index 17883f5a4..b14a4376a 100644 +--- a/src/libbpf.c ++++ b/src/libbpf.c +@@ -1978,9 +1978,9 @@ static int bpf_object__read_kconfig_file(struct bpf_object *obj, void *data) + return -ENAMETOOLONG; + + /* gzopen also accepts uncompressed files. */ +- file = gzopen(buf, "r"); ++ file = gzopen(buf, "re"); + if (!file) +- file = gzopen("/proc/config.gz", "r"); ++ file = gzopen("/proc/config.gz", "re"); + + if (!file) { + pr_warn("failed to open system Kconfig\n"); +-- +2.33.0 diff --git a/backport-libbpf-make-RINGBUF-map-size-adjustments-more-eagerly.patch b/backport-libbpf-make-RINGBUF-map-size-adjustments-more-eagerly.patch new file mode 100644 index 0000000000000000000000000000000000000000..f15c73c4df44d9f2bbb95ca869b3aa2ac07d6180 --- /dev/null +++ b/backport-libbpf-make-RINGBUF-map-size-adjustments-more-eagerly.patch @@ -0,0 +1,154 @@ +From 610707057ac60311fde94b3a049de9d4826a3bf2 Mon Sep 17 00:00:00 2001 +From: Andrii Nakryiko +Date: Fri, 15 Jul 2022 16:09:51 -0700 +Subject: [PATCH] libbpf: make RINGBUF map size adjustments more eagerly + +Make libbpf adjust RINGBUF map size (rounding it up to closest power-of-2 +of page_size) more eagerly: during open phase when initializing the map +and on explicit calls to bpf_map__set_max_entries(). + +Such approach allows user to check actual size of BPF ringbuf even +before it's created in the kernel, but also it prevents various edge +case scenarios where BPF ringbuf size can get out of sync with what it +would be in kernel. One of them (reported in [0]) is during an attempt +to pin/reuse BPF ringbuf. + +Move adjust_ringbuf_sz() helper closer to its first actual use. The +implementation of the helper is unchanged. + +Also make detection of whether bpf_object is already loaded more robust +by checking obj->loaded explicitly, given that map->fd can be < 0 even +if bpf_object is already loaded due to ability to disable map creation +with bpf_map__set_autocreate(map, false). + + [0] Closes: https://github.com/libbpf/libbpf/pull/530 + +Fixes: 0087a681fa8c ("libbpf: Automatically fix up BPF_MAP_TYPE_RINGBUF size, if necessary") +Signed-off-by: Andrii Nakryiko +Acked-by: Yonghong Song +Link: https://lore.kernel.org/r/20220715230952.2219271-1-andrii@kernel.org +Signed-off-by: Alexei Starovoitov +--- + src/libbpf.c | 77 ++++++++++++++++++++++++++++------------------------ + 1 file changed, 42 insertions(+), 35 deletions(-) + +diff --git a/src/libbpf.c b/src/libbpf.c +index 9b5500659..b01fe01b0 100644 +--- a/src/libbpf.c ++++ b/src/libbpf.c +@@ -2331,6 +2331,37 @@ int parse_btf_map_def(const char *map_name, struct btf *btf, + return 0; + } + ++static size_t adjust_ringbuf_sz(size_t sz) ++{ ++ __u32 page_sz = sysconf(_SC_PAGE_SIZE); ++ __u32 mul; ++ ++ /* if user forgot to set any size, make sure they see error */ ++ if (sz == 0) ++ return 0; ++ /* Kernel expects BPF_MAP_TYPE_RINGBUF's max_entries to be ++ * a power-of-2 multiple of kernel's page size. If user diligently ++ * satisified these conditions, pass the size through. ++ */ ++ if ((sz % page_sz) == 0 && is_pow_of_2(sz / page_sz)) ++ return sz; ++ ++ /* Otherwise find closest (page_sz * power_of_2) product bigger than ++ * user-set size to satisfy both user size request and kernel ++ * requirements and substitute correct max_entries for map creation. ++ */ ++ for (mul = 1; mul <= UINT_MAX / page_sz; mul <<= 1) { ++ if (mul * page_sz > sz) ++ return mul * page_sz; ++ } ++ ++ /* if it's impossible to satisfy the conditions (i.e., user size is ++ * very close to UINT_MAX but is not a power-of-2 multiple of ++ * page_size) then just return original size and let kernel reject it ++ */ ++ return sz; ++} ++ + static void fill_map_from_def(struct bpf_map *map, const struct btf_map_def *def) + { + map->def.type = def->map_type; +@@ -2344,6 +2375,10 @@ static void fill_map_from_def(struct bpf_map *map, const struct btf_map_def *def + map->btf_key_type_id = def->key_type_id; + map->btf_value_type_id = def->value_type_id; + ++ /* auto-adjust BPF ringbuf map max_entries to be a multiple of page size */ ++ if (map->def.type == BPF_MAP_TYPE_RINGBUF) ++ map->def.max_entries = adjust_ringbuf_sz(map->def.max_entries); ++ + if (def->parts & MAP_DEF_MAP_TYPE) + pr_debug("map '%s': found type = %u.\n", map->name, def->map_type); + +@@ -4317,9 +4352,15 @@ struct bpf_map *bpf_map__inner_map(struct bpf_map *map) + + int bpf_map__set_max_entries(struct bpf_map *map, __u32 max_entries) + { +- if (map->fd >= 0) ++ if (map->obj->loaded) + return libbpf_err(-EBUSY); ++ + map->def.max_entries = max_entries; ++ ++ /* auto-adjust BPF ringbuf map max_entries to be a multiple of page size */ ++ if (map->def.type == BPF_MAP_TYPE_RINGBUF) ++ map->def.max_entries = adjust_ringbuf_sz(map->def.max_entries); ++ + return 0; + } + +@@ -4875,37 +4916,6 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) + + static void bpf_map__destroy(struct bpf_map *map); + +-static size_t adjust_ringbuf_sz(size_t sz) +-{ +- __u32 page_sz = sysconf(_SC_PAGE_SIZE); +- __u32 mul; +- +- /* if user forgot to set any size, make sure they see error */ +- if (sz == 0) +- return 0; +- /* Kernel expects BPF_MAP_TYPE_RINGBUF's max_entries to be +- * a power-of-2 multiple of kernel's page size. If user diligently +- * satisified these conditions, pass the size through. +- */ +- if ((sz % page_sz) == 0 && is_pow_of_2(sz / page_sz)) +- return sz; +- +- /* Otherwise find closest (page_sz * power_of_2) product bigger than +- * user-set size to satisfy both user size request and kernel +- * requirements and substitute correct max_entries for map creation. +- */ +- for (mul = 1; mul <= UINT_MAX / page_sz; mul <<= 1) { +- if (mul * page_sz > sz) +- return mul * page_sz; +- } +- +- /* if it's impossible to satisfy the conditions (i.e., user size is +- * very close to UINT_MAX but is not a power-of-2 multiple of +- * page_size) then just return original size and let kernel reject it +- */ +- return sz; +-} +- + static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, bool is_inner) + { + LIBBPF_OPTS(bpf_map_create_opts, create_attr); +@@ -4944,9 +4954,6 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b + } + + switch (def->type) { +- case BPF_MAP_TYPE_RINGBUF: +- map->def.max_entries = adjust_ringbuf_sz(map->def.max_entries); +- /* fallthrough */ + case BPF_MAP_TYPE_PERF_EVENT_ARRAY: + case BPF_MAP_TYPE_CGROUP_ARRAY: + case BPF_MAP_TYPE_STACK_TRACE: +-- +2.33.0 diff --git a/libbpf.spec b/libbpf.spec index 9d8eb98c9a024c526283f35a9f1fab13a51a5bb1..2ea9bc1fe94f131d9f56ad8347b14989f7475258 100644 --- a/libbpf.spec +++ b/libbpf.spec @@ -4,7 +4,7 @@ Name: %{githubname} Version: %{githubver} -Release: 10 +Release: 11 Summary: Libbpf library License: LGPLv2 or BSD @@ -34,6 +34,10 @@ Patch0017: backport-libbpf-Use-elf_getshdrnum-instead-of-e_shnum.patch Patch0018: backport-libbpf-Ensure-FD-3-during-bpf_map__reuse_fd.patch Patch0019: backport-libbpf-Ensure-libbpf-always-opens-files-with-O_CLOEX.patch Patch0020: 0001-remove-nonexistent-helper-functions-and-add-new-help.patch +Patch0021: backport-libbpf-Fix-realloc-API-handling-in-zero-sized-edge-cases.patch +Patch0022: backport-libbpf-Set-close-on-exec-flag-on-gzopen.patch +Patch0023: backport-libbpf-Fix-is_pow_of_2.patch +Patch0024: backport-libbpf-make-RINGBUF-map-size-adjustments-more-eagerly.patch # This package supersedes libbpf from kernel-tools, # which has default Epoch: 0. By having Epoch: 1 @@ -86,6 +90,13 @@ developing applications that use %{name} %{_libdir}/libbpf.a %changelog +* Thu Dec 7 2023 zhangmingyi 2:0.8.1-11 +- backport patches from upstream: + backport-libbpf-Fix-realloc-API-handling-in-zero-sized-edge-cases.patch + backport-libbpf-Set-close-on-exec-flag-on-gzopen.patch + backport-libbpf-Fix-is_pow_of_2.patch + backport-libbpf-make-RINGBUF-map-size-adjustments-more-eagerly.patch + * Fri Dec 1 2023 liningjie 2:0.8.1-10 - backport patches from openEuler-22.03-LTS-SP2: 0001-remove-nonexistent-helper-functions-and-add-new-help.patch