[PATCH OLK-5.10 0/2] Fix CVE-2025-40123
Fix CVE-2025-40123. Daniel Borkmann (2): bpf: Enforce expected_attach_type for tailcall compatibility selftests/bpf: Add test case for different expected_attach_type include/linux/bpf.h | 1 + kernel/bpf/core.c | 5 ++ .../bpf/prog_tests/xdp_devmap_attach.c | 62 ++++++++++++++++++- .../bpf/progs/test_xdp_devmap_tailcall.c | 18 ++++++ .../selftests/bpf/progs/xdp_tailcall_devmap.c | 19 ++++++ 5 files changed, 104 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 -- 2.34.1
From: Daniel Borkmann <daniel@iogearbox.net> mainline inclusion from mainline-v6.18-rc1 commit 4540aed51b12bc13364149bf95f6ecef013197c0 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... -------------------------------- Yinhao et al. recently reported: Our fuzzer tool discovered an uninitialized pointer issue in the bpf_prog_test_run_xdp() function within the Linux kernel's BPF subsystem. This leads to a NULL pointer dereference when a BPF program attempts to deference the txq member of struct xdp_buff object. The test initializes two programs of BPF_PROG_TYPE_XDP: progA acts as the entry point for bpf_prog_test_run_xdp() and its expected_attach_type can neither be of be BPF_XDP_DEVMAP nor BPF_XDP_CPUMAP. progA calls into a slot of a tailcall map it owns. progB's expected_attach_type must be BPF_XDP_DEVMAP to pass xdp_is_valid_access() validation. The program returns struct xdp_md's egress_ifindex, and the latter is only allowed to be accessed under mentioned expected_attach_type. progB is then inserted into the tailcall which progA calls. The underlying issue goes beyond XDP though. Another example are programs of type BPF_PROG_TYPE_CGROUP_SOCK_ADDR. sock_addr_is_valid_access() as well as sock_addr_func_proto() have different logic depending on the programs' expected_attach_type. Similarly, a program attached to BPF_CGROUP_INET4_GETPEERNAME should not be allowed doing a tailcall into a program which calls bpf_bind() out of BPF which is only enabled for BPF_CGROUP_INET4_CONNECT. In short, specifying expected_attach_type allows to open up additional functionality or restrictions beyond what the basic bpf_prog_type enables. The use of tailcalls must not violate these constraints. Fix it by enforcing expected_attach_type in __bpf_prog_map_compatible(). Note that we only enforce this for tailcall maps, but not for BPF devmaps or cpumaps: There, the programs are invoked through dev_map_bpf_prog_run*() and cpu_map_bpf_prog_run*() which set up a new environment / context and therefore these situations are not prone to this issue. Fixes: 5e43f899b03a ("bpf: Check attach type at prog load time") Reported-by: Yinhao Hu <dddddd@hust.edu.cn> Reported-by: Kaiyan Mei <M202472210@hust.edu.cn> Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/r/20250926171201.188490-1-daniel@iogearbox.net Signed-off-by: Alexei Starovoitov <ast@kernel.org> Conflicts: kernel/bpf/core.c include/linux/bpf.h [Just context conflicts] Signed-off-by: Tengda Wu <wutengda2@huawei.com> --- include/linux/bpf.h | 1 + kernel/bpf/core.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index bd435b20bca1..4e6955bf06e7 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -179,6 +179,7 @@ struct bpf_map_owner { bool jited; u64 storage_cookie[MAX_BPF_CGROUP_STORAGE_TYPE]; const struct btf_type *attach_func_proto; + enum bpf_attach_type expected_attach_type; }; struct bpf_map { diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 4d72a8651de5..6abc58b682a4 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -1794,6 +1794,7 @@ bool bpf_prog_map_compatible(struct bpf_map *map, map->owner->type = prog_type; map->owner->jited = fp->jited; map->owner->attach_func_proto = aux->attach_func_proto; + map->owner->expected_attach_type = fp->expected_attach_type; for_each_cgroup_storage_type(i) { map->owner->storage_cookie[i] = aux->cgroup_storage[i] ? @@ -1803,6 +1804,10 @@ bool bpf_prog_map_compatible(struct bpf_map *map, } else { ret = map->owner->type == prog_type && map->owner->jited == fp->jited; + if (ret && + map->map_type == BPF_MAP_TYPE_PROG_ARRAY && + map->owner->expected_attach_type != fp->expected_attach_type) + ret = false; for_each_cgroup_storage_type(i) { if (!ret) break; -- 2.34.1
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
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/19102 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/66A... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/19102 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/66A...
participants (2)
-
patchwork bot -
Tengda Wu