diff options
| author | Alexei Starovoitov <ast@kernel.org> | 2026-10-17 23:09:38 +0000 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-10-18 00:36:43 +0000 |
| commit | b6458abbafe4bf4b992d2c5ee06ab529e8428591 (patch) | |
| tree | d191f35c56ad48cff166056e97af0fab19d5fb1a /kernel | |
| parent | f693030a187b56a3946b36521bb90d785f906669 (diff) | |
| download | linux-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.c | 20 |
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; |
