Skip to content

Commit b2d8ef1

Browse files
davemarchevskyAlexei Starovoitov
authored andcommitted
bpf: Cleanup check_refcount_ok
Discussion around a recently-submitted patch provided historical context for check_refcount_ok [0]. Specifically, the function and its helpers - may_be_acquire_function and arg_type_may_be_refcounted - predate the OBJ_RELEASE type flag and the addition of many more helpers with acquire/release semantics. The purpose of check_refcount_ok is to ensure: 1) Helper doesn't have multiple uses of return reg's ref_obj_id 2) Helper with release semantics only has one arg needing to be released, since that's tracked using meta->ref_obj_id With current verifier, it's safe to remove check_refcount_ok and its helpers. Since addition of OBJ_RELEASE type flag, case 2) has been handled by the arg_type_is_release check in check_func_arg. To ensure case 1) won't result in verifier silently prioritizing one use of ref_obj_id, this patch adds a helper_multiple_ref_obj_use check which fails loudly if a helper passes > 1 test for use of ref_obj_id. [0]: lore.kernel.org/bpf/20220713234529.4154673-1-davemarchevsky@fb.com Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Joanne Koong <joannelkoong@gmail.com> Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20220808171559.3251090-1-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 6e11628 commit b2d8ef1

File tree

1 file changed

+29
-45
lines changed

1 file changed

+29
-45
lines changed

kernel/bpf/verifier.c

Lines changed: 29 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -467,25 +467,11 @@ static bool type_is_rdonly_mem(u32 type)
467467
return type & MEM_RDONLY;
468468
}
469469

470-
static bool arg_type_may_be_refcounted(enum bpf_arg_type type)
471-
{
472-
return type == ARG_PTR_TO_SOCK_COMMON;
473-
}
474-
475470
static bool type_may_be_null(u32 type)
476471
{
477472
return type & PTR_MAYBE_NULL;
478473
}
479474

480-
static bool may_be_acquire_function(enum bpf_func_id func_id)
481-
{
482-
return func_id == BPF_FUNC_sk_lookup_tcp ||
483-
func_id == BPF_FUNC_sk_lookup_udp ||
484-
func_id == BPF_FUNC_skc_lookup_tcp ||
485-
func_id == BPF_FUNC_map_lookup_elem ||
486-
func_id == BPF_FUNC_ringbuf_reserve;
487-
}
488-
489475
static bool is_acquire_function(enum bpf_func_id func_id,
490476
const struct bpf_map *map)
491477
{
@@ -518,6 +504,26 @@ static bool is_ptr_cast_function(enum bpf_func_id func_id)
518504
func_id == BPF_FUNC_skc_to_tcp_request_sock;
519505
}
520506

507+
static bool is_dynptr_acquire_function(enum bpf_func_id func_id)
508+
{
509+
return func_id == BPF_FUNC_dynptr_data;
510+
}
511+
512+
static bool helper_multiple_ref_obj_use(enum bpf_func_id func_id,
513+
const struct bpf_map *map)
514+
{
515+
int ref_obj_uses = 0;
516+
517+
if (is_ptr_cast_function(func_id))
518+
ref_obj_uses++;
519+
if (is_acquire_function(func_id, map))
520+
ref_obj_uses++;
521+
if (is_dynptr_acquire_function(func_id))
522+
ref_obj_uses++;
523+
524+
return ref_obj_uses > 1;
525+
}
526+
521527
static bool is_cmpxchg_insn(const struct bpf_insn *insn)
522528
{
523529
return BPF_CLASS(insn->code) == BPF_STX &&
@@ -6453,33 +6459,6 @@ static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
64536459
return true;
64546460
}
64556461

6456-
static bool check_refcount_ok(const struct bpf_func_proto *fn, int func_id)
6457-
{
6458-
int count = 0;
6459-
6460-
if (arg_type_may_be_refcounted(fn->arg1_type))
6461-
count++;
6462-
if (arg_type_may_be_refcounted(fn->arg2_type))
6463-
count++;
6464-
if (arg_type_may_be_refcounted(fn->arg3_type))
6465-
count++;
6466-
if (arg_type_may_be_refcounted(fn->arg4_type))
6467-
count++;
6468-
if (arg_type_may_be_refcounted(fn->arg5_type))
6469-
count++;
6470-
6471-
/* A reference acquiring function cannot acquire
6472-
* another refcounted ptr.
6473-
*/
6474-
if (may_be_acquire_function(func_id) && count)
6475-
return false;
6476-
6477-
/* We only support one arg being unreferenced at the moment,
6478-
* which is sufficient for the helper functions we have right now.
6479-
*/
6480-
return count <= 1;
6481-
}
6482-
64836462
static bool check_btf_id_ok(const struct bpf_func_proto *fn)
64846463
{
64856464
int i;
@@ -6502,8 +6481,7 @@ static int check_func_proto(const struct bpf_func_proto *fn, int func_id)
65026481
{
65036482
return check_raw_mode_ok(fn) &&
65046483
check_arg_pair_ok(fn) &&
6505-
check_btf_id_ok(fn) &&
6506-
check_refcount_ok(fn, func_id) ? 0 : -EINVAL;
6484+
check_btf_id_ok(fn) ? 0 : -EINVAL;
65076485
}
65086486

65096487
/* Packet data might have moved, any old PTR_TO_PACKET[_META,_END]
@@ -7473,6 +7451,12 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
74737451
if (type_may_be_null(regs[BPF_REG_0].type))
74747452
regs[BPF_REG_0].id = ++env->id_gen;
74757453

7454+
if (helper_multiple_ref_obj_use(func_id, meta.map_ptr)) {
7455+
verbose(env, "verifier internal error: func %s#%d sets ref_obj_id more than once\n",
7456+
func_id_name(func_id), func_id);
7457+
return -EFAULT;
7458+
}
7459+
74767460
if (is_ptr_cast_function(func_id)) {
74777461
/* For release_reference() */
74787462
regs[BPF_REG_0].ref_obj_id = meta.ref_obj_id;
@@ -7485,10 +7469,10 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
74857469
regs[BPF_REG_0].id = id;
74867470
/* For release_reference() */
74877471
regs[BPF_REG_0].ref_obj_id = id;
7488-
} else if (func_id == BPF_FUNC_dynptr_data) {
7472+
} else if (is_dynptr_acquire_function(func_id)) {
74897473
int dynptr_id = 0, i;
74907474

7491-
/* Find the id of the dynptr we're acquiring a reference to */
7475+
/* Find the id of the dynptr we're tracking the reference of */
74927476
for (i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) {
74937477
if (arg_type_is_dynptr(fn->arg_type[i])) {
74947478
if (dynptr_id) {

0 commit comments

Comments
 (0)