diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c index 5945956a7573..32f346ce3ffc 100644 --- a/kernel/bpf/states.c +++ b/kernel/bpf/states.c @@ -343,8 +343,12 @@ static bool check_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) return true; } - /* We ran out of idmap slots, which should be impossible */ - WARN_ON_ONCE(1); + /* + * idmap slots are bounded by the number of registers and stack slots. + * Since referenced dynptrs acquire intermediate references that do + * not live in either, so the map can be exhausted. Since it is unlikely, + * fail the verification by treating the states as not equivalent. + */ return false; } @@ -890,6 +894,9 @@ static bool refsafe(struct bpf_verifier_state *old, struct bpf_verifier_state *c return false; switch (old->refs[i].type) { case REF_TYPE_PTR: + if (!check_ids(old->refs[i].parent_id, cur->refs[i].parent_id, idmap)) + return false; + break; case REF_TYPE_IRQ: break; case REF_TYPE_LOCK: diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 7d27ba396d32..3b874bbbaac0 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -12817,9 +12817,10 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, struct bpf_kfunc_call_arg_meta meta; struct bpf_insn_aux_data *insn_aux; int err, insn_idx = *insn_idx_p; - u32 i, nargs, ptr_type_id, id; const struct btf_param *args; + u32 i, nargs, ptr_type_id; struct btf *desc_btf; + int id; /* skip for now, but return error when we find this in fixup_kfunc_call */ if (!insn->imm) @@ -18362,9 +18363,13 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog) /* Acquire references for struct_ops program arguments tagged with "__ref" */ if (!subprog && env->prog->type == BPF_PROG_TYPE_STRUCT_OPS) { - for (i = 0; i < aux->ctx_arg_info_size; i++) - aux->ctx_arg_info[i].ref_id = aux->ctx_arg_info[i].refcounted ? - acquire_reference(env, 0, 0) : 0; + for (i = 0; i < aux->ctx_arg_info_size; i++) { + ret = aux->ctx_arg_info[i].refcounted ? acquire_reference(env, 0, 0) : 0; + if (ret < 0) + goto out; + + aux->ctx_arg_info[i].ref_id = ret; + } } ret = do_check(env); diff --git a/tools/testing/selftests/bpf/progs/file_reader_fail.c b/tools/testing/selftests/bpf/progs/file_reader_fail.c index d5fae5e4cf9a..3bb9e2612f8f 100644 --- a/tools/testing/selftests/bpf/progs/file_reader_fail.c +++ b/tools/testing/selftests/bpf/progs/file_reader_fail.c @@ -87,7 +87,8 @@ int use_file_dynptr_slice_after_put_file(void *ctx) struct task_struct *task = bpf_get_current_task_btf(); struct file *file = bpf_get_task_exe_file(task); struct bpf_dynptr dynptr; - char *data; + char buf[1]; + const char *data; if (!file) return 0; @@ -95,15 +96,14 @@ int use_file_dynptr_slice_after_put_file(void *ctx) if (bpf_dynptr_from_file(file, 0, &dynptr)) goto out; - data = bpf_dynptr_data(&dynptr, 0, 1); + data = bpf_dynptr_slice(&dynptr, 0, buf, sizeof(buf)); if (!data) goto out; /* this should fail - file dynptr should be discarded first to prevent resource leak */ bpf_put_file(file); - *data = 'x'; - return 0; + return data[0]; out: bpf_dynptr_file_discard(&dynptr);