summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2026-10-17 23:09:38 +0000
committerAlexei Starovoitov <ast@kernel.org>2026-10-18 00:36:43 +0000
commitb6458abbafe4bf4b992d2c5ee06ab529e8428591 (patch)
treed191f35c56ad48cff166056e97af0fab19d5fb1a /kernel
parentf693030a187b56a3946b36521bb90d785f906669 (diff)
downloadlinux-b6458abbafe4bf4b992d2c5ee06ab529e8428591.tar.gz
linux-b6458abbafe4bf4b992d2c5ee06ab529e8428591.zip
bpf: Don't take an extension for a function that runs sleepable
An extension cannot be sleepable, and it is verified as a program that runs under the RCU read lock. But it runs in the context of the function that it replaces. For a sleepable program, or a function that is called from a bpf_wq or bpf_task_work callback, that is rcu_read_lock_trace(). The verifier lets such an extension use maps and pointers that rely on RCU. Its maps are not counted as maps with sleepable users either, so that what it got from them is freed behind a plain RCU grace period: WARNING: net/core/sock_map.c:903 at __sock_hash_lookup_elem+0xe8/0xf0 BUG: KASAN: slab-use-after-free in bpf_prog_b3bad285227d855b_ext_storage+0x245/0x297 Write of size 8 at addr ffff888108717a50 by task fr/955 The verifier knows the contexts that a global function is called in. Refuse to replace one that is called without the RCU read lock, and the main function of a sleepable program. A function that sleepable code only calls under bpf_rcu_read_lock() can still be replaced. The summarization test has replaced functions of sleepable programs by ones that do not sleep. Expect that to fail. Fixes: 1e6c62a88215 ("bpf: Introduce sleepable BPF programs") Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20261017230950.802052-5-alexei.starovoitov@gmail.com
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/verifier.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2c812a5f1da8..d738ce6e7428 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -22151,6 +22151,21 @@ static int check_unreliable_func_args(struct bpf_verifier_log *log, struct btf *
return -EINVAL;
}
+/*
+ * An extension is verified as a program that runs under the RCU read lock. Does
+ * the function that it is to replace?
+ */
+static bool func_has_rcu_read_lock(const struct bpf_prog *prog, int subprog)
+{
+ const struct bpf_func_info_aux *sub_aux = &prog->aux->func_info_aux[subprog];
+
+ if (!subprog)
+ return !prog->sleepable;
+
+ return !sub_aux->called[BPF_FUNC_CTX_SLEEPABLE] &&
+ !sub_aux->called[BPF_FUNC_CTX_NO_RCU_LOCK];
+}
+
int bpf_check_attach_target(struct bpf_verifier_log *log,
const struct bpf_prog *prog,
const struct bpf_prog *tgt_prog,
@@ -22247,6 +22262,11 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
"Cannot extend a writable raw tracepoint program\n");
return -EINVAL;
}
+ if (!func_has_rcu_read_lock(tgt_prog, subprog)) {
+ bpf_log(log,
+ "Cannot extend a function that runs without RCU read lock\n");
+ return -EINVAL;
+ }
tgt_changes_pkt_data = aux->func
? aux->func[subprog]->aux->changes_pkt_data
: aux->changes_pkt_data;