Message ID | 20230424192924.1549667-1-davemarchevsky@fb.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | BPF |
Headers | show |
Series | [bpf-next] bpf: Disable bpf_refcount_acquire kfunc calls until race conditions are fixed | expand |
On Mon, Apr 24, 2023 at 12:29 PM Dave Marchevsky <davemarchevsky@fb.com> wrote: > > As reported by Kumar in [0], the shared ownership implementation for BPF > programs has some race conditions which need to be addressed before it > can safely be used. This patch does so in a minimal way instead of > ripping out shared ownership entirely, as proper fixes for the issues > raised will follow ASAP, at which point this patch's commit can be > reverted to re-enable shared ownership. > > The patch removes the ability to call bpf_refcount_acquire_impl from BPF > programs. Programs can only bump refcount and obtain a new owning > reference using this kfunc, so removing the ability to call it > effectively disables shared ownership. > > Instead of changing success / failure expectations for > bpf_refcount-related selftests, this patch just disables them from > running for now. > > [0]: https://lore.kernel.org/bpf/d7hyspcow5wtjcmw4fugdgyp3fwhljwuscp3xyut5qnwivyeru@ysdq543otzv2/ > > Reported-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> > Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com> > --- > kernel/bpf/helpers.c | 1 - > kernel/bpf/verifier.c | 21 +++---------------- > .../bpf/prog_tests/refcounted_kptr.c | 2 -- > 3 files changed, 3 insertions(+), 21 deletions(-) > > diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c > index 8d368fa353f9..3886b9815a25 100644 > --- a/kernel/bpf/helpers.c > +++ b/kernel/bpf/helpers.c > @@ -2325,7 +2325,6 @@ BTF_ID_FLAGS(func, crash_kexec, KF_DESTRUCTIVE) > #endif > BTF_ID_FLAGS(func, bpf_obj_new_impl, KF_ACQUIRE | KF_RET_NULL) > BTF_ID_FLAGS(func, bpf_obj_drop_impl, KF_RELEASE) > -BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE) > BTF_ID_FLAGS(func, bpf_list_push_front_impl) > BTF_ID_FLAGS(func, bpf_list_push_back_impl) > BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 0d73139ee4d8..9926046f30c2 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -9579,7 +9579,6 @@ enum kfunc_ptr_arg_type { > enum special_kfunc_type { > KF_bpf_obj_new_impl, > KF_bpf_obj_drop_impl, > - KF_bpf_refcount_acquire_impl, > KF_bpf_list_push_front_impl, > KF_bpf_list_push_back_impl, > KF_bpf_list_pop_front, > @@ -9600,7 +9599,6 @@ enum special_kfunc_type { > BTF_SET_START(special_kfunc_set) > BTF_ID(func, bpf_obj_new_impl) > BTF_ID(func, bpf_obj_drop_impl) > -BTF_ID(func, bpf_refcount_acquire_impl) > BTF_ID(func, bpf_list_push_front_impl) > BTF_ID(func, bpf_list_push_back_impl) > BTF_ID(func, bpf_list_pop_front) > @@ -9619,7 +9617,6 @@ BTF_SET_END(special_kfunc_set) > BTF_ID_LIST(special_kfunc_list) > BTF_ID(func, bpf_obj_new_impl) > BTF_ID(func, bpf_obj_drop_impl) > -BTF_ID(func, bpf_refcount_acquire_impl) > BTF_ID(func, bpf_list_push_front_impl) > BTF_ID(func, bpf_list_push_back_impl) > BTF_ID(func, bpf_list_pop_front) > @@ -9929,8 +9926,7 @@ static bool is_bpf_rbtree_api_kfunc(u32 btf_id) > > static bool is_bpf_graph_api_kfunc(u32 btf_id) > { > - return is_bpf_list_api_kfunc(btf_id) || is_bpf_rbtree_api_kfunc(btf_id) || > - btf_id == special_kfunc_list[KF_bpf_refcount_acquire_impl]; > + return is_bpf_list_api_kfunc(btf_id) || is_bpf_rbtree_api_kfunc(btf_id); > } > > static bool is_callback_calling_kfunc(u32 btf_id) > @@ -10691,8 +10687,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, > if (is_kfunc_acquire(&meta) && !btf_type_is_struct_ptr(meta.btf, t)) { > /* Only exception is bpf_obj_new_impl */ > if (meta.btf != btf_vmlinux || > - (meta.func_id != special_kfunc_list[KF_bpf_obj_new_impl] && > - meta.func_id != special_kfunc_list[KF_bpf_refcount_acquire_impl])) { > + (meta.func_id != special_kfunc_list[KF_bpf_obj_new_impl])) { > verbose(env, "acquire kernel function does not return PTR_TO_BTF_ID\n"); > return -EINVAL; > } > @@ -10740,15 +10735,6 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, > insn_aux->obj_new_size = ret_t->size; > insn_aux->kptr_struct_meta = > btf_find_struct_meta(ret_btf, ret_btf_id); > - } else if (meta.func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl]) { > - mark_reg_known_zero(env, regs, BPF_REG_0); > - regs[BPF_REG_0].type = PTR_TO_BTF_ID | MEM_ALLOC; > - regs[BPF_REG_0].btf = meta.arg_refcount_acquire.btf; > - regs[BPF_REG_0].btf_id = meta.arg_refcount_acquire.btf_id; > - > - insn_aux->kptr_struct_meta = > - btf_find_struct_meta(meta.arg_refcount_acquire.btf, > - meta.arg_refcount_acquire.btf_id); > } else if (meta.func_id == special_kfunc_list[KF_bpf_list_pop_front] || > meta.func_id == special_kfunc_list[KF_bpf_list_pop_back]) { > struct btf_field *field = meta.arg_list_head.field; > @@ -17417,8 +17403,7 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, > insn_buf[2] = addr[1]; > insn_buf[3] = *insn; > *cnt = 4; > - } else if (desc->func_id == special_kfunc_list[KF_bpf_obj_drop_impl] || > - desc->func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl]) { > + } else if (desc->func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) { > struct btf_struct_meta *kptr_struct_meta = env->insn_aux_data[insn_idx].kptr_struct_meta; > struct bpf_insn addr[2] = { BPF_LD_IMM64(BPF_REG_2, (long)kptr_struct_meta) }; imo that is too much. Could you disable it with a single line that is easy to revert? Something like this: diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 0d73139ee4d8..c558a35cb19e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10509,6 +10509,10 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ verbose(env, "arg#%d doesn't point to a type with bpf_refcount field\n", i); return -EINVAL; } + if (rec->refcount_off >= 0) { + verbose(env, "disabled for now\n"); + return -EINVAL; + } > diff --git a/tools/testing/selftests/bpf/prog_tests/refcounted_kptr.c b/tools/testing/selftests/bpf/prog_tests/refcounted_kptr.c > index 2ab23832062d..595cbf92bff5 100644 > --- a/tools/testing/selftests/bpf/prog_tests/refcounted_kptr.c > +++ b/tools/testing/selftests/bpf/prog_tests/refcounted_kptr.c > @@ -9,10 +9,8 @@ > > void test_refcounted_kptr(void) > { > - RUN_TESTS(refcounted_kptr); > } > > void test_refcounted_kptr_fail(void) > { > - RUN_TESTS(refcounted_kptr_fail); > } and these two, of course. > -- > 2.34.1 >
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 8d368fa353f9..3886b9815a25 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2325,7 +2325,6 @@ BTF_ID_FLAGS(func, crash_kexec, KF_DESTRUCTIVE) #endif BTF_ID_FLAGS(func, bpf_obj_new_impl, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_obj_drop_impl, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE) BTF_ID_FLAGS(func, bpf_list_push_front_impl) BTF_ID_FLAGS(func, bpf_list_push_back_impl) BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 0d73139ee4d8..9926046f30c2 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -9579,7 +9579,6 @@ enum kfunc_ptr_arg_type { enum special_kfunc_type { KF_bpf_obj_new_impl, KF_bpf_obj_drop_impl, - KF_bpf_refcount_acquire_impl, KF_bpf_list_push_front_impl, KF_bpf_list_push_back_impl, KF_bpf_list_pop_front, @@ -9600,7 +9599,6 @@ enum special_kfunc_type { BTF_SET_START(special_kfunc_set) BTF_ID(func, bpf_obj_new_impl) BTF_ID(func, bpf_obj_drop_impl) -BTF_ID(func, bpf_refcount_acquire_impl) BTF_ID(func, bpf_list_push_front_impl) BTF_ID(func, bpf_list_push_back_impl) BTF_ID(func, bpf_list_pop_front) @@ -9619,7 +9617,6 @@ BTF_SET_END(special_kfunc_set) BTF_ID_LIST(special_kfunc_list) BTF_ID(func, bpf_obj_new_impl) BTF_ID(func, bpf_obj_drop_impl) -BTF_ID(func, bpf_refcount_acquire_impl) BTF_ID(func, bpf_list_push_front_impl) BTF_ID(func, bpf_list_push_back_impl) BTF_ID(func, bpf_list_pop_front) @@ -9929,8 +9926,7 @@ static bool is_bpf_rbtree_api_kfunc(u32 btf_id) static bool is_bpf_graph_api_kfunc(u32 btf_id) { - return is_bpf_list_api_kfunc(btf_id) || is_bpf_rbtree_api_kfunc(btf_id) || - btf_id == special_kfunc_list[KF_bpf_refcount_acquire_impl]; + return is_bpf_list_api_kfunc(btf_id) || is_bpf_rbtree_api_kfunc(btf_id); } static bool is_callback_calling_kfunc(u32 btf_id) @@ -10691,8 +10687,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, if (is_kfunc_acquire(&meta) && !btf_type_is_struct_ptr(meta.btf, t)) { /* Only exception is bpf_obj_new_impl */ if (meta.btf != btf_vmlinux || - (meta.func_id != special_kfunc_list[KF_bpf_obj_new_impl] && - meta.func_id != special_kfunc_list[KF_bpf_refcount_acquire_impl])) { + (meta.func_id != special_kfunc_list[KF_bpf_obj_new_impl])) { verbose(env, "acquire kernel function does not return PTR_TO_BTF_ID\n"); return -EINVAL; } @@ -10740,15 +10735,6 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, insn_aux->obj_new_size = ret_t->size; insn_aux->kptr_struct_meta = btf_find_struct_meta(ret_btf, ret_btf_id); - } else if (meta.func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl]) { - mark_reg_known_zero(env, regs, BPF_REG_0); - regs[BPF_REG_0].type = PTR_TO_BTF_ID | MEM_ALLOC; - regs[BPF_REG_0].btf = meta.arg_refcount_acquire.btf; - regs[BPF_REG_0].btf_id = meta.arg_refcount_acquire.btf_id; - - insn_aux->kptr_struct_meta = - btf_find_struct_meta(meta.arg_refcount_acquire.btf, - meta.arg_refcount_acquire.btf_id); } else if (meta.func_id == special_kfunc_list[KF_bpf_list_pop_front] || meta.func_id == special_kfunc_list[KF_bpf_list_pop_back]) { struct btf_field *field = meta.arg_list_head.field; @@ -17417,8 +17403,7 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, insn_buf[2] = addr[1]; insn_buf[3] = *insn; *cnt = 4; - } else if (desc->func_id == special_kfunc_list[KF_bpf_obj_drop_impl] || - desc->func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl]) { + } else if (desc->func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) { struct btf_struct_meta *kptr_struct_meta = env->insn_aux_data[insn_idx].kptr_struct_meta; struct bpf_insn addr[2] = { BPF_LD_IMM64(BPF_REG_2, (long)kptr_struct_meta) }; diff --git a/tools/testing/selftests/bpf/prog_tests/refcounted_kptr.c b/tools/testing/selftests/bpf/prog_tests/refcounted_kptr.c index 2ab23832062d..595cbf92bff5 100644 --- a/tools/testing/selftests/bpf/prog_tests/refcounted_kptr.c +++ b/tools/testing/selftests/bpf/prog_tests/refcounted_kptr.c @@ -9,10 +9,8 @@ void test_refcounted_kptr(void) { - RUN_TESTS(refcounted_kptr); } void test_refcounted_kptr_fail(void) { - RUN_TESTS(refcounted_kptr_fail); }
As reported by Kumar in [0], the shared ownership implementation for BPF programs has some race conditions which need to be addressed before it can safely be used. This patch does so in a minimal way instead of ripping out shared ownership entirely, as proper fixes for the issues raised will follow ASAP, at which point this patch's commit can be reverted to re-enable shared ownership. The patch removes the ability to call bpf_refcount_acquire_impl from BPF programs. Programs can only bump refcount and obtain a new owning reference using this kfunc, so removing the ability to call it effectively disables shared ownership. Instead of changing success / failure expectations for bpf_refcount-related selftests, this patch just disables them from running for now. [0]: https://lore.kernel.org/bpf/d7hyspcow5wtjcmw4fugdgyp3fwhljwuscp3xyut5qnwivyeru@ysdq543otzv2/ Reported-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com> --- kernel/bpf/helpers.c | 1 - kernel/bpf/verifier.c | 21 +++---------------- .../bpf/prog_tests/refcounted_kptr.c | 2 -- 3 files changed, 3 insertions(+), 21 deletions(-)