From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: bpf@vger.kernel.org
Cc: Emil Tsalapatis <emil@etsalapatis.com>,
Puranjay Mohan <puranjay@kernel.org>,
Mykyta Yatsenko <yatsenko@meta.com>,
Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Martin KaFai Lau <martin.lau@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>, Tejun Heo <tj@kernel.org>,
Dan Schatzberg <dschatzberg@meta.com>,
kkd@meta.com, kernel-team@meta.com
Subject: [PATCH bpf-next v5 4/7] selftests/bpf: Add syscall ctx variable offset tests
Date: Mon, 6 Apr 2026 21:43:58 +0200 [thread overview]
Message-ID: <20260406194403.1649608-5-memxor@gmail.com> (raw)
In-Reply-To: <20260406194403.1649608-1-memxor@gmail.com>
Add various tests to exercise fixed and variable offsets on PTR_TO_CTX
for syscall programs, and cover disallowed cases for other program types
lacking convert_ctx_access callback. Load verifier_ctx with CAP_SYS_ADMIN
so that kfunc related logic can be tested. While at it, convert assembly
tests to C. Unfortunately, ctx_pointer_to_helper_2's unpriv case conflicts
with usage of kfuncs in the file and cannot be run.
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Acked-by: Puranjay Mohan <puranjay@kernel.org>
Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
.../selftests/bpf/progs/verifier_ctx.c | 271 +++++++++++++++++-
.../selftests/bpf/test_kmods/bpf_testmod.c | 2 +-
2 files changed, 267 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/bpf/progs/verifier_ctx.c b/tools/testing/selftests/bpf/progs/verifier_ctx.c
index 4c285ac8fff6..6e683dd8002a 100644
--- a/tools/testing/selftests/bpf/progs/verifier_ctx.c
+++ b/tools/testing/selftests/bpf/progs/verifier_ctx.c
@@ -4,6 +4,10 @@
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"
+#include "../test_kmods/bpf_testmod_kfunc.h"
+
+static const char ctx_strncmp_target[] = "ctx";
+static const char ctx_snprintf_fmt[] = "";
SEC("tc")
__description("context stores via BPF_ATOMIC")
@@ -69,7 +73,6 @@ __naked void ctx_pointer_to_helper_1(void)
SEC("socket")
__description("pass modified ctx pointer to helper, 2")
__failure __msg("negative offset ctx ptr R1 off=-612 disallowed")
-__failure_unpriv __msg_unpriv("negative offset ctx ptr R1 off=-612 disallowed")
__naked void ctx_pointer_to_helper_2(void)
{
asm volatile (" \
@@ -292,7 +295,7 @@ padding_access("cgroup/post_bind4", bpf_sock, dst_port, 2);
__failure __msg("invalid bpf_context access")
padding_access("sk_reuseport", sk_reuseport_md, hash, 4);
-SEC("syscall")
+SEC("?syscall")
__description("syscall: write to ctx with fixed offset")
__success
int syscall_ctx_fixed_off_write(void *ctx)
@@ -304,6 +307,174 @@ int syscall_ctx_fixed_off_write(void *ctx)
return 0;
}
+SEC("?syscall")
+__description("syscall: read ctx with fixed offset")
+__success
+int syscall_ctx_fixed_off_read(void *ctx)
+{
+ char *p = ctx;
+ volatile __u32 val;
+
+ val = *(__u32 *)(p + 4);
+ (void)val;
+ return 0;
+}
+
+SEC("?syscall")
+__description("syscall: read ctx with variable offset")
+__success
+int syscall_ctx_var_off_read(void *ctx)
+{
+ __u64 off = bpf_get_prandom_u32();
+ char *p = ctx;
+ volatile __u32 val;
+
+ off &= 0xfc;
+ p += off;
+ val = *(__u32 *)p;
+ (void)val;
+ return 0;
+}
+
+SEC("?syscall")
+__description("syscall: write ctx with variable offset")
+__success
+int syscall_ctx_var_off_write(void *ctx)
+{
+ __u64 off = bpf_get_prandom_u32();
+ char *p = ctx;
+
+ off &= 0xfc;
+ p += off;
+ *(__u32 *)p = 0;
+ return 0;
+}
+
+SEC("?syscall")
+__description("syscall: reject negative variable offset ctx access")
+__failure __msg("min value is negative")
+int syscall_ctx_neg_var_off(void *ctx)
+{
+ __u64 off = bpf_get_prandom_u32();
+ char *p = ctx;
+
+ off &= 4;
+ p -= off;
+ return *(__u32 *)p;
+}
+
+SEC("?syscall")
+__description("syscall: reject unbounded variable offset ctx access")
+__failure __msg("unbounded memory access")
+int syscall_ctx_unbounded_var_off(void *ctx)
+{
+ __u64 off = (__u32)bpf_get_prandom_u32();
+ char *p = ctx;
+
+ off <<= 2;
+ p += off;
+ return *(__u32 *)p;
+}
+
+SEC("?syscall")
+__description("syscall: helper read ctx with fixed offset")
+__success
+int syscall_ctx_helper_fixed_off_read(void *ctx)
+{
+ char *p = ctx;
+
+ p += 4;
+ return bpf_strncmp(p, 4, ctx_strncmp_target);
+}
+
+SEC("?syscall")
+__description("syscall: helper write ctx with fixed offset")
+__success
+int syscall_ctx_helper_fixed_off_write(void *ctx)
+{
+ char *p = ctx;
+
+ p += 4;
+ return bpf_probe_read_kernel(p, 4, 0);
+}
+
+SEC("?syscall")
+__description("syscall: helper read ctx with variable offset")
+__success
+int syscall_ctx_helper_var_off_read(void *ctx)
+{
+ __u64 off = bpf_get_prandom_u32();
+ char *p = ctx;
+
+ off &= 0xfc;
+ p += off;
+ return bpf_strncmp(p, 4, ctx_strncmp_target);
+}
+
+SEC("?syscall")
+__description("syscall: helper write ctx with variable offset")
+__success
+int syscall_ctx_helper_var_off_write(void *ctx)
+{
+ __u64 off = bpf_get_prandom_u32();
+ char *p = ctx;
+
+ off &= 0xfc;
+ p += off;
+ return bpf_probe_read_kernel(p, 4, 0);
+}
+
+SEC("?syscall")
+__description("syscall: helper read zero-sized ctx access")
+__success
+int syscall_ctx_helper_zero_sized_read(void *ctx)
+{
+ return bpf_snprintf(0, 0, ctx_snprintf_fmt, ctx, 0);
+}
+
+SEC("?syscall")
+__description("syscall: helper write zero-sized ctx access")
+__success
+int syscall_ctx_helper_zero_sized_write(void *ctx)
+{
+ return bpf_probe_read_kernel(ctx, 0, 0);
+}
+
+SEC("?syscall")
+__description("syscall: kfunc access ctx with fixed offset")
+__success
+int syscall_ctx_kfunc_fixed_off(void *ctx)
+{
+ char *p = ctx;
+
+ p += 4;
+ bpf_kfunc_call_test_mem_len_pass1(p, 4);
+ return 0;
+}
+
+SEC("?syscall")
+__description("syscall: kfunc access ctx with variable offset")
+__success
+int syscall_ctx_kfunc_var_off(void *ctx)
+{
+ __u64 off = bpf_get_prandom_u32();
+ char *p = ctx;
+
+ off &= 0xfc;
+ p += off;
+ bpf_kfunc_call_test_mem_len_pass1(p, 4);
+ return 0;
+}
+
+SEC("?syscall")
+__description("syscall: kfunc access zero-sized ctx")
+__success
+int syscall_ctx_kfunc_zero_sized(void *ctx)
+{
+ bpf_kfunc_call_test_mem_len_pass1(ctx, 0);
+ return 0;
+}
+
/*
* For non-syscall program types without convert_ctx_access, direct ctx
* dereference is still allowed after adding a fixed offset, while variable
@@ -314,7 +485,7 @@ int syscall_ctx_fixed_off_write(void *ctx)
* for non-syscall ctx pointers at fixed, variable, and zero-sized accesses.
*/
#define no_rewrite_ctx_access(type, name, off, load_t) \
- SEC(type) \
+ SEC("?" type) \
__description(type ": read ctx at fixed offset") \
__success \
int no_rewrite_##name##_fixed(void *ctx) \
@@ -326,7 +497,7 @@ int syscall_ctx_fixed_off_write(void *ctx)
(void)val; \
return 0; \
} \
- SEC(type) \
+ SEC("?" type) \
__description(type ": reject variable offset ctx access") \
__failure __msg("variable ctx access var_off=") \
int no_rewrite_##name##_var(void *ctx) \
@@ -338,7 +509,7 @@ int syscall_ctx_fixed_off_write(void *ctx)
p += off_var; \
return *(load_t *)p; \
} \
- SEC(type) \
+ SEC("?" type) \
__description(type ": reject negative offset ctx access") \
__failure __msg("invalid bpf_context access") \
int no_rewrite_##name##_neg(void *ctx) \
@@ -347,6 +518,96 @@ int syscall_ctx_fixed_off_write(void *ctx)
\
p -= 612; \
return *(load_t *)p; \
+ } \
+ SEC("?" type) \
+ __description(type ": reject helper read ctx at fixed offset") \
+ __failure __msg("dereference of modified ctx ptr") \
+ int no_rewrite_##name##_helper_read_fixed(void *ctx) \
+ { \
+ char *p = ctx; \
+ \
+ p += off; \
+ return bpf_strncmp(p, 4, ctx_strncmp_target); \
+ } \
+ SEC("?" type) \
+ __description(type ": reject helper write ctx at fixed offset") \
+ __failure __msg("dereference of modified ctx ptr") \
+ int no_rewrite_##name##_helper_write_fixed(void *ctx) \
+ { \
+ char *p = ctx; \
+ \
+ p += off; \
+ return bpf_probe_read_kernel(p, 4, 0); \
+ } \
+ SEC("?" type) \
+ __description(type ": reject helper read ctx with variable offset") \
+ __failure __msg("variable ctx access var_off=") \
+ int no_rewrite_##name##_helper_read_var(void *ctx) \
+ { \
+ __u64 off_var = bpf_get_prandom_u32(); \
+ char *p = ctx; \
+ \
+ off_var &= 4; \
+ p += off_var; \
+ return bpf_strncmp(p, 4, ctx_strncmp_target); \
+ } \
+ SEC("?" type) \
+ __description(type ": reject helper write ctx with variable offset") \
+ __failure __msg("variable ctx access var_off=") \
+ int no_rewrite_##name##_helper_write_var(void *ctx) \
+ { \
+ __u64 off_var = bpf_get_prandom_u32(); \
+ char *p = ctx; \
+ \
+ off_var &= 4; \
+ p += off_var; \
+ return bpf_probe_read_kernel(p, 4, 0); \
+ } \
+ SEC("?" type) \
+ __description(type ": reject helper read zero-sized ctx access") \
+ __failure __msg("R4 type=ctx expected=fp") \
+ int no_rewrite_##name##_helper_read_zero(void *ctx) \
+ { \
+ return bpf_snprintf(0, 0, ctx_snprintf_fmt, ctx, 0); \
+ } \
+ SEC("?" type) \
+ __description(type ": reject helper write zero-sized ctx access") \
+ __failure __msg("R1 type=ctx expected=fp") \
+ int no_rewrite_##name##_helper_write_zero(void *ctx) \
+ { \
+ return bpf_probe_read_kernel(ctx, 0, 0); \
+ } \
+ SEC("?" type) \
+ __description(type ": reject kfunc ctx at fixed offset") \
+ __failure __msg("dereference of modified ctx ptr") \
+ int no_rewrite_##name##_kfunc_fixed(void *ctx) \
+ { \
+ char *p = ctx; \
+ \
+ p += off; \
+ bpf_kfunc_call_test_mem_len_pass1(p, 4); \
+ return 0; \
+ } \
+ SEC("?" type) \
+ __description(type ": reject kfunc ctx with variable offset") \
+ __failure __msg("variable ctx access var_off=") \
+ int no_rewrite_##name##_kfunc_var(void *ctx) \
+ { \
+ __u64 off_var = bpf_get_prandom_u32(); \
+ char *p = ctx; \
+ \
+ off_var &= 4; \
+ p += off_var; \
+ bpf_kfunc_call_test_mem_len_pass1(p, 4); \
+ return 0; \
+ } \
+ SEC("?" type) \
+ __description(type ": reject kfunc zero-sized ctx access") \
+ __failure __msg("R1 type=ctx expected=fp") \
+ int no_rewrite_##name##_kfunc_zero(void *ctx) \
+ { \
+ bpf_kfunc_call_test_mem_len_pass1(ctx, 0); \
+ return 0; \
}
no_rewrite_ctx_access("kprobe", kprobe, 8, u64);
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
index 061356f10093..d876314a4d67 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
@@ -723,6 +723,7 @@ BTF_ID_FLAGS(func, bpf_iter_testmod_seq_next, KF_ITER_NEXT | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_iter_testmod_seq_destroy, KF_ITER_DESTROY)
BTF_ID_FLAGS(func, bpf_iter_testmod_seq_value)
BTF_ID_FLAGS(func, bpf_kfunc_common_test)
+BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_pass1)
BTF_ID_FLAGS(func, bpf_kfunc_dynptr_test)
BTF_ID_FLAGS(func, bpf_kfunc_nested_acquire_nonzero_offset_test, KF_ACQUIRE)
BTF_ID_FLAGS(func, bpf_kfunc_nested_acquire_zero_offset_test, KF_ACQUIRE)
@@ -1287,7 +1288,6 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test2)
BTF_ID_FLAGS(func, bpf_kfunc_call_test3)
BTF_ID_FLAGS(func, bpf_kfunc_call_test4)
BTF_ID_FLAGS(func, bpf_kfunc_call_test5)
-BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_pass1)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail1)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail2)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_acquire, KF_ACQUIRE | KF_RET_NULL)
--
2.52.0
next prev parent reply other threads:[~2026-04-06 19:44 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-06 19:43 [PATCH bpf-next v5 0/7] Allow variable offsets for syscall PTR_TO_CTX Kumar Kartikeya Dwivedi
2026-04-06 19:43 ` [PATCH bpf-next v5 1/7] bpf: Support " Kumar Kartikeya Dwivedi
2026-04-06 19:43 ` [PATCH bpf-next v5 2/7] bpf: Enable unaligned accesses for syscall ctx Kumar Kartikeya Dwivedi
2026-04-06 19:43 ` [PATCH bpf-next v5 3/7] selftests/bpf: Convert ctx tests from ASM to C Kumar Kartikeya Dwivedi
2026-04-06 19:43 ` Kumar Kartikeya Dwivedi [this message]
2026-04-06 19:43 ` [PATCH bpf-next v5 5/7] selftests/bpf: Test modified syscall ctx for ARG_PTR_TO_CTX Kumar Kartikeya Dwivedi
2026-04-06 19:44 ` [PATCH bpf-next v5 6/7] selftests/bpf: Add tests for unaligned syscall ctx accesses Kumar Kartikeya Dwivedi
2026-04-06 19:44 ` [PATCH bpf-next v5 7/7] selftests/bpf: Add tests for syscall ctx accesses beyond U16_MAX Kumar Kartikeya Dwivedi
2026-04-06 22:02 ` Alexei Starovoitov
2026-04-06 22:30 ` [PATCH bpf-next v5 0/7] Allow variable offsets for syscall PTR_TO_CTX patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260406194403.1649608-5-memxor@gmail.com \
--to=memxor@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=dschatzberg@meta.com \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=kernel-team@meta.com \
--cc=kkd@meta.com \
--cc=martin.lau@kernel.org \
--cc=puranjay@kernel.org \
--cc=tj@kernel.org \
--cc=yatsenko@meta.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.