Re: [PATCH bpf v4 2/2] selftests/bpf: Cover negative raw_tp writable buffer offsets

From: Eduard Zingerman

Date: Thu Jul 09 2026 - 13:00:16 EST


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 <sun.jian.kdev@xxxxxxxxx>
> ---
>  .../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));
}


[...]