Skip to content

Commit 5b3d729

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
libbpf: Improve LINUX_VERSION_CODE detection
Ubuntu reports incorrect kernel version through uname(), which on older kernels leads to kprobe BPF programs failing to load due to the version check mismatch. Accommodate Ubuntu's quirks with LINUX_VERSION_CODE by using Ubuntu-specific /proc/version_code to fetch major/minor/patch versions to form LINUX_VERSION_CODE. While at it, consolide libbpf's kernel version detection code between libbpf.c and libbpf_probes.c. [0] Closes: libbpf/libbpf#421 Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/bpf/20211222231003.2334940-1-andrii@kernel.org
1 parent f60edf5 commit 5b3d729

File tree

3 files changed

+28
-17
lines changed

3 files changed

+28
-17
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,11 +795,36 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
795795
return 0;
796796
}
797797

798-
static __u32 get_kernel_version(void)
798+
__u32 get_kernel_version(void)
799799
{
800+
/* On Ubuntu LINUX_VERSION_CODE doesn't correspond to info.release,
801+
* but Ubuntu provides /proc/version_signature file, as described at
802+
* https://ubuntu.com/kernel, with an example contents below, which we
803+
* can use to get a proper LINUX_VERSION_CODE.
804+
*
805+
* Ubuntu 5.4.0-12.15-generic 5.4.8
806+
*
807+
* In the above, 5.4.8 is what kernel is actually expecting, while
808+
* uname() call will return 5.4.0 in info.release.
809+
*/
810+
const char *ubuntu_kver_file = "/proc/version_signature";
800811
__u32 major, minor, patch;
801812
struct utsname info;
802813

814+
if (access(ubuntu_kver_file, R_OK) == 0) {
815+
FILE *f;
816+
817+
f = fopen(ubuntu_kver_file, "r");
818+
if (f) {
819+
if (fscanf(f, "%*s %*s %d.%d.%d\n", &major, &minor, &patch) == 3) {
820+
fclose(f);
821+
return KERNEL_VERSION(major, minor, patch);
822+
}
823+
fclose(f);
824+
}
825+
/* something went wrong, fall back to uname() approach */
826+
}
827+
803828
uname(&info);
804829
if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3)
805830
return 0;

tools/lib/bpf/libbpf_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ static inline void libbpf_strlcpy(char *dst, const char *src, size_t sz)
188188
dst[i] = '\0';
189189
}
190190

191+
__u32 get_kernel_version(void);
192+
191193
struct btf;
192194
struct btf_type;
193195

tools/lib/bpf/libbpf_probes.c

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,6 @@ static int get_vendor_id(int ifindex)
4848
return strtol(buf, NULL, 0);
4949
}
5050

51-
static int get_kernel_version(void)
52-
{
53-
int version, subversion, patchlevel;
54-
struct utsname utsn;
55-
56-
/* Return 0 on failure, and attempt to probe with empty kversion */
57-
if (uname(&utsn))
58-
return 0;
59-
60-
if (sscanf(utsn.release, "%d.%d.%d",
61-
&version, &subversion, &patchlevel) != 3)
62-
return 0;
63-
64-
return (version << 16) + (subversion << 8) + patchlevel;
65-
}
66-
6751
static int probe_prog_load(enum bpf_prog_type prog_type,
6852
const struct bpf_insn *insns, size_t insns_cnt,
6953
char *log_buf, size_t log_buf_sz,

0 commit comments

Comments
 (0)