Skip to content

Commit 9962ef9

Browse files
kkdwvdKernel Patches Daemon
authored andcommitted
bpf: Enforce RCU protection for KF_RCU_PROTECTED
Currently, KF_RCU_PROTECTED only applies to iterator APIs and that too in a convoluted fashion: the presence of this flag on the kfunc is used to set MEM_RCU in iterator type, and the lack of RCU protection results in an error only later, once next() or destroy() methods are invoked on the iterator. While there is no bug, this is certainly a bit unintuitive, and makes the enforcement of the flag iterator specific. In the interest of making this flag useful for other upcoming kfuncs, e.g. scx_bpf_cpu_curr() [0][1], add enforcement for invoking the kfunc in an RCU critical section in general. This would also mean that iterator APIs using KF_RCU_PROTECTED will error out earlier, instead of throwing an error for lack of RCU CS protection when next() or destroy() methods are invoked. [0]: https://lore.kernel.org/all/[email protected] [1]: https://lore.kernel.org/all/[email protected] Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]>
1 parent cde4d9b commit 9962ef9

File tree

4 files changed

+20
-4
lines changed

4 files changed

+20
-4
lines changed

Documentation/bpf/kfuncs.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,20 @@ consider doing refcnt != 0 check, especially when returning a KF_ACQUIRE
335335
pointer. Note as well that a KF_ACQUIRE kfunc that is KF_RCU should very likely
336336
also be KF_RET_NULL.
337337

338+
2.4.8 KF_RCU_PROTECTED flag
339+
---------------------------
340+
341+
The KF_RCU_PROTECTED flag is used to indicate that the kfunc must be invoked in
342+
an RCU critical section. This is assumed by default in non-sleepable programs,
343+
and must be explicitly ensured by calling ``bpf_rcu_read_lock`` for sleepable
344+
ones. The flag is distinct from the ``KF_RCU`` flag, which only ensures that its
345+
arguments are at least RCU protected pointers. This may transitively imply that
346+
RCU protection is ensured, but it does not work in cases of kfuncs which require
347+
RCU protection but do not take RCU protected arguments.
348+
338349
.. _KF_deprecated_flag:
339350

340-
2.4.8 KF_DEPRECATED flag
351+
2.4.9 KF_DEPRECATED flag
341352
------------------------
342353

343354
The KF_DEPRECATED flag is used for kfuncs which are scheduled to be

kernel/bpf/verifier.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13916,6 +13916,11 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1391613916
return -EACCES;
1391713917
}
1391813918

13919+
if (is_kfunc_rcu_protected(&meta) && !in_rcu_cs(env)) {
13920+
verbose(env, "kernel func %s requires RCU critical section protection\n", func_name);
13921+
return -EACCES;
13922+
}
13923+
1391913924
/* In case of release function, we get register number of refcounted
1392013925
* PTR_TO_BTF_ID in bpf_kfunc_arg_meta, do the release now.
1392113926
*/

tools/testing/selftests/bpf/progs/cgroup_read_xattr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ int BPF_PROG(use_css_iter_non_sleepable)
7373
}
7474

7575
SEC("lsm.s/socket_connect")
76-
__failure __msg("expected an RCU CS")
76+
__failure __msg("kernel func bpf_iter_css_new requires RCU critical section protection")
7777
int BPF_PROG(use_css_iter_sleepable_missing_rcu_lock)
7878
{
7979
u64 cgrp_id = bpf_get_current_cgroup_id();

tools/testing/selftests/bpf/progs/iters_task_failure.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ void bpf_rcu_read_lock(void) __ksym;
1515
void bpf_rcu_read_unlock(void) __ksym;
1616

1717
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
18-
__failure __msg("expected an RCU CS when using bpf_iter_task_next")
18+
__failure __msg("kernel func bpf_iter_task_new requires RCU critical section protection")
1919
int BPF_PROG(iter_tasks_without_lock)
2020
{
2121
struct task_struct *pos;
@@ -27,7 +27,7 @@ int BPF_PROG(iter_tasks_without_lock)
2727
}
2828

2929
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
30-
__failure __msg("expected an RCU CS when using bpf_iter_css_next")
30+
__failure __msg("kernel func bpf_iter_css_new requires RCU critical section protection")
3131
int BPF_PROG(iter_css_without_lock)
3232
{
3333
u64 cg_id = bpf_get_current_cgroup_id();

0 commit comments

Comments
 (0)