[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1102091: bookworm-pu: package libbpf/1.1.2-1+deb12u1



Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: libbpf@packages.debian.org, sudipm.mukherjee@gmail.com
Control: affects -1 + src:libbpf

[ Reason ]

As mentioned in #1101745, latest systemd versions will segfault if used
with the libbpf packaged in bookworm. The systemd version present in
bookworm is not affected, but if any user tries to update and install the
latest systemd from upstream they will face the issue.
The relevant systemd issue is https://github.com/systemd/systemd/issues/36903.

The issue was reported for systemd, but it is possible that any user with
a similar usecase will see the same segfault.

[ Impact ]

user applications using libbpf which triggers the same scenario as systemd issue
will crash with a segfailt. 

[ Tests ]

Manually tested by installing in a Bookworm system.
1. Confirmed that systemd still works and there is no issue seen in the
basic usage of the system.
2. Used bpftrace and confirmed that it is still working and no issues seen
in its basic usage.

[ Risks ]

There are total of 3 commits between 1.1.0 to 1.1.2. All 3 commits are only fixing
bugs as documented in the [Changes] section below. There is no other change of code.
All the 3 commits are backported by upstream from later release and they are part
of v1.5.0 in Trixie and no issues has been reported yet.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]

There are total of 3 commits as can be seen at: https://github.com/libbpf/libbpf/compare/v1.1.0...v1.1.2
The details of the commits:

commit 6cbb1a25347de0c85cb91cdbed9912eb3c21e77b
Author: Andrii Nakryiko <andrii@kernel.org>
Date:   Mon Jul 8 13:45:39 2024 -0700

    libbpf: fix BPF skeleton forward/backward compat handling
    
    BPF skeleton was designed from day one to be extensible. Generated BPF
    skeleton code specifies actual sizes of map/prog/variable skeletons for
    that reason and libbpf is supposed to work with newer/older versions
    correctly.
    
    Unfortunately, it was missed that we implicitly embed hard-coded most
    up-to-date (according to libbpf's version of libbpf.h header used to
    compile BPF skeleton header) sizes of those structs, which can differ
    from the actual sizes at runtime when libbpf is used as a shared
    library.
    
    We have a few places were we just index array of maps/progs/vars, which
    implicitly uses these potentially invalid sizes of structs.
    
    This patch aims to fix this problem going forward. Once this lands,
    we'll backport these changes in Github repo to create patched releases
    for older libbpfs.


commit 7696f8ada212798873295ef1ed837e5a5b7b0772
Author: Andrii Nakryiko <andrii@kernel.org>
Date:   Tue Aug 27 13:37:21 2024 -0700

    libbpf: Fix bpf_object__open_skeleton()'s mishandling of options
    
    We do an ugly copying of options in bpf_object__open_skeleton() just to
    be able to set object name from skeleton's recorded name (while still
    allowing user to override it through opts->object_name).
    
    This is not just ugly, but it also is broken due to memcpy() that
    doesn't take into account potential skel_opts' and user-provided opts'
    sizes differences due to backward and forward compatibility. This leads
    to copying over extra bytes and then failing to validate options
    properly. It could, technically, lead also to SIGSEGV, if we are unlucky.
    
    So just get rid of that memory copy completely and instead pass
    default object name into bpf_object_open() directly, simplifying all
    this significantly. The rule now is that obj_name should be non-NULL for
    bpf_object_open() when called with in-memory buffer, so validate that
    explicitly as well.
    
    We adopt bpf_object__open_mem() to this as well and generate default
    name (based on buffer memory address and size) outside of bpf_object_open().


commit 5ba294c95a833505c815eec17d3afd0398c756b6
Author: Tony Ambardar <tony.ambardar@gmail.com>
Date:   Fri Aug 30 02:51:50 2024 -0700

    libbpf: Ensure new BTF objects inherit input endianness
    
    New split BTF needs to preserve base's endianness. Similarly, when
    creating a distilled BTF, we need to preserve original endianness.
    
    Fix by updating libbpf's btf__distill_base() and btf_new_empty() to retain
    the byte order of any source BTF objects when creating new ones.


[ Other info ]

If updating the version is not acceptable, then I can try to find out
the exact commit which fixes the segfault. But since the change only fixes
reported bugs, I think it will be best to update libbpf to 1.1.2.

diff -Nru libbpf-1.1.0/debian/changelog libbpf-1.1.2/debian/changelog
--- libbpf-1.1.0/debian/changelog	2023-01-06 20:31:46.000000000 +0000
+++ libbpf-1.1.2/debian/changelog	2025-04-04 21:06:45.000000000 +0100
@@ -1,3 +1,13 @@
+libbpf (1.1.2-1+deb12u1) bookworm; urgency=medium
+
+  * New upstream version 1.1.2 (Closes: #1101745)
+    - Upstream changes:
+      - libbpf: fix BPF skeleton forward/backward compat handling.
+      - libbpf: Fix bpf_object__open_skeleton()'s mishandling of options.
+      - libbpf: Ensure new BTF objects inherit input endianness.
+
+ -- Sudip Mukherjee <sudipm.mukherjee@gmail.com>  Fri, 04 Apr 2025 21:06:45 +0100
+
 libbpf (1.1.0-1) unstable; urgency=medium
 
   * New upstream version 1.1.0
diff -Nru libbpf-1.1.0/src/btf.c libbpf-1.1.2/src/btf.c
--- libbpf-1.1.0/src/btf.c	2022-12-21 06:23:18.000000000 +0000
+++ libbpf-1.1.2/src/btf.c	2024-09-03 21:59:02.000000000 +0100
@@ -832,6 +832,7 @@
 		btf->base_btf = base_btf;
 		btf->start_id = btf__type_cnt(base_btf);
 		btf->start_str_off = base_btf->hdr->str_len;
+		btf->swapped_endian = base_btf->swapped_endian;
 	}
 
 	/* +1 for empty string at offset 0 */
diff -Nru libbpf-1.1.0/src/libbpf.c libbpf-1.1.2/src/libbpf.c
--- libbpf-1.1.0/src/libbpf.c	2022-12-21 06:23:18.000000000 +0000
+++ libbpf-1.1.2/src/libbpf.c	2024-09-03 21:59:02.000000000 +0100
@@ -7214,16 +7214,19 @@
 }
 
 static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, size_t obj_buf_sz,
+					  const char *obj_name,
 					  const struct bpf_object_open_opts *opts)
 {
-	const char *obj_name, *kconfig, *btf_tmp_path;
+	const char *kconfig, *btf_tmp_path;
 	struct bpf_object *obj;
-	char tmp_name[64];
 	int err;
 	char *log_buf;
 	size_t log_size;
 	__u32 log_level;
 
+	if (obj_buf && !obj_name)
+		return ERR_PTR(-EINVAL);
+
 	if (elf_version(EV_CURRENT) == EV_NONE) {
 		pr_warn("failed to init libelf for %s\n",
 			path ? : "(mem buf)");
@@ -7233,16 +7236,12 @@
 	if (!OPTS_VALID(opts, bpf_object_open_opts))
 		return ERR_PTR(-EINVAL);
 
-	obj_name = OPTS_GET(opts, object_name, NULL);
+	obj_name = OPTS_GET(opts, object_name, NULL) ?: obj_name;
 	if (obj_buf) {
-		if (!obj_name) {
-			snprintf(tmp_name, sizeof(tmp_name), "%lx-%lx",
-				 (unsigned long)obj_buf,
-				 (unsigned long)obj_buf_sz);
-			obj_name = tmp_name;
-		}
 		path = obj_name;
 		pr_debug("loading object '%s' from buffer\n", obj_name);
+	} else {
+		pr_debug("loading object from %s\n", path);
 	}
 
 	log_buf = OPTS_GET(opts, kernel_log_buf, NULL);
@@ -7308,9 +7307,7 @@
 	if (!path)
 		return libbpf_err_ptr(-EINVAL);
 
-	pr_debug("loading %s\n", path);
-
-	return libbpf_ptr(bpf_object_open(path, NULL, 0, opts));
+	return libbpf_ptr(bpf_object_open(path, NULL, 0, NULL, opts));
 }
 
 struct bpf_object *bpf_object__open(const char *path)
@@ -7322,10 +7319,15 @@
 bpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz,
 		     const struct bpf_object_open_opts *opts)
 {
+	char tmp_name[64];
+
 	if (!obj_buf || obj_buf_sz == 0)
 		return libbpf_err_ptr(-EINVAL);
 
-	return libbpf_ptr(bpf_object_open(NULL, obj_buf, obj_buf_sz, opts));
+	/* create a (quite useless) default "name" for this memory buffer object */
+	snprintf(tmp_name, sizeof(tmp_name), "%lx-%zx", (unsigned long)obj_buf, obj_buf_sz);
+
+	return libbpf_ptr(bpf_object_open(NULL, obj_buf, obj_buf_sz, tmp_name, opts));
 }
 
 static int bpf_object_unload(struct bpf_object *obj)
@@ -12213,14 +12215,15 @@
 
 static int populate_skeleton_maps(const struct bpf_object *obj,
 				  struct bpf_map_skeleton *maps,
-				  size_t map_cnt)
+				  size_t map_cnt, size_t map_skel_sz)
 {
 	int i;
 
 	for (i = 0; i < map_cnt; i++) {
-		struct bpf_map **map = maps[i].map;
-		const char *name = maps[i].name;
-		void **mmaped = maps[i].mmaped;
+		struct bpf_map_skeleton *map_skel = (void *)maps + i * map_skel_sz;
+		struct bpf_map **map = map_skel->map;
+		const char *name = map_skel->name;
+		void **mmaped = map_skel->mmaped;
 
 		*map = bpf_object__find_map_by_name(obj, name);
 		if (!*map) {
@@ -12237,13 +12240,14 @@
 
 static int populate_skeleton_progs(const struct bpf_object *obj,
 				   struct bpf_prog_skeleton *progs,
-				   size_t prog_cnt)
+				   size_t prog_cnt, size_t prog_skel_sz)
 {
 	int i;
 
 	for (i = 0; i < prog_cnt; i++) {
-		struct bpf_program **prog = progs[i].prog;
-		const char *name = progs[i].name;
+		struct bpf_prog_skeleton *prog_skel = (void *)progs + i * prog_skel_sz;
+		struct bpf_program **prog = prog_skel->prog;
+		const char *name = prog_skel->name;
 
 		*prog = bpf_object__find_program_by_name(obj, name);
 		if (!*prog) {
@@ -12257,40 +12261,24 @@
 int bpf_object__open_skeleton(struct bpf_object_skeleton *s,
 			      const struct bpf_object_open_opts *opts)
 {
-	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, skel_opts,
-		.object_name = s->name,
-	);
 	struct bpf_object *obj;
 	int err;
 
-	/* Attempt to preserve opts->object_name, unless overriden by user
-	 * explicitly. Overwriting object name for skeletons is discouraged,
-	 * as it breaks global data maps, because they contain object name
-	 * prefix as their own map name prefix. When skeleton is generated,
-	 * bpftool is making an assumption that this name will stay the same.
-	 */
-	if (opts) {
-		memcpy(&skel_opts, opts, sizeof(*opts));
-		if (!opts->object_name)
-			skel_opts.object_name = s->name;
-	}
-
-	obj = bpf_object__open_mem(s->data, s->data_sz, &skel_opts);
-	err = libbpf_get_error(obj);
-	if (err) {
-		pr_warn("failed to initialize skeleton BPF object '%s': %d\n",
-			s->name, err);
+	obj = bpf_object_open(NULL, s->data, s->data_sz, s->name, opts);
+	if (IS_ERR(obj)) {
+		err = PTR_ERR(obj);
+		pr_warn("failed to initialize skeleton BPF object '%s': %d\n", s->name, err);
 		return libbpf_err(err);
 	}
 
 	*s->obj = obj;
-	err = populate_skeleton_maps(obj, s->maps, s->map_cnt);
+	err = populate_skeleton_maps(obj, s->maps, s->map_cnt, s->map_skel_sz);
 	if (err) {
 		pr_warn("failed to populate skeleton maps for '%s': %d\n", s->name, err);
 		return libbpf_err(err);
 	}
 
-	err = populate_skeleton_progs(obj, s->progs, s->prog_cnt);
+	err = populate_skeleton_progs(obj, s->progs, s->prog_cnt, s->prog_skel_sz);
 	if (err) {
 		pr_warn("failed to populate skeleton progs for '%s': %d\n", s->name, err);
 		return libbpf_err(err);
@@ -12320,20 +12308,20 @@
 		return libbpf_err(-errno);
 	}
 
-	err = populate_skeleton_maps(s->obj, s->maps, s->map_cnt);
+	err = populate_skeleton_maps(s->obj, s->maps, s->map_cnt, s->map_skel_sz);
 	if (err) {
 		pr_warn("failed to populate subskeleton maps: %d\n", err);
 		return libbpf_err(err);
 	}
 
-	err = populate_skeleton_progs(s->obj, s->progs, s->prog_cnt);
+	err = populate_skeleton_progs(s->obj, s->progs, s->prog_cnt, s->prog_skel_sz);
 	if (err) {
 		pr_warn("failed to populate subskeleton maps: %d\n", err);
 		return libbpf_err(err);
 	}
 
 	for (var_idx = 0; var_idx < s->var_cnt; var_idx++) {
-		var_skel = &s->vars[var_idx];
+		var_skel = (void *)s->vars + var_idx * s->var_skel_sz;
 		map = *var_skel->map;
 		map_type_id = bpf_map__btf_value_type_id(map);
 		map_type = btf__type_by_id(btf, map_type_id);
@@ -12380,10 +12368,11 @@
 	}
 
 	for (i = 0; i < s->map_cnt; i++) {
-		struct bpf_map *map = *s->maps[i].map;
+		struct bpf_map_skeleton *map_skel = (void *)s->maps + i * s->map_skel_sz;
+		struct bpf_map *map = *map_skel->map;
 		size_t mmap_sz = bpf_map_mmap_sz(map);
-		int prot, map_fd = bpf_map__fd(map);
-		void **mmaped = s->maps[i].mmaped;
+		int prot, map_fd = map->fd;
+		void **mmaped = map_skel->mmaped;
 
 		if (!mmaped)
 			continue;
@@ -12427,8 +12416,9 @@
 	int i, err;
 
 	for (i = 0; i < s->prog_cnt; i++) {
-		struct bpf_program *prog = *s->progs[i].prog;
-		struct bpf_link **link = s->progs[i].link;
+		struct bpf_prog_skeleton *prog_skel = (void *)s->progs + i * s->prog_skel_sz;
+		struct bpf_program *prog = *prog_skel->prog;
+		struct bpf_link **link = prog_skel->link;
 
 		if (!prog->autoload || !prog->autoattach)
 			continue;
@@ -12468,7 +12458,8 @@
 	int i;
 
 	for (i = 0; i < s->prog_cnt; i++) {
-		struct bpf_link **link = s->progs[i].link;
+		struct bpf_prog_skeleton *prog_skel = (void *)s->progs + i * s->prog_skel_sz;
+		struct bpf_link **link = prog_skel->link;
 
 		bpf_link__destroy(*link);
 		*link = NULL;
diff -Nru libbpf-1.1.0/src/Makefile libbpf-1.1.2/src/Makefile
--- libbpf-1.1.0/src/Makefile	2022-12-21 06:23:18.000000000 +0000
+++ libbpf-1.1.2/src/Makefile	2024-09-03 21:59:02.000000000 +0100
@@ -10,7 +10,7 @@
 
 LIBBPF_MAJOR_VERSION := 1
 LIBBPF_MINOR_VERSION := 1
-LIBBPF_PATCH_VERSION := 0
+LIBBPF_PATCH_VERSION := 2
 LIBBPF_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).$(LIBBPF_PATCH_VERSION)
 LIBBPF_MAJMIN_VERSION := $(LIBBPF_MAJOR_VERSION).$(LIBBPF_MINOR_VERSION).0
 LIBBPF_MAP_VERSION := $(shell grep -oE '^LIBBPF_([0-9.]+)' libbpf.map | sort -rV | head -n1 | cut -d'_' -f2)

Reply to: