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));
}
[...]