* [PATCH bpf-next 0/8] bpf: Enhance __bpf_prog_map_compatible()
@ 2026-02-24 15:40 Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 1/8] bpf: Add fsession to verbose log in check_get_func_ip() Leon Hwang
` (7 more replies)
0 siblings, 8 replies; 13+ messages in thread
From: Leon Hwang @ 2026-02-24 15:40 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Leon Hwang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, linux-kernel, linux-kselftest,
netdev, kernel-patches-bot
Following discussion in the "bpf: tail calls in sleepable programs" [1],
this series extends __bpf_prog_map_compatible() with additional per-program
compatibility checks.
The series validates these attributes:
* kprobe_write_ctx: for uprobe programs that can update pt_regs.
* call_get_func_ip: for tracing programs using bpf_get_func_ip().
* call_session_cookie: for fsession programs using bpf_session_cookie().
* call_session_is_return: for fsession programs using bpf_session_is_return().
For each attribute, prog_array compatibility is one-way:
programs without the requirement are rejected when tail-calling into
programs that require it.
This keeps tail-call runtime assumptions consistent. For example,
call_get_func_ip programs rely on func_ip metadata prepared on trampoline
stack; tail-calling from a !call_get_func_ip program into such a callee can
produce invalid func_ip values. The same class of issue applies to
call_session_cookie and call_session_is_return.
Links:
[1] https://lore.kernel.org/bpf/20260130081208.1130204-1-jolsa@kernel.org/
Leon Hwang (8):
bpf: Add fsession to verbose log in check_get_func_ip()
bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx
progs
bpf: Disallow !call_get_func_ip progs tail-calling call_get_func_ip
progs
bpf: Disallow !call_session_cookie progs tail-calling
call_session_cookie progs
bpf: Disallow !call_session_is_return progs tail-calling
call_session_is_return progs
selftests/bpf: Add a test to verify kprobe_write_ctx compatibility
enforcement
selftests/bpf: Add a test to verify call_get_func_ip compatibility
enforcement
selftests/bpf: Add a test to verify session-kfunc compatibility
enforcement
include/linux/bpf.h | 11 +++--
kernel/bpf/core.c | 15 ++++++
kernel/bpf/verifier.c | 4 +-
.../selftests/bpf/prog_tests/attach_probe.c | 44 +++++++++++++++++
.../selftests/bpf/prog_tests/fsession_test.c | 47 +++++++++++++++++++
.../bpf/prog_tests/get_func_ip_test.c | 46 ++++++++++++++++++
.../selftests/bpf/progs/fsession_test.c | 6 +++
.../selftests/bpf/progs/get_func_ip_test.c | 6 +++
.../selftests/bpf/progs/kprobe_write_ctx.c | 6 +++
9 files changed, 181 insertions(+), 4 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH bpf-next 1/8] bpf: Add fsession to verbose log in check_get_func_ip()
2026-02-24 15:40 [PATCH bpf-next 0/8] bpf: Enhance __bpf_prog_map_compatible() Leon Hwang
@ 2026-02-24 15:40 ` Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 2/8] bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx progs Leon Hwang
` (6 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Leon Hwang @ 2026-02-24 15:40 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Leon Hwang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, linux-kernel, linux-kselftest,
netdev, kernel-patches-bot
Since bpf_get_func_ip() is supported for fsession intuitively, add
fsession to the verbose log in check_get_func_ip().
No functional change intended.
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
kernel/bpf/verifier.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 1153a828ce8d..9e9c04e08fba 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -11463,7 +11463,7 @@ static int check_get_func_ip(struct bpf_verifier_env *env)
if (type == BPF_PROG_TYPE_TRACING) {
if (!bpf_prog_has_trampoline(env->prog)) {
- verbose(env, "func %s#%d supported only for fentry/fexit/fmod_ret programs\n",
+ verbose(env, "func %s#%d supported only for fentry/fexit/fsession/fmod_ret programs\n",
func_id_name(func_id), func_id);
return -ENOTSUPP;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH bpf-next 2/8] bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx progs
2026-02-24 15:40 [PATCH bpf-next 0/8] bpf: Enhance __bpf_prog_map_compatible() Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 1/8] bpf: Add fsession to verbose log in check_get_func_ip() Leon Hwang
@ 2026-02-24 15:40 ` Leon Hwang
2026-02-24 16:22 ` bot+bpf-ci
2026-02-24 16:57 ` Alexei Starovoitov
2026-02-24 15:40 ` [PATCH bpf-next 3/8] bpf: Disallow !call_get_func_ip progs tail-calling call_get_func_ip progs Leon Hwang
` (5 subsequent siblings)
7 siblings, 2 replies; 13+ messages in thread
From: Leon Hwang @ 2026-02-24 15:40 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Leon Hwang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, linux-kernel, linux-kselftest,
netdev, kernel-patches-bot
uprobe programs that can modify pt_regs require different runtime
assumptions than pt_regs-read-only uprobe programs. Mixing both in
one prog_array can make owner expectations diverge from callee behavior.
Reject the combination of !kprobe_write_ctx progs with kprobe_write_ctx
progs in __bpf_prog_map_compatible() to address the issue.
Fixes: 7384893d970e ("bpf: Allow uprobe program to change context registers")
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
include/linux/bpf.h | 7 ++++---
kernel/bpf/core.c | 3 +++
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index b78b53198a2e..2a2f6448a5fb 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -285,9 +285,10 @@ struct bpf_list_node_kern {
*/
struct bpf_map_owner {
enum bpf_prog_type type;
- bool jited;
- bool xdp_has_frags;
- bool sleepable;
+ u32 jited:1,
+ xdp_has_frags:1,
+ sleepable:1,
+ kprobe_write_ctx:1;
u64 storage_cookie[MAX_BPF_CGROUP_STORAGE_TYPE];
const struct btf_type *attach_func_proto;
enum bpf_attach_type expected_attach_type;
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 3ece2da55625..f99a901b5e48 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2402,6 +2402,7 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
map->owner->jited = fp->jited;
map->owner->xdp_has_frags = aux->xdp_has_frags;
map->owner->sleepable = fp->sleepable;
+ map->owner->kprobe_write_ctx = aux->kprobe_write_ctx;
map->owner->expected_attach_type = fp->expected_attach_type;
map->owner->attach_func_proto = aux->attach_func_proto;
for_each_cgroup_storage_type(i) {
@@ -2415,6 +2416,8 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
map->owner->jited == fp->jited &&
map->owner->xdp_has_frags == aux->xdp_has_frags &&
map->owner->sleepable == fp->sleepable;
+ if (ret && (!map->owner->kprobe_write_ctx && aux->kprobe_write_ctx))
+ ret = false;
if (ret &&
map->map_type == BPF_MAP_TYPE_PROG_ARRAY &&
map->owner->expected_attach_type != fp->expected_attach_type)
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH bpf-next 3/8] bpf: Disallow !call_get_func_ip progs tail-calling call_get_func_ip progs
2026-02-24 15:40 [PATCH bpf-next 0/8] bpf: Enhance __bpf_prog_map_compatible() Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 1/8] bpf: Add fsession to verbose log in check_get_func_ip() Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 2/8] bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx progs Leon Hwang
@ 2026-02-24 15:40 ` Leon Hwang
2026-02-24 16:35 ` bot+bpf-ci
2026-02-24 15:40 ` [PATCH bpf-next 4/8] bpf: Disallow !call_session_cookie progs tail-calling call_session_cookie progs Leon Hwang
` (4 subsequent siblings)
7 siblings, 1 reply; 13+ messages in thread
From: Leon Hwang @ 2026-02-24 15:40 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Leon Hwang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, linux-kernel, linux-kselftest,
netdev, kernel-patches-bot
Trampoline-based tracing programs that call bpf_get_func_ip() rely on
func_ip stored on stack. Mixing them with tracing programs that do not
share this requirement creates asymmetric expectations in tail calls.
Reject the combination of !call_get_func_ip progs with call_get_func_ip
progs in __bpf_prog_map_compatible() to address the issue.
Fixes: 1e37392cccde ("bpf: Enable BPF_TRAMP_F_IP_ARG for trampolines with call_get_func_ip")
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
include/linux/bpf.h | 3 ++-
kernel/bpf/core.c | 4 ++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 2a2f6448a5fb..65793fd146c5 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -288,7 +288,8 @@ struct bpf_map_owner {
u32 jited:1,
xdp_has_frags:1,
sleepable:1,
- kprobe_write_ctx:1;
+ kprobe_write_ctx:1,
+ call_get_func_ip:1;
u64 storage_cookie[MAX_BPF_CGROUP_STORAGE_TYPE];
const struct btf_type *attach_func_proto;
enum bpf_attach_type expected_attach_type;
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index f99a901b5e48..01fce3fba0be 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2403,6 +2403,7 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
map->owner->xdp_has_frags = aux->xdp_has_frags;
map->owner->sleepable = fp->sleepable;
map->owner->kprobe_write_ctx = aux->kprobe_write_ctx;
+ map->owner->call_get_func_ip = fp->call_get_func_ip;
map->owner->expected_attach_type = fp->expected_attach_type;
map->owner->attach_func_proto = aux->attach_func_proto;
for_each_cgroup_storage_type(i) {
@@ -2418,6 +2419,9 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
map->owner->sleepable == fp->sleepable;
if (ret && (!map->owner->kprobe_write_ctx && aux->kprobe_write_ctx))
ret = false;
+ if (ret && (!map->owner->call_get_func_ip && fp->call_get_func_ip &&
+ prog_type == BPF_PROG_TYPE_TRACING))
+ ret = false;
if (ret &&
map->map_type == BPF_MAP_TYPE_PROG_ARRAY &&
map->owner->expected_attach_type != fp->expected_attach_type)
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH bpf-next 4/8] bpf: Disallow !call_session_cookie progs tail-calling call_session_cookie progs
2026-02-24 15:40 [PATCH bpf-next 0/8] bpf: Enhance __bpf_prog_map_compatible() Leon Hwang
` (2 preceding siblings ...)
2026-02-24 15:40 ` [PATCH bpf-next 3/8] bpf: Disallow !call_get_func_ip progs tail-calling call_get_func_ip progs Leon Hwang
@ 2026-02-24 15:40 ` Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 5/8] bpf: Disallow !call_session_is_return progs tail-calling call_session_is_return progs Leon Hwang
` (3 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Leon Hwang @ 2026-02-24 15:40 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Leon Hwang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, linux-kernel, linux-kselftest,
netdev, kernel-patches-bot
bpf_session_cookie() depends on consistent session metadata stored on
stack for fsession programs. Mixing fsession programs that do and do not
rely on these helpers in tail calls can violate that runtime contract.
Disallow the combination of !call_session_cookie progs and
call_session_cookie progs in __bpf_prog_map_compatible() to address the
issue.
Fixes: eeee4239dbb1 ("bpf: support fsession for bpf_session_cookie")
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
include/linux/bpf.h | 3 ++-
kernel/bpf/core.c | 4 ++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 65793fd146c5..c74db70f9be1 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -289,7 +289,8 @@ struct bpf_map_owner {
xdp_has_frags:1,
sleepable:1,
kprobe_write_ctx:1,
- call_get_func_ip:1;
+ call_get_func_ip:1,
+ call_session_cookie:1;
u64 storage_cookie[MAX_BPF_CGROUP_STORAGE_TYPE];
const struct btf_type *attach_func_proto;
enum bpf_attach_type expected_attach_type;
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 01fce3fba0be..904a8dbfd56f 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2404,6 +2404,7 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
map->owner->sleepable = fp->sleepable;
map->owner->kprobe_write_ctx = aux->kprobe_write_ctx;
map->owner->call_get_func_ip = fp->call_get_func_ip;
+ map->owner->call_session_cookie = fp->call_session_cookie;
map->owner->expected_attach_type = fp->expected_attach_type;
map->owner->attach_func_proto = aux->attach_func_proto;
for_each_cgroup_storage_type(i) {
@@ -2422,6 +2423,9 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
if (ret && (!map->owner->call_get_func_ip && fp->call_get_func_ip &&
prog_type == BPF_PROG_TYPE_TRACING))
ret = false;
+ if (ret && (!map->owner->call_session_cookie && fp->call_session_cookie &&
+ prog_type == BPF_PROG_TYPE_TRACING))
+ ret = false;
if (ret &&
map->map_type == BPF_MAP_TYPE_PROG_ARRAY &&
map->owner->expected_attach_type != fp->expected_attach_type)
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH bpf-next 5/8] bpf: Disallow !call_session_is_return progs tail-calling call_session_is_return progs
2026-02-24 15:40 [PATCH bpf-next 0/8] bpf: Enhance __bpf_prog_map_compatible() Leon Hwang
` (3 preceding siblings ...)
2026-02-24 15:40 ` [PATCH bpf-next 4/8] bpf: Disallow !call_session_cookie progs tail-calling call_session_cookie progs Leon Hwang
@ 2026-02-24 15:40 ` Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 6/8] selftests/bpf: Add a test to verify kprobe_write_ctx compatibility enforcement Leon Hwang
` (2 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Leon Hwang @ 2026-02-24 15:40 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Leon Hwang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, linux-kernel, linux-kselftest,
netdev, kernel-patches-bot
bpf_session_is_return() depends on consistent session metadata stored on
stack for fsession programs. Mixing fsession programs that do and do not
rely on these helpers in tail calls can violate that runtime contract.
Disallow the combination of !call_session_is_return progs and
call_session_is_return progs in __bpf_prog_map_compatible() to address
the issue.
Fixes: 27d89baa6da8 ("bpf: support fsession for bpf_session_is_return")
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
include/linux/bpf.h | 4 +++-
kernel/bpf/core.c | 4 ++++
kernel/bpf/verifier.c | 2 ++
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index c74db70f9be1..6be5f81b61e7 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -290,7 +290,8 @@ struct bpf_map_owner {
sleepable:1,
kprobe_write_ctx:1,
call_get_func_ip:1,
- call_session_cookie:1;
+ call_session_cookie:1,
+ call_session_is_return:1;
u64 storage_cookie[MAX_BPF_CGROUP_STORAGE_TYPE];
const struct btf_type *attach_func_proto;
enum bpf_attach_type expected_attach_type;
@@ -1699,6 +1700,7 @@ struct bpf_prog_aux {
bool changes_pkt_data;
bool might_sleep;
bool kprobe_write_ctx;
+ bool call_session_is_return; /* Do we call bpf_session_is_return */
u64 prog_array_member_cnt; /* counts how many times as member of prog_array */
struct mutex ext_mutex; /* mutex for is_extended and prog_array_member_cnt */
struct bpf_arena *arena;
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 904a8dbfd56f..44aeb49b2d1b 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2405,6 +2405,7 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
map->owner->kprobe_write_ctx = aux->kprobe_write_ctx;
map->owner->call_get_func_ip = fp->call_get_func_ip;
map->owner->call_session_cookie = fp->call_session_cookie;
+ map->owner->call_session_is_return = aux->call_session_is_return;
map->owner->expected_attach_type = fp->expected_attach_type;
map->owner->attach_func_proto = aux->attach_func_proto;
for_each_cgroup_storage_type(i) {
@@ -2426,6 +2427,9 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
if (ret && (!map->owner->call_session_cookie && fp->call_session_cookie &&
prog_type == BPF_PROG_TYPE_TRACING))
ret = false;
+ if (ret && (!map->owner->call_session_is_return && aux->call_session_is_return &&
+ prog_type == BPF_PROG_TYPE_TRACING))
+ ret = false;
if (ret &&
map->map_type == BPF_MAP_TYPE_PROG_ARRAY &&
map->owner->expected_attach_type != fp->expected_attach_type)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 9e9c04e08fba..919075ee3479 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -14409,6 +14409,8 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
if (meta.func_id == special_kfunc_list[KF_bpf_session_cookie])
env->prog->call_session_cookie = true;
+ if (meta.func_id == special_kfunc_list[KF_bpf_session_is_return])
+ env->prog->aux->call_session_is_return = true;
return 0;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH bpf-next 6/8] selftests/bpf: Add a test to verify kprobe_write_ctx compatibility enforcement
2026-02-24 15:40 [PATCH bpf-next 0/8] bpf: Enhance __bpf_prog_map_compatible() Leon Hwang
` (4 preceding siblings ...)
2026-02-24 15:40 ` [PATCH bpf-next 5/8] bpf: Disallow !call_session_is_return progs tail-calling call_session_is_return progs Leon Hwang
@ 2026-02-24 15:40 ` Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 7/8] selftests/bpf: Add a test to verify call_get_func_ip " Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 8/8] selftests/bpf: Add a test to verify session-kfunc " Leon Hwang
7 siblings, 0 replies; 13+ messages in thread
From: Leon Hwang @ 2026-02-24 15:40 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Leon Hwang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, linux-kernel, linux-kselftest,
netdev, kernel-patches-bot
Add prog_array coverage for kprobe programs with and without
kprobe_write_ctx requirements.
The test verifies one-way enforcement: !kprobe_write_ctx programs
cannot tail-call kprobe_write_ctx programs.
Assisted-by: Codex:gpt-5.3-codex
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
.../selftests/bpf/prog_tests/attach_probe.c | 44 +++++++++++++++++++
.../selftests/bpf/progs/kprobe_write_ctx.c | 6 +++
2 files changed, 50 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/attach_probe.c b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
index 9e77e5da7097..a9444db92246 100644
--- a/tools/testing/selftests/bpf/prog_tests/attach_probe.c
+++ b/tools/testing/selftests/bpf/prog_tests/attach_probe.c
@@ -220,11 +220,53 @@ static void test_attach_kprobe_write_ctx(void)
kprobe_write_ctx__destroy(skel);
}
+
+static void test_kprobe_write_ctx_prog_array_compat(void)
+{
+ __u32 key = 0, read_prog_fd, write_prog_fd;
+ struct kprobe_write_ctx *skel = NULL;
+ int map_fd = -1, err;
+
+ skel = kprobe_write_ctx__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "kprobe_write_ctx__open_and_load"))
+ return;
+
+ map_fd = bpf_map_create(BPF_MAP_TYPE_PROG_ARRAY, NULL, sizeof(key),
+ sizeof(__u32), 1, NULL);
+ if (!ASSERT_GE(map_fd, 0, "bpf_map_create"))
+ goto cleanup;
+
+ read_prog_fd = bpf_program__fd(skel->progs.kprobe_read_ctx);
+ write_prog_fd = bpf_program__fd(skel->progs.kprobe_write_ctx);
+ if (!ASSERT_GE(read_prog_fd, 0, "read_prog_fd"))
+ goto cleanup;
+ if (!ASSERT_GE(write_prog_fd, 0, "write_prog_fd"))
+ goto cleanup;
+
+ err = bpf_map_update_elem(map_fd, &key, &read_prog_fd, BPF_ANY);
+ if (!ASSERT_OK(err, "bpf_map_update_elem success"))
+ goto cleanup;
+
+ err = bpf_map_update_elem(map_fd, &key, &write_prog_fd, BPF_ANY);
+ if (!ASSERT_ERR(err, "bpf_map_update_elem failure"))
+ goto cleanup;
+ ASSERT_EQ(errno, EINVAL, "bpf_map_update_elem errno");
+
+cleanup:
+ if (map_fd >= 0)
+ close(map_fd);
+ kprobe_write_ctx__destroy(skel);
+}
#else
static void test_attach_kprobe_write_ctx(void)
{
test__skip();
}
+
+static void test_kprobe_write_ctx_prog_array_compat(void)
+{
+ test__skip();
+}
#endif
static void test_attach_probe_auto(struct test_attach_probe *skel)
@@ -434,6 +476,8 @@ void test_attach_probe(void)
test_attach_kprobe_long_event_name();
if (test__start_subtest("kprobe-write-ctx"))
test_attach_kprobe_write_ctx();
+ if (test__start_subtest("kprobe-write-ctx-prog-array-compat"))
+ test_kprobe_write_ctx_prog_array_compat();
cleanup:
test_attach_probe__destroy(skel);
diff --git a/tools/testing/selftests/bpf/progs/kprobe_write_ctx.c b/tools/testing/selftests/bpf/progs/kprobe_write_ctx.c
index f77aef0474d3..09e0c487bde5 100644
--- a/tools/testing/selftests/bpf/progs/kprobe_write_ctx.c
+++ b/tools/testing/selftests/bpf/progs/kprobe_write_ctx.c
@@ -13,6 +13,12 @@ int kprobe_write_ctx(struct pt_regs *ctx)
return 0;
}
+SEC("kprobe")
+int kprobe_read_ctx(struct pt_regs *ctx)
+{
+ return 0;
+}
+
SEC("kprobe.multi")
int kprobe_multi_write_ctx(struct pt_regs *ctx)
{
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH bpf-next 7/8] selftests/bpf: Add a test to verify call_get_func_ip compatibility enforcement
2026-02-24 15:40 [PATCH bpf-next 0/8] bpf: Enhance __bpf_prog_map_compatible() Leon Hwang
` (5 preceding siblings ...)
2026-02-24 15:40 ` [PATCH bpf-next 6/8] selftests/bpf: Add a test to verify kprobe_write_ctx compatibility enforcement Leon Hwang
@ 2026-02-24 15:40 ` Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 8/8] selftests/bpf: Add a test to verify session-kfunc " Leon Hwang
7 siblings, 0 replies; 13+ messages in thread
From: Leon Hwang @ 2026-02-24 15:40 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Leon Hwang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, linux-kernel, linux-kselftest,
netdev, kernel-patches-bot
Add prog_array coverage for tracing programs that differ in
bpf_get_func_ip() dependency.
The test verifies one-way enforcement: !call_get_func_ip programs
cannot tail-call call_get_func_ip programs.
Assisted-by: Codex:gpt-5.3-codex
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
.../bpf/prog_tests/get_func_ip_test.c | 46 +++++++++++++++++++
.../selftests/bpf/progs/get_func_ip_test.c | 6 +++
2 files changed, 52 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/get_func_ip_test.c b/tools/testing/selftests/bpf/prog_tests/get_func_ip_test.c
index 7772a0f288d3..670457d4e159 100644
--- a/tools/testing/selftests/bpf/prog_tests/get_func_ip_test.c
+++ b/tools/testing/selftests/bpf/prog_tests/get_func_ip_test.c
@@ -139,3 +139,49 @@ void test_get_func_ip_test(void)
test_function_entry();
test_function_body();
}
+
+static void test_prog_array_call_get_func_ip_compat(void)
+{
+ __u32 key = 0, with_get_func_ip_fd, without_get_func_ip_fd;
+ struct get_func_ip_test *skel = NULL;
+ int map_fd = -1, err;
+
+ skel = get_func_ip_test__open();
+ if (!ASSERT_OK_PTR(skel, "get_func_ip_test__open"))
+ return;
+
+ err = get_func_ip_test__load(skel);
+ if (!ASSERT_OK(err, "get_func_ip_test__load"))
+ goto cleanup;
+
+ with_get_func_ip_fd = bpf_program__fd(skel->progs.test1);
+ without_get_func_ip_fd = bpf_program__fd(skel->progs.test1_dummy);
+ if (!ASSERT_GE(with_get_func_ip_fd, 0, "with_get_func_ip_fd"))
+ goto cleanup;
+ if (!ASSERT_GE(without_get_func_ip_fd, 0, "without_get_func_ip_fd"))
+ goto cleanup;
+
+ map_fd = bpf_map_create(BPF_MAP_TYPE_PROG_ARRAY, NULL, sizeof(key),
+ sizeof(__u32), 1, NULL);
+ if (!ASSERT_GE(map_fd, 0, "bpf_map_create"))
+ goto cleanup;
+
+ err = bpf_map_update_elem(map_fd, &key, &without_get_func_ip_fd, BPF_ANY);
+ if (!ASSERT_OK(err, "bpf_map_update_elem success"))
+ goto cleanup;
+
+ err = bpf_map_update_elem(map_fd, &key, &with_get_func_ip_fd, BPF_ANY);
+ if (!ASSERT_ERR(err, "bpf_map_update_elem failure"))
+ goto cleanup;
+ ASSERT_EQ(errno, EINVAL, "bpf_map_update_elem errno");
+
+cleanup:
+ if (map_fd >= 0)
+ close(map_fd);
+ get_func_ip_test__destroy(skel);
+}
+
+void test_get_func_ip_test_prog_map_compatible(void)
+{
+ test_prog_array_call_get_func_ip_compat();
+}
diff --git a/tools/testing/selftests/bpf/progs/get_func_ip_test.c b/tools/testing/selftests/bpf/progs/get_func_ip_test.c
index 45eaa54d1ac7..6a7d306af96e 100644
--- a/tools/testing/selftests/bpf/progs/get_func_ip_test.c
+++ b/tools/testing/selftests/bpf/progs/get_func_ip_test.c
@@ -32,6 +32,12 @@ int BPF_PROG(test1, int a)
return 0;
}
+SEC("fentry/bpf_fentry_test1")
+int BPF_PROG(test1_dummy, int a)
+{
+ return 0;
+}
+
__u64 test2_result = 0;
SEC("fexit/bpf_fentry_test2")
int BPF_PROG(test2, int a)
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH bpf-next 8/8] selftests/bpf: Add a test to verify session-kfunc compatibility enforcement
2026-02-24 15:40 [PATCH bpf-next 0/8] bpf: Enhance __bpf_prog_map_compatible() Leon Hwang
` (6 preceding siblings ...)
2026-02-24 15:40 ` [PATCH bpf-next 7/8] selftests/bpf: Add a test to verify call_get_func_ip " Leon Hwang
@ 2026-02-24 15:40 ` Leon Hwang
7 siblings, 0 replies; 13+ messages in thread
From: Leon Hwang @ 2026-02-24 15:40 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Leon Hwang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, linux-kernel, linux-kselftest,
netdev, kernel-patches-bot
Add prog_array coverage for tracing programs that differ in
bpf_session_cookie() / bpf_session_is_return() usage.
The test verifies one-way enforcement: !call_session_* programs
cannot tail-call call_session_* programs.
Assisted-by: Codex:gpt-5.3-codex
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
.../selftests/bpf/prog_tests/fsession_test.c | 47 +++++++++++++++++++
.../selftests/bpf/progs/fsession_test.c | 6 +++
2 files changed, 53 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/fsession_test.c b/tools/testing/selftests/bpf/prog_tests/fsession_test.c
index a299aeb8cc2e..304986544a8d 100644
--- a/tools/testing/selftests/bpf/prog_tests/fsession_test.c
+++ b/tools/testing/selftests/bpf/prog_tests/fsession_test.c
@@ -129,6 +129,51 @@ static void test_fsession_cookie(void)
fsession_test__destroy(skel);
}
+static void test_fsession_prog_array_session_kfunc_compat(void)
+{
+ struct fsession_test *skel = NULL;
+ __u32 key = 0, session_kfunc_prog_fd, no_session_kfunc_prog_fd;
+ int map_fd = -1, err;
+
+ skel = fsession_test__open();
+ if (!ASSERT_OK_PTR(skel, "fsession_test__open"))
+ goto cleanup;
+
+ err = fsession_test__load(skel);
+ if (err == -EOPNOTSUPP) {
+ test__skip();
+ goto cleanup;
+ }
+ if (!ASSERT_OK(err, "fsession_test__load"))
+ goto cleanup;
+
+ session_kfunc_prog_fd = bpf_program__fd(skel->progs.test9);
+ no_session_kfunc_prog_fd = bpf_program__fd(skel->progs.test12);
+ if (!ASSERT_GE(session_kfunc_prog_fd, 0, "session_kfunc_prog_fd"))
+ goto cleanup;
+ if (!ASSERT_GE(no_session_kfunc_prog_fd, 0, "no_session_kfunc_prog_fd"))
+ goto cleanup;
+
+ map_fd = bpf_map_create(BPF_MAP_TYPE_PROG_ARRAY, NULL, sizeof(key),
+ sizeof(__u32), 1, NULL);
+ if (!ASSERT_GE(map_fd, 0, "bpf_map_create"))
+ goto cleanup;
+
+ err = bpf_map_update_elem(map_fd, &key, &no_session_kfunc_prog_fd, BPF_ANY);
+ if (!ASSERT_OK(err, "bpf_map_update_elem success"))
+ goto cleanup;
+
+ err = bpf_map_update_elem(map_fd, &key, &session_kfunc_prog_fd, BPF_ANY);
+ if (!ASSERT_ERR(err, "bpf_map_update_elem failure"))
+ goto cleanup;
+ ASSERT_EQ(errno, EINVAL, "bpf_map_update_elem errno");
+
+cleanup:
+ if (map_fd >= 0)
+ close(map_fd);
+ fsession_test__destroy(skel);
+}
+
void test_fsession_test(void)
{
if (test__start_subtest("fsession_test"))
@@ -137,4 +182,6 @@ void test_fsession_test(void)
test_fsession_reattach();
if (test__start_subtest("fsession_cookie"))
test_fsession_cookie();
+ if (test__start_subtest("fsession_prog_array_session_kfunc_compat"))
+ test_fsession_prog_array_session_kfunc_compat();
}
diff --git a/tools/testing/selftests/bpf/progs/fsession_test.c b/tools/testing/selftests/bpf/progs/fsession_test.c
index 86e8a2fe467e..1e6be28bcc3d 100644
--- a/tools/testing/selftests/bpf/progs/fsession_test.c
+++ b/tools/testing/selftests/bpf/progs/fsession_test.c
@@ -177,3 +177,9 @@ int BPF_PROG(test11, int a)
test11_result = a == 1;
return 0;
}
+
+SEC("fsession/bpf_fentry_test1")
+int BPF_PROG(test12, int a, int ret)
+{
+ return 0;
+}
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next 2/8] bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx progs
2026-02-24 15:40 ` [PATCH bpf-next 2/8] bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx progs Leon Hwang
@ 2026-02-24 16:22 ` bot+bpf-ci
2026-02-24 16:57 ` Alexei Starovoitov
1 sibling, 0 replies; 13+ messages in thread
From: bot+bpf-ci @ 2026-02-24 16:22 UTC (permalink / raw)
To: leon.hwang, bpf
Cc: ast, daniel, andrii, martin.lau, eddyz87, song, yonghong.song,
john.fastabend, kpsingh, sdf, haoluo, jolsa, shuah, yangfeng,
leon.hwang, menglong8.dong, puranjay, bjorn, pulehui,
linux-kernel, linux-kselftest, netdev, kernel-patches-bot, ast,
andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 2658 bytes --]
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
[ ... ]
> @@ -2415,6 +2416,8 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
> map->owner->jited == fp->jited &&
> map->owner->xdp_has_frags == aux->xdp_has_frags &&
> map->owner->sleepable == fp->sleepable;
> + if (ret && (!map->owner->kprobe_write_ctx && aux->kprobe_write_ctx))
> + ret = false;
Is this check one-directional on purpose? It rejects the case
where the map owner is !kprobe_write_ctx and the incoming program
has kprobe_write_ctx, but it allows the reverse: a !kprobe_write_ctx
program passing the compatibility check against a kprobe_write_ctx-
owning map.
This means the following sequence is possible:
1. Program A (kprobe_write_ctx=true) is stored first in a
prog_array, becoming the map owner.
2. Program B (kprobe_write_ctx=false) passes the compatibility
check because (!true && false) evaluates to false, so ret
stays true.
3. Program B is attached to a kprobe via __perf_event_set_bpf_prog(),
which only rejects (kprobe_write_ctx && !is_uprobe) -- B passes
because its kprobe_write_ctx is false.
4. At runtime B tail-calls into A. Program A's instructions now
execute in kprobe context and write to kernel pt_regs.
The same path applies when B merely uses the map for bpf_tail_call()
without being stored -- bpf_check_tail_call() runs the same
__bpf_prog_map_compatible() check and allows B through.
The commit message says "Reject the combination of !kprobe_write_ctx
progs with kprobe_write_ctx progs" which suggests both directions
should be blocked. Would a symmetric check be more appropriate here?
> if (ret &&
> map->map_type == BPF_MAP_TYPE_PROG_ARRAY &&
> map->owner->expected_attach_type != fp->expected_attach_type)
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/22358832658
AI-authorship-score: low
AI-authorship-explanation: The commit message is concise and uses standard kernel terminology; the code changes follow established BPF patterns with no signs of AI-generated phrasing or structure.
issues-found: 1
issue-severity-score: high
issue-severity-explanation: The asymmetric compatibility check allows a !kprobe_write_ctx program attached to a kprobe to tail-call a kprobe_write_ctx program, enabling writes to kernel pt_regs in kprobe context and defeating the security enforcement the patch is meant to provide.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next 3/8] bpf: Disallow !call_get_func_ip progs tail-calling call_get_func_ip progs
2026-02-24 15:40 ` [PATCH bpf-next 3/8] bpf: Disallow !call_get_func_ip progs tail-calling call_get_func_ip progs Leon Hwang
@ 2026-02-24 16:35 ` bot+bpf-ci
0 siblings, 0 replies; 13+ messages in thread
From: bot+bpf-ci @ 2026-02-24 16:35 UTC (permalink / raw)
To: leon.hwang, bpf
Cc: ast, daniel, andrii, martin.lau, eddyz87, song, yonghong.song,
john.fastabend, kpsingh, sdf, haoluo, jolsa, shuah, yangfeng,
leon.hwang, menglong8.dong, puranjay, bjorn, pulehui,
linux-kernel, linux-kselftest, netdev, kernel-patches-bot, ast,
andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 2646 bytes --]
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
[ ... ]
> @@ -2418,6 +2419,9 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
> map->owner->sleepable == fp->sleepable;
> if (ret && (!map->owner->kprobe_write_ctx && aux->kprobe_write_ctx))
> ret = false;
> + if (ret && (!map->owner->call_get_func_ip && fp->call_get_func_ip &&
> + prog_type == BPF_PROG_TYPE_TRACING))
> + ret = false;
This check catches the case where owner->call_get_func_ip is 0 and
the new program has call_get_func_ip set. However, does the reverse
ordering also need to be handled?
Consider:
1. Program H (call_get_func_ip=1) is added to the prog_array first
and becomes the owner with owner->call_get_func_ip=1.
2. Program M (call_get_func_ip=0) is loaded and references this
prog_array for tail calls. bpf_check_tail_call() calls
__bpf_prog_map_compatible(PA, M), and the check evaluates:
(!owner->call_get_func_ip && fp->call_get_func_ip)
(!1 && 0) = false
so M passes the compatibility check.
3. M is attached to a trampoline where no program needs func_ip,
so ip_arg is false and func_ip is not pushed on the stack.
4. M tail-calls H. H calls bpf_get_func_ip(), which reads from
the expected stack offset, but that slot was never written by
the trampoline, so it returns stale stack data.
Would it be safer to reject any mismatch on call_get_func_ip for
tracing programs, regardless of which program was added first?
Something like:
if (ret && (map->owner->call_get_func_ip != fp->call_get_func_ip) &&
prog_type == BPF_PROG_TYPE_TRACING)
ret = false;
> if (ret &&
> map->map_type == BPF_MAP_TYPE_PROG_ARRAY &&
> map->owner->expected_attach_type != fp->expected_attach_type)
> ret = false;
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/22358832658
AI-authorship-score: medium
AI-authorship-explanation: Selftests in the series carry Assisted-by Codex tags, and the kernel code change is formulaic pattern replication across all commits, consistent with AI-assisted development.
issues-found: 1
issue-severity-score: medium
issue-severity-explanation: One-directional compatibility check allows a non-call_get_func_ip tail-caller to bypass the check when the call_get_func_ip program is added to the prog_array first, potentially causing bpf_get_func_ip to return stale stack data.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next 2/8] bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx progs
2026-02-24 15:40 ` [PATCH bpf-next 2/8] bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx progs Leon Hwang
2026-02-24 16:22 ` bot+bpf-ci
@ 2026-02-24 16:57 ` Alexei Starovoitov
2026-02-25 15:15 ` Leon Hwang
1 sibling, 1 reply; 13+ messages in thread
From: Alexei Starovoitov @ 2026-02-24 16:57 UTC (permalink / raw)
To: Leon Hwang
Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, LKML,
open list:KERNEL SELFTEST FRAMEWORK, Network Development,
kernel-patches-bot
On Tue, Feb 24, 2026 at 7:41 AM Leon Hwang <leon.hwang@linux.dev> wrote:
>
> uprobe programs that can modify pt_regs require different runtime
> assumptions than pt_regs-read-only uprobe programs. Mixing both in
> one prog_array can make owner expectations diverge from callee behavior.
>
> Reject the combination of !kprobe_write_ctx progs with kprobe_write_ctx
> progs in __bpf_prog_map_compatible() to address the issue.
>
> Fixes: 7384893d970e ("bpf: Allow uprobe program to change context registers")
> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
> ---
> include/linux/bpf.h | 7 ++++---
> kernel/bpf/core.c | 3 +++
> 2 files changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index b78b53198a2e..2a2f6448a5fb 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -285,9 +285,10 @@ struct bpf_list_node_kern {
> */
> struct bpf_map_owner {
> enum bpf_prog_type type;
> - bool jited;
> - bool xdp_has_frags;
> - bool sleepable;
> + u32 jited:1,
> + xdp_has_frags:1,
> + sleepable:1,
> + kprobe_write_ctx:1;
Don't you see how much churn you're adding this way?
Every patch has to touch two lines instead of one.
Use
u32 jited:1;
u32 xdp_has_frags:1;
also the bot is correct on patch 2 and 3.
Don't be fancy. Require strict conformance both ways in *all* patches.
And your codex selftests are garbage. I don't have other words
to describe it. They are not testing the actual bug that
your patches are fixing. Think of what you're doing.
Asking LLM to write a test for your other patch is not what you
should be asking it to do. The selftest should be such that
it proves the unsafety/crash before the fix.
pw-bot: cr
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH bpf-next 2/8] bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx progs
2026-02-24 16:57 ` Alexei Starovoitov
@ 2026-02-25 15:15 ` Leon Hwang
0 siblings, 0 replies; 13+ messages in thread
From: Leon Hwang @ 2026-02-25 15:15 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
John Fastabend, KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa,
Shuah Khan, Feng Yang, Menglong Dong, Puranjay Mohan,
Björn Töpel, Pu Lehui, LKML,
open list:KERNEL SELFTEST FRAMEWORK, Network Development,
kernel-patches-bot
On 2026/2/25 00:57, Alexei Starovoitov wrote:
> On Tue, Feb 24, 2026 at 7:41 AM Leon Hwang <leon.hwang@linux.dev> wrote:
>>
>> uprobe programs that can modify pt_regs require different runtime
>> assumptions than pt_regs-read-only uprobe programs. Mixing both in
>> one prog_array can make owner expectations diverge from callee behavior.
>>
>> Reject the combination of !kprobe_write_ctx progs with kprobe_write_ctx
>> progs in __bpf_prog_map_compatible() to address the issue.
>>
>> Fixes: 7384893d970e ("bpf: Allow uprobe program to change context registers")
>> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
>> ---
>> include/linux/bpf.h | 7 ++++---
>> kernel/bpf/core.c | 3 +++
>> 2 files changed, 7 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index b78b53198a2e..2a2f6448a5fb 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -285,9 +285,10 @@ struct bpf_list_node_kern {
>> */
>> struct bpf_map_owner {
>> enum bpf_prog_type type;
>> - bool jited;
>> - bool xdp_has_frags;
>> - bool sleepable;
>> + u32 jited:1,
>> + xdp_has_frags:1,
>> + sleepable:1,
>> + kprobe_write_ctx:1;
>
> Don't you see how much churn you're adding this way?
> Every patch has to touch two lines instead of one.
> Use
> u32 jited:1;
> u32 xdp_has_frags:1;
>
Ack.
> also the bot is correct on patch 2 and 3.
Agreed.
Here's a concrete example that breaks the constraint:
struct {
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__uint(max_entries, 1);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(__u32));
} jmp_table SEC(".maps");
SEC("?kprobe")
int prog_a(struct pt_regs *regs)
{
regs->ax = 0;
bpf_tail_call_static(regs, &jmp_table, 0);
return 0;
}
SEC("?kprobe")
int prog_b(struct pt_regs *regs)
{
bpf_tail_call_static(regs, &jmp_table, 0);
return 0;
}
The jmp_table is shared between prog_a and prog_b.
The constraint can be broken by:
* Load prog_a first.
At this point, owner->kprobe_write_ctx=true.
* Load prog_b next.
At this point, prog_b passes the prog map compatibility validation.
* Add prog_a to jmp_table.
* Attach prog_b to a kernel function.
When the kernel function runs, the regs will be updated via prog_a.
> Don't be fancy. Require strict conformance both ways in *all* patches.
>
It was to avoid awkward UX.
For example, the tail call from prog_a (kprobe_write_ctx=true) to prog_b
(kprobe_write_ctx=false) should be allowed. If prog_b is required to be
kprobe_write_ctx=true, prog_b will break user's expectation that prog_b
should not always update ctx.
The same awkward UX applies to call_get_func_ip, call_session_cookie,
and call_session_is_return.
I'll find a way to avoid such awkward UX by keeping the one-directional
validation, and to avoid the aforementioned constraint-broken issue at
the same time.
> And your codex selftests are garbage. I don't have other words
> to describe it. They are not testing the actual bug that
> your patches are fixing. Think of what you're doing.
> Asking LLM to write a test for your other patch is not what you
> should be asking it to do. The selftest should be such that
> it proves the unsafety/crash before the fix.
>
OK. I'll reimplement the selftests by myself in the next revision.
Thanks,
Leon
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-02-25 15:16 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-24 15:40 [PATCH bpf-next 0/8] bpf: Enhance __bpf_prog_map_compatible() Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 1/8] bpf: Add fsession to verbose log in check_get_func_ip() Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 2/8] bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx progs Leon Hwang
2026-02-24 16:22 ` bot+bpf-ci
2026-02-24 16:57 ` Alexei Starovoitov
2026-02-25 15:15 ` Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 3/8] bpf: Disallow !call_get_func_ip progs tail-calling call_get_func_ip progs Leon Hwang
2026-02-24 16:35 ` bot+bpf-ci
2026-02-24 15:40 ` [PATCH bpf-next 4/8] bpf: Disallow !call_session_cookie progs tail-calling call_session_cookie progs Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 5/8] bpf: Disallow !call_session_is_return progs tail-calling call_session_is_return progs Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 6/8] selftests/bpf: Add a test to verify kprobe_write_ctx compatibility enforcement Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 7/8] selftests/bpf: Add a test to verify call_get_func_ip " Leon Hwang
2026-02-24 15:40 ` [PATCH bpf-next 8/8] selftests/bpf: Add a test to verify session-kfunc " Leon Hwang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox