Add tests to verify the issues: * xdp_has_frags: The backwards compatibility can be broken via freplace. * kprobe_write_ctx: It can be abused to modify struct pt_regs of kernel functions via kprobe_write_ctx=true freplace progs.
Without the fixes, the issues are verified: xdp_has_frags=true freplace prog is allowed to attach to xdp_has_frags=false XDP prog. kprobe_write_ctx=true freplace prog is allowed to attach to kprobe_write_ctx=false kprobe prog. Then, the first arg of bpf_fentry_test1 will be set as 0, and bpf_prog_test_run_opts() gets -EFAULT instead of 0. With the fixes, the issues are rejected by verifier: Extension program cannot have different xdp_has_frags value with target prog #134/1 freplace_compatible/xdp_has_frags:OK Extension program cannot have different kprobe_write_ctx value with target prog #134/2 freplace_compatible/kprobe_write_ctx:OK Signed-off-by: Leon Hwang <[email protected]> --- .../bpf/prog_tests/freplace_compatible.c | 124 ++++++++++++++++++ .../selftests/bpf/progs/freplace_compatible.c | 40 ++++++ 2 files changed, 164 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/freplace_compatible.c create mode 100644 tools/testing/selftests/bpf/progs/freplace_compatible.c diff --git a/tools/testing/selftests/bpf/prog_tests/freplace_compatible.c b/tools/testing/selftests/bpf/prog_tests/freplace_compatible.c new file mode 100644 index 000000000000..251e17ef4e52 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/freplace_compatible.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <test_progs.h> +#include "freplace_compatible.skel.h" + +static void test_xdp_has_frags(void) +{ + struct freplace_compatible *skel_xdp, *skel_ext = NULL; + struct bpf_program *prog_xdp, *prog_ext; + struct bpf_link *link = NULL; + char buff[128] = {}; + int err, prog_fd; + __u32 flags; + LIBBPF_OPTS(bpf_test_run_opts, topts, + .data_in = buff, + .data_size_in = sizeof(buff), + .repeat = 1, + ); + + skel_xdp = freplace_compatible__open(); + if (!ASSERT_OK_PTR(skel_xdp, "freplace_compatible__open xdp")) + return; + + prog_xdp = skel_xdp->progs.xdp; + bpf_program__set_autoload(prog_xdp, true); + + err = freplace_compatible__load(skel_xdp); + if (!ASSERT_OK(err, "freplace_compatible__load xdp")) + goto out; + + skel_ext = freplace_compatible__open(); + if (!ASSERT_OK_PTR(skel_ext, "freplace_compatible__open ext")) + goto out; + + prog_ext = skel_ext->progs.freplace_xdp; + bpf_program__set_autoload(prog_ext, true); + + flags = bpf_program__flags(prog_ext) | BPF_F_XDP_HAS_FRAGS; + bpf_program__set_flags(prog_ext, flags); + + prog_fd = bpf_program__fd(prog_xdp); + bpf_program__set_attach_target(prog_ext, prog_fd, "xdp"); + + err = freplace_compatible__load(skel_ext); + ASSERT_ERR(err, "freplace_compatible__load ext"); + + link = bpf_program__attach_freplace(prog_ext, prog_fd, "xdp"); + ASSERT_ERR_PTR(link, "bpf_program__attach_freplace"); + + err = bpf_prog_test_run_opts(prog_fd, &topts); + if (!ASSERT_OK(err, "bpf_prog_test_run_opts")) + goto out; + + ASSERT_EQ(topts.retval, XDP_PASS, "xdp retval"); + +out: + bpf_link__destroy(link); + freplace_compatible__destroy(skel_ext); + freplace_compatible__destroy(skel_xdp); +} + +#ifdef __x86_64__ +static void test_kprobe_write_ctx(void) +{ + struct freplace_compatible *skel_kprobe, *skel_ext = NULL; + struct bpf_program *prog_kprobe, *prog_ext, *prog_fentry; + struct bpf_link *link_kprobe = NULL, *link_ext = NULL; + int err; + LIBBPF_OPTS(bpf_kprobe_opts, kprobe_opts); + LIBBPF_OPTS(bpf_test_run_opts, topts); + + skel_kprobe = freplace_compatible__open(); + if (!ASSERT_OK_PTR(skel_kprobe, "freplace_compatible__open kprobe")) + return; + + prog_kprobe = skel_kprobe->progs.kprobe; + bpf_program__set_autoload(prog_kprobe, true); + + prog_fentry = skel_kprobe->progs.fentry; + bpf_program__set_autoload(prog_fentry, true); + + err = freplace_compatible__load(skel_kprobe); + if (!ASSERT_OK(err, "freplace_compatible__load kprobe")) + goto out; + + skel_ext = freplace_compatible__open(); + if (!ASSERT_OK_PTR(skel_ext, "freplace_compatible__open ext")) + goto out; + + prog_ext = skel_ext->progs.freplace_kprobe; + bpf_program__set_autoload(prog_ext, true); + + bpf_program__set_attach_target(prog_ext, bpf_program__fd(prog_kprobe), "kprobe"); + + err = freplace_compatible__load(skel_ext); + ASSERT_ERR(err, "freplace_compatible__load ext"); + + link_ext = bpf_program__attach_freplace(prog_ext, 0, NULL); + ASSERT_ERR_PTR(link_ext, "bpf_program__attach_freplace"); + + link_kprobe = bpf_program__attach_kprobe_opts(prog_kprobe, "bpf_fentry_test1", + &kprobe_opts); + if (!ASSERT_OK_PTR(link_kprobe, "bpf_program__attach_kprobe_opts")) + goto out; + + err = bpf_prog_test_run_opts(bpf_program__fd(prog_fentry), &topts); + ASSERT_OK(err, "bpf_prog_test_run_opts"); + +out: + bpf_link__destroy(link_ext); + bpf_link__destroy(link_kprobe); + freplace_compatible__destroy(skel_ext); + freplace_compatible__destroy(skel_kprobe); +} +#endif + +void test_freplace_compatible(void) +{ + if (test__start_subtest("xdp_has_frags")) + test_xdp_has_frags(); +#ifdef __x86_64__ + if (test__start_subtest("kprobe_write_ctx")) + test_kprobe_write_ctx(); +#endif +} diff --git a/tools/testing/selftests/bpf/progs/freplace_compatible.c b/tools/testing/selftests/bpf/progs/freplace_compatible.c new file mode 100644 index 000000000000..f13b4878268b --- /dev/null +++ b/tools/testing/selftests/bpf/progs/freplace_compatible.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +SEC("?xdp") +int xdp(struct xdp_md *ctx) +{ + return XDP_PASS; +} + +SEC("?freplace") +int freplace_xdp(struct xdp_md *ctx) +{ + return 0xFF; +} + +#if defined(__TARGET_ARCH_x86) +SEC("?kprobe") +int kprobe(struct pt_regs *regs) +{ + return 0; +} + +SEC("?freplace") +int freplace_kprobe(struct pt_regs *regs) +{ + regs->di = 0; + return 0; +} + +SEC("?fentry/bpf_fentry_test1") +int BPF_PROG(fentry) +{ + return 0; +} +#endif + +char _license[] SEC("license") = "GPL"; + -- 2.53.0

