Subject: [PATCH bpf-next 2/8] bpf: Disallow !kprobe_write_ctx progs tail-calling kprobe_write_ctx progs

From: Leon Hwang <[email-masked]>
Date: Tue, 24 Feb 2026 23:40:18 +0800

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 <[email-masked]>
---
 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