bpfilter umh导致的libc依赖问题

Linux 4.18开始支持bpfilter,用于代替netfilter,其工作原理见下图:

bpfilter umh导致的libc依赖问题_第1张图片
bpfilter

可以看到bpfilter需要一个UMH(User Module Helper)实现eBPF的规则转换,这个UMH是需要运行在用户空间的。在内核源码下的net/bpfilter可以看到以下文件:

.
├── bpfilter_kern.c
├── bpfilter_umh_blob.S
├── Kconfig
├── main.c
├── Makefile
└── msgfmt.h

其中,main.c就是要在用户空间运行的bpfilter_umh的源代码,main.c将编译成net/bpfilter/bpfilter_umh,然后在bpfilter_umh_blob.S里面用incbin将编译好的bpfilter_umh包进去:

/* net/bpfilter/bpfilter_umh_blob.S */

/* SPDX-License-Identifier: GPL-2.0 */
    .section .init.rodata, "a"
    .global bpfilter_umh_start
bpfilter_umh_start:
    .incbin "net/bpfilter/bpfilter_umh"
    .global bpfilter_umh_end
bpfilter_umh_end:

bpfilter在加载的时候将bpfilter_umh fork到用户空间里运行:

/* net/bpfilter/bpfilter_kern.c */

static int __init load_umh(void)
{
    int err;

    /* fork usermode process */
    err = fork_usermode_blob(&bpfilter_umh_start,
                 &bpfilter_umh_end - &bpfilter_umh_start,
                 &info);
    if (err)
        return err;
    pr_info("Loaded bpfilter_umh pid %d\n", info.pid);

    /* health check that usermode process started correctly */
    if (__bpfilter_process_sockopt(NULL, 0, 0, 0, 0) != 0) {
        stop_umh();
        return -EFAULT;
    }
    if (IS_ENABLED(CONFIG_INET))
        bpfilter_process_sockopt = &__bpfilter_process_sockopt;

    return 0;
}
# net/bpfilter/Kconfig

menuconfig BPFILTER
    bool "BPF based packet filtering framework (BPFILTER)"
    depends on NET && BPF && INET
    help
      This builds experimental bpfilter framework that is aiming to
      provide netfilter compatible functionality via BPF

if BPFILTER
config BPFILTER_UMH
    tristate "bpfilter kernel module with user mode helper"
    depends on $(success,$(srctree)/scripts/cc-can-link.sh $(CC))
    default m
    help
      This builds bpfilter kernel module with embedded user mode helper
endif

要特别注意的是,在Kconfig中,如果CONFIG_BPFILTER_UMHm,那么bpfilter_umh将不会使用静态链接的方式编译,这样一来,如果目标系统使用的libc与编译内核的工具链使用的libc差距过大的话,会导致bpfilter_umh无法工作,也就意味着bpfilter模块无法装载。

例如,使用glibc的工具链编译的启用bpfilter支持的内核,放在musl环境的OpenWrt中,由于C库不同致使bpfilter_umh无法运行,bpfilter模块也就不能加载,最终导致iptables报错:

root@OpenWrt:~# iptables -L
iptables v1.6.2: can't initialize iptables table `filter': No child process

为了解决这个问题,需要将CONFIG_BPFILTER_UMH设定为y,这样会给bpfilter_umh添加-static的链接参数(静态链接),就不会产生libc的依赖问题了。

你可能感兴趣的:(bpfilter umh导致的libc依赖问题)