From: Daniel Borkmann <daniel@iogearbox.net> mainline inclusion from mainline-v6.18-rc1 commit 0e8e60e86cf3292e747a0fa7cc13127f290323ad category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/ID6BAQ CVE: CVE-2025-40123 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Add a small test case which adds two programs - one calling the other through a tailcall - and check that BPF rejects them in case of different expected_attach_type values: # ./vmtest.sh -- ./test_progs -t xdp_devmap [...] #641/1 xdp_devmap_attach/DEVMAP with programs in entries:OK #641/2 xdp_devmap_attach/DEVMAP with frags programs in entries:OK #641/3 xdp_devmap_attach/Verifier check of DEVMAP programs:OK #641/4 xdp_devmap_attach/DEVMAP with programs in entries on veth:OK #641 xdp_devmap_attach:OK Summary: 2/4 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/r/20250926171201.188490-2-daniel@iogearbox.net Signed-off-by: Alexei Starovoitov <ast@kernel.org> Conflicts: tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.c tools/testing/selftests/bpf/progs/test_xdp_devmap_tailcall.c tools/testing/selftests/bpf/progs/xdp_tailcall_devmap.c [The static initialization feature in the test case was introduced by commit 341ac5ffc4bd ("libbpf: Support static initialization of BPF_MAP_TYPE_PROG_ARRAY") and is not currently supported in the present version. Directly backporting this patch would result in significant conflicts. Therefore, the test case has been refactored. The modifications include: 1. Splitting the test case into two separate files to be loaded individually—the first load is used to add map elements, while the second load is used for testing; 2. Adjusting the return value judgment logic of the first load based on the prog_dev parameter to accommodate verifier rejection issues (version 6.6 also encounters verifier rejection problems).] Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- .../bpf/prog_tests/xdp_devmap_attach.c | 62 ++++++++++++++++++- .../bpf/progs/test_xdp_devmap_tailcall.c | 18 ++++++ .../selftests/bpf/progs/xdp_tailcall_devmap.c | 19 ++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/progs/test_xdp_devmap_tailcall.c create mode 100644 tools/testing/selftests/bpf/progs/xdp_tailcall_devmap.c diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.c b/tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.c index 88ef3ec8ac4c..572616eff047 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.c @@ -4,6 +4,8 @@ #include <test_progs.h> #include "test_xdp_devmap_helpers.skel.h" +#include "test_xdp_devmap_tailcall.skel.h" +#include "xdp_tailcall_devmap.skel.h" #include "test_xdp_with_devmap_helpers.skel.h" #define IFINDEX_LO 1 @@ -78,12 +80,70 @@ void test_neg_xdp_devmap_helpers(void) } } +static void test_xdp_devmap_tailcall(enum bpf_attach_type prog_dev, + enum bpf_attach_type prog_tail, + bool expect_reject) +{ + struct test_xdp_devmap_tailcall *skel = NULL; + struct xdp_tailcall_devmap *tailcall_skel = NULL; + __u32 duration = 0, zero = 0; + int err, map_fd, prog_fd; + + skel = test_xdp_devmap_tailcall__open(); + if (!ASSERT_OK_PTR(skel, "test_xdp_devmap_tailcall__open")) + return; + + bpf_program__set_expected_attach_type(skel->progs.xdp_devmap, prog_dev); + err = test_xdp_devmap_tailcall__load(skel); + if (prog_dev == BPF_XDP_DEVMAP) { + if (!ASSERT_OK(err, "test_xdp_devmap_tailcall__load")) + goto out_close; + } else { + /* + * Will be rejected by verifier due to xdp_is_valid_access + * failure, because programs with expected_attach_type + * other than BPF_XDP_DEVMAP are not allowed to obtain + * ctx->egress_ifindex. + */ + ASSERT_ERR(err, "test_xdp_devmap_tailcall__load"); + goto out_close; + } + + map_fd = bpf_map__fd(skel->maps.xdp_map); + prog_fd = bpf_program__fd(skel->progs.xdp_devmap); + err = bpf_map_update_elem(map_fd, &zero, &prog_fd, BPF_ANY); + CHECK(err, "Add program to devmap entry", + "err %d errno %d\n", err, errno); + + tailcall_skel = xdp_tailcall_devmap__open(); + if (!ASSERT_OK_PTR(tailcall_skel, "xdp_tailcall_devmap__open")) + goto out_close; + + bpf_map__reuse_fd(tailcall_skel->maps.xdp_map, map_fd); + bpf_program__set_expected_attach_type(tailcall_skel->progs.xdp_entry, + prog_tail); + + err = xdp_tailcall_devmap__load(tailcall_skel); + if (expect_reject) + ASSERT_ERR(err, "xdp_tailcall_devmap__load"); + else + ASSERT_OK(err, "xdp_tailcall_devmap__load"); + +out_close: + test_xdp_devmap_tailcall__destroy(skel); + xdp_tailcall_devmap__destroy(tailcall_skel); +} void test_xdp_devmap_attach(void) { if (test__start_subtest("DEVMAP with programs in entries")) test_xdp_with_devmap_helpers(); - if (test__start_subtest("Verifier check of DEVMAP programs")) + if (test__start_subtest("Verifier check of DEVMAP programs")) { test_neg_xdp_devmap_helpers(); + test_xdp_devmap_tailcall(BPF_XDP_DEVMAP, BPF_XDP_DEVMAP, false); + test_xdp_devmap_tailcall(0, 0, true); + test_xdp_devmap_tailcall(BPF_XDP_DEVMAP, 0, true); + test_xdp_devmap_tailcall(0, BPF_XDP_DEVMAP, true); + } } diff --git a/tools/testing/selftests/bpf/progs/test_xdp_devmap_tailcall.c b/tools/testing/selftests/bpf/progs/test_xdp_devmap_tailcall.c new file mode 100644 index 000000000000..e4f203142c4e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xdp_devmap_tailcall.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +struct { + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); + __uint(max_entries, 1); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u32)); +} xdp_map SEC(".maps"); + +SEC("xdp") +int xdp_devmap(struct xdp_md *ctx) +{ + return ctx->egress_ifindex; +} diff --git a/tools/testing/selftests/bpf/progs/xdp_tailcall_devmap.c b/tools/testing/selftests/bpf/progs/xdp_tailcall_devmap.c new file mode 100644 index 000000000000..a047c2266182 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/xdp_tailcall_devmap.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +struct { + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); + __uint(max_entries, 1); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u32)); +} xdp_map SEC(".maps"); + +SEC("xdp") +int xdp_entry(struct xdp_md *ctx) +{ + bpf_tail_call(ctx, &xdp_map, 0); + return 0; +} -- 2.34.1