XDP program ip link error: Prog section rejected: Operation not permitted

XDP program ip link error: Prog section rejected: Operation not permitted

我尝试进入 XDP,为此我有这个非常小的程序:

// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include "bpf/bpf_helpers.h"
#include "xdpsock.h"

struct {
    __uint(type, BPF_MAP_TYPE_ARRAY);
    __uint(max_entries, MAX_SOCKS);
    __uint(key_size, sizeof(int));
    __uint(value_size, sizeof(int));
} xsks_map SEC(".maps");

SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx) {

    return XDP_DROP;
}

但是如果我尝试将它加载到虚拟接口 veth-basic02,我会得到这个错误:

$ sudo ip -force link set dev veth-basic02 xdp object xdpsock_kern.o section xdp_sock

Prog section 'xdp_sock' rejected: Operation not permitted (1)! - Type: 6 - Instructions: 2 (0 over limit) - License:

Verifier analysis:

Error fetching program/map!

内核版本:5.3.0-28-generic

这是我正在使用的 Makefile:

OBJS = xdpsock_kern.o

LLC ?= llc
CLANG ?= clang
INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`
EXTRA_CFLAGS ?= -O2 -emit-llvm

# In case up-to-date headers are not installed locally in /usr/include,
# use source build.

linuxhdrs ?= /usr/src/linux-headers-5.1.0-050100

LINUXINCLUDE =  -I$(linuxhdrs)/arch/x86/include/uapi \
                -I$(linuxhdrs)/arch/x86/include/generated/uapi \
                -I$(linuxhdrs)/include/generated/uapi \
                -I$(linuxhdrs)/include/uapi \
                -I$(linuxhdrs)/include  \
                -I/bpf

prefix ?= /usr/local

INSTALLPATH = $(prefix)/lib/bpf

install_PROGRAM = install
install_DIR = install -dv

all:    $(OBJS)

.PHONY: clean

clean:
    rm -f $(OBJS)

INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`

$(OBJS):  %.o:%.c
    $(CLANG) $(INC_FLAGS) \
                -D__KERNEL__ -D__ASM_SYSREG_H \
                -Wno-unused-value -Wno-pointer-sign \
                -Wno-compare-distinct-pointer-types \
                -Wno-gnu-variable-sized-type-not-at-end \
                -Wno-address-of-packed-member -Wno-tautological-compare \
                -Wno-unknown-warning-option \
                -I../include $(LINUXINCLUDE) \
                $(EXTRA_CFLAGS) -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@

install: $(OBJS)
    $(install_DIR) -d $(INSTALLPATH) ; \
    $(install_PROGRAM) $^ -t $(INSTALLPATH)

uninstall: $(OBJS)
    rm -rf $(INSTALLPATH)

封锁:

$ dmesg | grep Lockdown
[    1.283355] Lockdown: swapper/0: Hibernation is restricted; see man kernel_lockdown.7
[   11.313219] Lockdown: systemd: /dev/mem,kmem,port is restricted; see man kernel_lockdown.7
[   11.337794] Lockdown: systemd: BPF is restricted; see man kernel_lockdown.7
[   17.147844] Lockdown: Xorg: ioperm is restricted; see man kernel_lockdown.7

编辑: echo 1 > /proc/sys/kernel/sysrq + echo x > /proc/sysrq-trigger + Alt+SysRq+x 确实解决了问题 - 我终于可以加载 XDP 程序了!有趣的复活节彩蛋。谢谢@Qeole!

eBPF:不允许操作

在使用 eBPF 时,有几种可能的权限错误(bpf() 返回 -EPERM,您可以通过 strace -e bpf <command> 观察)。但没有那么多。通常,它们属于以下项目之一:

  • 用户不具备所需的能力CAP_SYS_ADMINCAP_NET_ADMIN、...通常取决于使用的程序)。这通常由 运行ning 作为 root 解决,他拥有所有必要的能力。在你的情况下,你 运行 和 sudo,所以你被覆盖了。

  • 创建 BPF 对象(新映射或加载程序)会超出内核中可锁定内存量的限制用户。这通常通过在终端中使用 ulimit -l <something_big> 或在 C 程序中使用 setrlimit() 来解决(对于 root。你的情况不太可能,你的程序非常小,你没有提到在你的系统上加载了很多 BPF 对象。

  • 还有一些可能性,比如尝试在“冻结”或只读的地图上书写等,或者尝试为非root 用户 使用函数调用。这些通常用于更高级的用例,不应该被像您这样简单的程序击中。

针对 bpf() 限制的锁定、安全启动、EFI 和(不幸的)向后移植

但是您遇到的问题可能与其他问题有关。 “Lockdown”是一个安全模块,已合并到 Linux 5.5 内核中。它旨在防止用户修改 运行ning Linux 图像。事实证明,一些发行版决定将 Lockdown 向后移植到他们的内核中,有时他们会选择早于合并到主线 Linux 的最终版本的补丁。

Ubuntu 和 Fedora,例如,有 a bunch of custom patches to backport that feature to the kernels used in Disco/19.04 and Eoan/19.10 (kernel 5.3 for the latter, I don't remember for Disco). It includes a patch that completely disables the bpf() system call when Lockdown is activated, meaning that creating maps or loading BPF programs is not possible. Also, they enabled Lockdown by default when Secure Boot is activated,我认为这是使用 EFI 引导的机器的默认值。

另见 this blog post:检查 Lockdown 是否影响 BPF 使用的一个好方法是尝试加载最小程序,或者到 运行 dmesg | grep Lockdown 看看它是否说类似于:

Lockdown: systemd: BPF is restricted; see man kernel_lockdown.7

因此,对于 Ubuntu 19.04 和 19.10,例如,您必须禁用锁定才能使用 eBPF。对于此操作,这可以通过 SysRq key + x (I have not tested), but NOT by writing to /proc/sysrq-trigger (Ubuntu disabled it 的物理笔划来完成)。或者,您可以禁用安全启动(在 BIOS 中或使用 mokutil,在 Internet 上搜索相关选项,并且不要忘记检查安全隐患)。

请注意 Linux 内核 5.4 或最新版本具有 mainline restrictions for bpf(), which do not deactivate the system call, so Focal/20.04 and newest will not be affected. Upgrading to a new kernel might thus be another workaround. I filed a ticket a few days ago to ask for this change to be backported (instead of deactivating bpf()) and the work is in progress, so by the time new readers look at the answer Lockdown impact on eBPF might well be mitigated (Edit: Should be fixed on Ubuntu 19.10 with kernel 5.3.0-43). Not sure how other distros handle this. And it will still have strong implications for tracing with eBPF