On Wed, 2026-07-08 at 02:01 -0700, Sun Jian wrote:
> Add raw tracepoint writable coverage for buffer accesses involving
> negative constant pointer adjustments.
> 
> The verifier case checks that a negative effective offset is rejected.
> The attach-time case adds incremental coverage beyond the existing nbd
> test and the verifier rejection case: it uses a negative var_off and a
> positive instruction offset whose effective offset remains non-negative.
> This exercises the checked access_end accounting path and verifies that
> the resulting max_tp_access is still checked against nbd_send_request's
> writable size at attach time.
> 
> Signed-off-by: Sun Jian <[email protected]>
> ---
>  .../raw_tp_writable_reject_nbd_invalid.c      | 58 +++++++++++--------
>  .../bpf/progs/verifier_raw_tp_writable.c      | 16 +++++
>  2 files changed, 51 insertions(+), 23 deletions(-)
> 
> diff --git 
> a/tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_nbd_invalid.c 
> b/tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_nbd_invalid.c
> index 216b0dfac0fe..efe4cad47b28 100644
> --- 
> a/tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_nbd_invalid.c
> +++ 
> b/tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_nbd_invalid.c
> @@ -4,12 +4,31 @@
>  #include <linux/nbd.h>
>  #include "bpf_util.h"
>  
> -void test_raw_tp_writable_reject_nbd_invalid(void)
> +static void check_nbd_attach_reject(const char *name,
> +                                 const struct bpf_insn *program, size_t 
> prog_len)
>  {
> -     __u32 duration = 0;
> +     LIBBPF_OPTS(bpf_prog_load_opts, opts);
>       char error[4096];
> -     int bpf_fd = -1, tp_fd = -1;
> +     int bpf_fd, tp_fd;
> +
> +     opts.log_level = 2;
> +     opts.log_buf = error;
> +     opts.log_size = sizeof(error);
> +
> +     bpf_fd = bpf_prog_load(BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, NULL, 
> "GPL v2",
> +                            program, prog_len, &opts);
> +     if (!ASSERT_GE(bpf_fd, 0, "prog_load"))
> +             return;
> +
> +     tp_fd = bpf_raw_tracepoint_open("nbd_send_request", bpf_fd);
> +     if (!ASSERT_LT(tp_fd, 0, name))
> +             close(tp_fd);
> +
> +     close(bpf_fd);
> +}
>  
> +void test_raw_tp_writable_reject_nbd_invalid(void)
> +{
>       const struct bpf_insn program[] = {
>               /* r6 is our tp buffer */
>               BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0),
> @@ -19,25 +38,18 @@ void test_raw_tp_writable_reject_nbd_invalid(void)
>               BPF_EXIT_INSN(),
>       };
>  
> -     LIBBPF_OPTS(bpf_prog_load_opts, opts,
> -             .log_level = 2,
> -             .log_buf = error,
> -             .log_size = sizeof(error),
> -     );
> -
> -     bpf_fd = bpf_prog_load(BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, NULL, 
> "GPL v2",
> -                            program, ARRAY_SIZE(program),
> -                            &opts);
> -     if (CHECK(bpf_fd < 0, "bpf_raw_tracepoint_writable load",
> -               "failed: %d errno %d\n", bpf_fd, errno))
> -             return;
> -
> -     tp_fd = bpf_raw_tracepoint_open("nbd_send_request", bpf_fd);
> -     if (CHECK(tp_fd >= 0, "bpf_raw_tracepoint_writable open",
> -               "erroneously succeeded\n"))
> -             goto out_bpffd;
> +     const struct bpf_insn negative_var_off_program[] = {
> +             BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0),
> +             /* make var_off negative, but keep the effective access offset 
> non-negative */
> +             BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8),
> +             /* one byte beyond the end of the nbd_request struct */
> +             BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_6,
> +                         sizeof(struct nbd_request) + 8),
> +             BPF_EXIT_INSN(),
> +     };
>  
> -     close(tp_fd);
> -out_bpffd:
> -     close(bpf_fd);
> +     check_nbd_attach_reject("nbd_invalid", program, ARRAY_SIZE(program));
> +     check_nbd_attach_reject("nbd_invalid_negative_var_off",
> +                             negative_var_off_program,
> +                             ARRAY_SIZE(negative_var_off_program));
>  }

Let's use subtests here:

static void check_nbd_attach_reject(const struct bpf_insn *program, size_t 
prog_len)
{
        LIBBPF_OPTS(bpf_prog_load_opts, opts);
        char error[4096];
        int bpf_fd, tp_fd;

        opts.log_level = 2;
        opts.log_buf = error;
        opts.log_size = sizeof(error);

        bpf_fd = bpf_prog_load(BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, NULL, 
"GPL v2",
                               program, prog_len, &opts);
        if (!ASSERT_GE(bpf_fd, 0, "prog_load"))
                return;

        tp_fd = bpf_raw_tracepoint_open("nbd_send_request", bpf_fd);
        ASSERT_ERR_FD(tp_fd, "bpf_raw_tracepoint_open");

        close(tp_fd);
        close(bpf_fd);
}

void test_raw_tp_writable_reject_nbd_invalid(void)
{
        const struct bpf_insn program[] = {
                /* r6 is our tp buffer */
                BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0),
                /* one byte beyond the end of the nbd_request struct */
                BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_6,
                            sizeof(struct nbd_request)),
                BPF_EXIT_INSN(),
        };
        const struct bpf_insn negative_var_off_program[] = {
                BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0),
                /* make var_off negative, but keep the effective access offset 
non-negative */
                BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, -8),
                /* one byte beyond the end of the nbd_request struct */
                BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_6,
                            sizeof(struct nbd_request) + 8),
                BPF_EXIT_INSN(),
        };

        if (test__start_subtest("nbd_invalid"))
                check_nbd_attach_reject(program, ARRAY_SIZE(program));
        if (test__start_subtest("nbd_invalid_negative_var_off"))
                check_nbd_attach_reject(negative_var_off_program,
                                        ARRAY_SIZE(negative_var_off_program));
}


[...]

Reply via email to