Skip to content

Commit d1d7730

Browse files
haoxiangbdanakryiko
authored andcommitted
libbpf: Correctly set the kernel code version in Debian kernel.
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: kernel-patches#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 <[email protected]> Signed-off-by: Ho-Ren (Jack) Chuang <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 17c9b4e commit d1d7730

File tree

2 files changed

+83
-37
lines changed

2 files changed

+83
-37
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
#include <linux/limits.h>
3535
#include <linux/perf_event.h>
3636
#include <linux/ring_buffer.h>
37-
#include <linux/version.h>
3837
#include <sys/epoll.h>
3938
#include <sys/ioctl.h>
4039
#include <sys/mman.h>
@@ -870,42 +869,6 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
870869
return 0;
871870
}
872871

873-
__u32 get_kernel_version(void)
874-
{
875-
/* On Ubuntu LINUX_VERSION_CODE doesn't correspond to info.release,
876-
* but Ubuntu provides /proc/version_signature file, as described at
877-
* https://ubuntu.com/kernel, with an example contents below, which we
878-
* can use to get a proper LINUX_VERSION_CODE.
879-
*
880-
* Ubuntu 5.4.0-12.15-generic 5.4.8
881-
*
882-
* In the above, 5.4.8 is what kernel is actually expecting, while
883-
* uname() call will return 5.4.0 in info.release.
884-
*/
885-
const char *ubuntu_kver_file = "/proc/version_signature";
886-
__u32 major, minor, patch;
887-
struct utsname info;
888-
889-
if (faccessat(AT_FDCWD, ubuntu_kver_file, R_OK, AT_EACCESS) == 0) {
890-
FILE *f;
891-
892-
f = fopen(ubuntu_kver_file, "r");
893-
if (f) {
894-
if (fscanf(f, "%*s %*s %d.%d.%d\n", &major, &minor, &patch) == 3) {
895-
fclose(f);
896-
return KERNEL_VERSION(major, minor, patch);
897-
}
898-
fclose(f);
899-
}
900-
/* something went wrong, fall back to uname() approach */
901-
}
902-
903-
uname(&info);
904-
if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3)
905-
return 0;
906-
return KERNEL_VERSION(major, minor, patch);
907-
}
908-
909872
static const struct btf_member *
910873
find_member_by_offset(const struct btf_type *t, __u32 bit_offset)
911874
{

tools/lib/bpf/libbpf_probes.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,94 @@
1212
#include <linux/btf.h>
1313
#include <linux/filter.h>
1414
#include <linux/kernel.h>
15+
#include <linux/version.h>
1516

1617
#include "bpf.h"
1718
#include "libbpf.h"
1819
#include "libbpf_internal.h"
1920

21+
/* On Ubuntu LINUX_VERSION_CODE doesn't correspond to info.release,
22+
* but Ubuntu provides /proc/version_signature file, as described at
23+
* https://ubuntu.com/kernel, with an example contents below, which we
24+
* can use to get a proper LINUX_VERSION_CODE.
25+
*
26+
* Ubuntu 5.4.0-12.15-generic 5.4.8
27+
*
28+
* In the above, 5.4.8 is what kernel is actually expecting, while
29+
* uname() call will return 5.4.0 in info.release.
30+
*/
31+
static __u32 get_ubuntu_kernel_version(void)
32+
{
33+
const char *ubuntu_kver_file = "/proc/version_signature";
34+
__u32 major, minor, patch;
35+
int ret;
36+
FILE *f;
37+
38+
if (faccessat(AT_FDCWD, ubuntu_kver_file, R_OK, AT_EACCESS) != 0)
39+
return 0;
40+
41+
f = fopen(ubuntu_kver_file, "r");
42+
if (!f)
43+
return 0;
44+
45+
ret = fscanf(f, "%*s %*s %u.%u.%u\n", &major, &minor, &patch);
46+
fclose(f);
47+
if (ret != 3)
48+
return 0;
49+
50+
return KERNEL_VERSION(major, minor, patch);
51+
}
52+
53+
/* On Debian LINUX_VERSION_CODE doesn't correspond to info.release.
54+
* Instead, it is provided in info.version. An example content of
55+
* Debian 10 looks like the below.
56+
*
57+
* utsname::release 4.19.0-22-amd64
58+
* utsname::version #1 SMP Debian 4.19.260-1 (2022-09-29)
59+
*
60+
* In the above, 4.19.260 is what kernel is actually expecting, while
61+
* uname() call will return 4.19.0 in info.release.
62+
*/
63+
static __u32 get_debian_kernel_version(struct utsname *info)
64+
{
65+
__u32 major, minor, patch;
66+
char *p;
67+
68+
p = strstr(info->version, "Debian ");
69+
if (!p) {
70+
/* This is not a Debian kernel. */
71+
return 0;
72+
}
73+
74+
if (sscanf(p, "Debian %u.%u.%u", &major, &minor, &patch) != 3)
75+
return 0;
76+
77+
return KERNEL_VERSION(major, minor, patch);
78+
}
79+
80+
__u32 get_kernel_version(void)
81+
{
82+
__u32 major, minor, patch, version;
83+
struct utsname info;
84+
85+
/* Check if this is an Ubuntu kernel. */
86+
version = get_ubuntu_kernel_version();
87+
if (version != 0)
88+
return version;
89+
90+
uname(&info);
91+
92+
/* Check if this is a Debian kernel. */
93+
version = get_debian_kernel_version(&info);
94+
if (version != 0)
95+
return version;
96+
97+
if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3)
98+
return 0;
99+
100+
return KERNEL_VERSION(major, minor, patch);
101+
}
102+
20103
static int probe_prog_load(enum bpf_prog_type prog_type,
21104
const struct bpf_insn *insns, size_t insns_cnt,
22105
char *log_buf, size_t log_buf_sz)

0 commit comments

Comments
 (0)