XDP加载失败:libbpf: failed to find valid kernel BTF
,内核 BTF 未找到或不可用
报错:
$ sudo ip link set dev eth0 xdp obj xdp.bpf.o sec xdp libbpf
libbpf: failed to find valid kernel BTF
libbpf: Error loading vmlinux BTF: -3
libbpf: failed to load object 'xdp.bpf.o'
解决办法:
1、升级内核*(行不通)
# Ubuntu/Debian
sudo apt install linux-image-5.15.0-78-generic
sudo reboot
原因:由于缺少有效的内核BTF(BPF Type Format)信息。BTF是BPF程序所需的内核调试符号信息,用于帮助加载和执行BPF程序。该错误表明 libbpf
无法找到有效的内核BTF,或者在加载BTF时发生了错误。
2、启用内核编译。
2.1检查是否有btf
ls /sys/kernel/btf #如果该目录下没有文件,表示当前内核没有BTF信息
2.2安装 linux-headers
和 BTF
文件
sudo apt-get install linux-headers-$(uname -r)
2.3 使用 bpftool
获取BTF信息
sudo bpftool btf dump file /sys/kernel/btf/vmlinux #这会将BTF信息转储到指定的文件,如果没有要重新编译内核
2.4 使用 objcopy
提取BTF信息
pahole -J vmlinux #pahole 是一个专门用来生成BTF符号的工具。生成的BTF文件可以在加载BPF程序时作为参数传递给 libbpf,,如果你有内核的vmlinux文件(通常位于/usr/src/linux/下)
报错:$ pahole -J vmlinux
Command 'pahole' not found, but can be installed with: sudo apt install pahole
解决:sudo apt install pahole
继续执行:pahole -J vmlinux
报错:pahole: vmlinux: Invalid argument
2.5 vmlinux
文件是从内核源代码编译生成的,它包含了内核的符号信息,通常用于调试和分析BPF程序。系统上没有 vmlinux
文件,并且没有安装内核源代码,按照以下步骤获取并编译它。
sudo apt-get install linux-source
2.6 解压文件
sudo tar -xjf linux-source-5.15.0.tar.bz2
2.7进入解压后的的内核源代码目录
cd /usr/src/linux-source-5.15.0
2.8 安装依赖包
sudo apt-get install build-essential libncurses-dev bison flex libssl-dev
2.9初始化内核
sudo make defconfig #初始化内核配置
报错:
wei@wei-virtual-machine:/usr/src/linux-source-5.15.0/linux-source-5.15.0$ sudo make defconfig HOSTCC scripts/basic/fixdep HOSTCC scripts/kconfig/conf.o HOSTCC scripts/kconfig/confdata.o HOSTCC scripts/kconfig/expr.o LEX scripts/kconfig/lexer.lex.c /bin/sh: 1: flex: not found make[1]: *** [scripts/Makefile.host:9: scripts/kconfig/lexer.lex.c] Error 127 make: *** [Makefile:630: defconfig] Error
解决:
sudo apt-get install flex
如果遇到其他类似的错误,可能是因为缺少其他编译工具。你可以通过安装常见的编译工具来解决这些问题:
sudo apt-get install build-essential libncurses-dev bison flex libssl-dev
3 配置内核
make menuconfig
#配置菜单中依次选择下面的选项
Kernel hacking -> Compile-time checks and compiler options -> Compile the kernel with debug info (CONFIG_DEBUG_INFO)
#Compile the kernel with debug info菜单下面选择与BTF有关的选项。最后保存,退出。
4 编译内核
sudo make
报错:
CC security/selinux/avc.o
CC security/selinux/hooks.o
CC security/selinux/selinuxfs.o
security/selinux/selinuxfs.c: In function ‘exit_sel_fs’:
security/selinux/selinuxfs.c:2260:22: error: ‘selinuxfs_mount’ undeclared (first use in this function)
2260 | kern_unmount(selinuxfs_mount);
| ^~~~~~~~~~~~~~~
security/selinux/selinuxfs.c:2260:22: note: each undeclared identifier is reported only once for each function it appears in
make[2]: *** [scripts/Makefile.build:297: security/selinux/selinuxfs.o] Error 1
make[1]: *** [scripts/Makefile.build:560: security/selinux] Error 2
make: *** [Makefile:1910: security] Error 2
解决办法:
# 进入内核源码目录
cd /usr/src/linux-source-5.15.0/linux-source-5.15.0
# 使用 sudo 编辑文件
sudo nano security/selinux/selinuxfs.c
这是selinxfs.c第2257行代码,void exit_sel_fs(void)
{
sysfs_remove_mount_point(fs_kobj, "selinux");
dput(selinux_null.dentry);
kern_unmount(selinuxfs_mount);
unregister_filesystem(&sel_fs_type);
把上面(selinuxfs_mount)修改成selinux_fs_mount)
保存退出。
还要继续找到kern_unmount(selinuxfs_mount);将其修改为:
kern_unmount(selinux_fs_mount);
#直接使用命令修改:
wei@wei-virtual-machine:/usr/src/linux-source-5.15.0/linux-source-5.15.0/security/selinux$ sudo sed -i 's/kern_unmount(selinuxfs_mount);/kern_unmount(selinux_fs_mount),/' selinuxfs.c
以上修改后又报错:
变量没有声明。
void exit_sel_fs(void)
{
sysfs_remove_mount_point(fs_kobj, "selinux");
dput(selinux_null.dentry);
kern_unmount(selinuxfs_mount);
unregister_filesystem(&sel_fs_type);保留源代码中的命名selinuxfs_mount。下面进行代码声明:
直接在void exit_sel_fs(void)前面加一行声明:static struct selinux_fs_info *selinux_fs_info;
出现报错:
security/selinux/selinuxfs.c: In function ‘exit_sel_fs’: security/selinux/selinuxfs.c:2259:22: error: passing argument 1 of ‘kern_unmount’ from incompatible pointer type [-Werror=incompatible-pointer-types] 2259 | kern_unmount(selinuxfs_mount); | ^~~~~~~~~~~~~~~ | | | struct super_block * In file included from ./include/linux/huge_mm.h:8, from ./include/linux/mm.h:727, from ./include/linux/pagemap.h:8, from security/selinux/selinuxfs.c:16: ./include/linux/fs.h:2617:43: note: expected ‘struct vfsmount *’ but argument is of type ‘struct super_block *’ 2617 | extern void kern_unmount(struct vfsmount *mnt); | ~~~~~~~~~~~~~~~
^CC arch/x86/kernel/traps.o CC mm/interval_tree.o CC fs/proc/version.o CC crypto/proc.o CC fs/proc/softirqs.o CC security/integrity/iint.o CC crypto/aead.o CC kernel/dma/direct.o cc1: some warnings being treated as errors make[2]: *** [scripts/Makefile.build:297: security/selinux/selinuxfs.o] Error 1 make[1]: *** [scripts/Makefile.build:560: security/selinux] Error 2又又报错
在Linux内核代码中,要声明一个
struct vfsmount
类型的变量,通常需要包含相应的头文件,并按照内核的命名约定进行声明。以下是如何声明selinuxfs_mount
变量
1、检查selinuxfs.c文件开头确保有:
#include <linux/fs.h>
#include <linux/mount.h>
2、在全局或模块级别声明selinuxfs_mount
变量:struct vfsmount *selinuxfs_mount;
3、找到最后面代码,修改成:
void exit_sel_fs(void) { sysfs_remove_mount_point(fs_kobj, "selinux"); dput(selinux_null.dentry); // 确保在调用kern_unmount之前,selinuxfs_mount已经正确初始化 if (selinuxfs_mount) { kern_unmount(selinuxfs_mount); } unregister_filesystem(&sel_fs_type); }
继续编译:
# 清理旧编译产物 make clean # 重新编译 make -j$(nproc)
成功编译,没有报错!
这是selinux文件目录:
4.1 安装内核模块和生成BTF
sudo make modules_install
sudo make install
4.2 内核模块生成了 BTF 信息