Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: https://github.com/libbpf/libbpf/issues/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

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
5b3d7298 f60edf5b

+28 -17
+26 -1
tools/lib/bpf/libbpf.c
··· 795 795 return 0; 796 796 } 797 797 798 - static __u32 get_kernel_version(void) 798 + __u32 get_kernel_version(void) 799 799 { 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"; 800 811 __u32 major, minor, patch; 801 812 struct utsname info; 813 + 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 + } 802 827 803 828 uname(&info); 804 829 if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3)
+2
tools/lib/bpf/libbpf_internal.h
··· 188 188 dst[i] = '\0'; 189 189 } 190 190 191 + __u32 get_kernel_version(void); 192 + 191 193 struct btf; 192 194 struct btf_type; 193 195
-16
tools/lib/bpf/libbpf_probes.c
··· 48 48 return strtol(buf, NULL, 0); 49 49 } 50 50 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 - 67 51 static int probe_prog_load(enum bpf_prog_type prog_type, 68 52 const struct bpf_insn *insns, size_t insns_cnt, 69 53 char *log_buf, size_t log_buf_sz,