diff options
| author | Josef Bacik <josef@toxicpanda.com> | 2026-10-17 16:37:26 +0000 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-10-17 22:01:14 +0000 |
| commit | 3e6d7522af2cd1b8bf135ee7df6ca962986f44d6 (patch) | |
| tree | f667ebed8ccada167347f05d433e3d723b1dc9b7 /include/linux | |
| parent | 927c9c985f3ef4d30c086884b7e0ecb933f742ef (diff) | |
bpf: Check the maps that sleepable callbacks use
Sleepable programs can only use the kinds of map that do without an RCU
read side critical section. check_map_prog_compatibility() sees to that
when a map is bound to the program, and asks whether the program is
sleepable. That misses the bpf_wq or bpf_task_work callback of a program
that is not, which runs sleepable all the same, and it misses an inner
map, which is not bound.
The bpf_wq callback of a tc program that looks a key up in a sockhash
gets as far as
WARNING: net/core/sock_map.c:903 at __sock_hash_lookup_elem+0x18f/0x1e0
Ask the same question for the map that is handed to a helper in sleepable
context, unless the RCU read lock is held: by bpf_rcu_read_lock(), or by
the helper that runs the callback, as bpf_for_each_map_elem() does for a
hash map. Programs that take the lock go on working. Disabled preemption
or interrupts are not enough, since the maps ask for rcu_read_lock_held().
The other parts of the program may use such a map as before.
A global function that is called with preemption or interrupts disabled is
verified for the non-sleepable context, in which nothing is known of all
that. Verify it for a context of its own: not sleepable, and without the
RCU read lock. It differs in what maps can be used, and in nothing else.
What is refused from now on runs into the warning above, or uses what the
map frees behind a plain RCU grace period: an entry of a devmap, of a perf
event array or of a cgroup array.
A bloom filter does without RCU. Add it to the list, so that callbacks
which use one go on loading. As a side effect sleepable programs can use
bloom filters as well.
A pointer to the value of a devmap which a program keeps beyond
bpf_rcu_read_unlock() is not dealt with here.
Fixes: 638e4b825d52 ("bpf: Allows per-cpu maps and map-in-map in sleepable programs")
Fixes: 8e83da9732d9 ("bpf: add bpf_wq_start")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261017163745.3341787-25-alexei.starovoitov@gmail.com
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/bpf.h | 14 | ||||
| -rw-r--r-- | include/linux/bpf_verifier.h | 2 |
2 files changed, 13 insertions, 3 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index db56d5d07462..1823ca3a1d5e 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1742,12 +1742,20 @@ static inline void bpf_trampoline_multi_detach(struct bpf_prog *prog, static inline void bpf_trampoline_set_flags(struct bpf_trampoline *tr, u32 flags) {} #endif +/* The contexts that a global function is called in, and is verified for. */ +enum bpf_func_context { + BPF_FUNC_CTX_NON_SLEEPABLE, + BPF_FUNC_CTX_SLEEPABLE, + /* Sleepable code has disabled preemption or interrupts: no RCU read lock. */ + BPF_FUNC_CTX_NO_RCU_LOCK, + BPF_FUNC_CTX_CNT, +}; + struct bpf_func_info_aux { u16 linkage; bool unreliable; - /* Indexed by in_sleepable. */ - bool called[2]; - bool verified[2]; + bool called[BPF_FUNC_CTX_CNT]; + bool verified[BPF_FUNC_CTX_CNT]; }; enum bpf_jit_poke_reason { diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 816948df8fff..e420d211f423 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -1090,6 +1090,8 @@ struct bpf_verifier_env { bool bypass_spec_v1; bool bypass_spec_v4; bool seen_direct_write; + /* a global function is verified for BPF_FUNC_CTX_NO_RCU_LOCK */ + bool no_rcu_read_lock; bool seen_exception; bool signature; u32 insn_aux_data_len; |
